mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-11-03 07:59:06 +08:00
Compare commits
1 Commits
autoexecpa
...
cached_pro
| Author | SHA1 | Date | |
|---|---|---|---|
| ea7646be89 |
@ -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'
|
||||
|
||||
@ -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) '==========================================================='
|
||||
|
||||
|
||||
@ -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] $@"
|
||||
|
||||
@ -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) $* > $@
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
# -*- makefile -*- : Force emacs to use Makefile mode
|
||||
|
||||
# Include generic Linux Makefile
|
||||
#
|
||||
MAKEDEPS += Makefile.linux
|
||||
include Makefile.linux
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
#
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", %progbits
|
||||
.text
|
||||
.arm
|
||||
|
||||
|
||||
@ -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
|
||||
@ -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 */
|
||||
@ -1,6 +1,5 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", %progbits
|
||||
.text
|
||||
.thumb
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.section ".note.GNU-stack", "", %progbits
|
||||
.text
|
||||
.arm
|
||||
|
||||
|
||||
@ -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
|
||||
40
src/arch/arm64/include/efi/ipxe/dhcp_arch.h
Normal file
40
src/arch/arm64/include/efi/ipxe/dhcp_arch.h
Normal 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
|
||||
@ -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 */
|
||||
@ -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
|
||||
#
|
||||
|
||||
40
src/arch/i386/include/efi/ipxe/dhcp_arch.h
Normal file
40
src/arch/i386/include/efi/ipxe/dhcp_arch.h
Normal 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
|
||||
@ -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 */
|
||||
40
src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
Normal file
40
src/arch/i386/include/pcbios/ipxe/dhcp_arch.h
Normal 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
|
||||
@ -136,8 +136,6 @@ SECTIONS {
|
||||
*(.note.*)
|
||||
*(.discard)
|
||||
*(.discard.*)
|
||||
*(.sbat)
|
||||
*(.sbat.*)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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.*)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
@ -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 */
|
||||
|
||||
41
src/arch/x86/include/linux/ipxe/dhcp_arch.h
Normal file
41
src/arch/x86/include/linux/ipxe/dhcp_arch.h
Normal 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
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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 ) ) ) {
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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,
|
||||
};
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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, [] ) = "";
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -229,8 +229,6 @@ SECTIONS {
|
||||
*(.einfo.*)
|
||||
*(.discard)
|
||||
*(.discard.*)
|
||||
*(.sbat)
|
||||
*(.sbat.*)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -24,8 +24,6 @@ SECTIONS {
|
||||
*(.einfo.*)
|
||||
*(.discard)
|
||||
*(.discard.*)
|
||||
*(.sbat)
|
||||
*(.sbat.*)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
#
|
||||
|
||||
40
src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
Normal file
40
src/arch/x86_64/include/efi/ipxe/dhcp_arch.h
Normal 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
|
||||
@ -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 */
|
||||
40
src/arch/x86_64/include/pcbios/ipxe/dhcp_arch.h
Normal file
40
src/arch/x86_64/include/pcbios/ipxe/dhcp_arch.h
Normal 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
|
||||
104
src/arch/x86_64/scripts/linux.lds
Normal file
104
src/arch/x86_64/scripts/linux.lds
Normal 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.*)
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -3,5 +3,5 @@
|
||||
*/
|
||||
#ifdef PLATFORM_pcbios
|
||||
#undef PCIAPI_PCBIOS
|
||||
#define PCIAPI_CLOUD
|
||||
#define PCIAPI_DIRECT
|
||||
#endif
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
114
src/core/acpi.c
114
src/core/acpi.c
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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,
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -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 );
|
||||
@ -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':
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
*
|
||||
|
||||
144
src/core/uri.c
144
src/core/uri.c
@ -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 );
|
||||
|
||||
137
src/core/utf8.c
137
src/core/utf8.c
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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 */
|
||||
}
|
||||
|
||||
|
||||
133
src/crypto/dhe.c
133
src/crypto/dhe.c
@ -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;
|
||||
}
|
||||
535
src/crypto/gcm.c
535
src/crypto/gcm.c
@ -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 );
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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,
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
@ -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 ) );
|
||||
}
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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 );
|
||||
@ -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;
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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,
|
||||
};
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
|
||||
@ -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++;
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 ) );
|
||||
|
||||
@ -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 ) );
|
||||
|
||||
@ -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 );
|
||||
|
||||
@ -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
Reference in New Issue
Block a user