diff options
author | Simon Rettberg | 2022-05-11 10:41:01 +0200 |
---|---|---|
committer | Simon Rettberg | 2022-05-11 10:41:01 +0200 |
commit | a12e3c379cf2e5946c7316259ef46736cdd5f222 (patch) | |
tree | 49638dad528a4490e293ea4a0f87e39ce862a75b | |
parent | Local UEFI disk boot support (diff) | |
parent | [cloud] Allow aws-import script to run on Python 3.6 (diff) | |
download | ipxe-a12e3c379cf2e5946c7316259ef46736cdd5f222.tar.gz ipxe-a12e3c379cf2e5946c7316259ef46736cdd5f222.tar.xz ipxe-a12e3c379cf2e5946c7316259ef46736cdd5f222.zip |
Merge branch 'master' into openslx
115 files changed, 3799 insertions, 961 deletions
diff --git a/contrib/cloud/aws-import b/contrib/cloud/aws-import index eef4302d..b9a350f6 100755 --- a/contrib/cloud/aws-import +++ b/contrib/cloud/aws-import @@ -16,7 +16,7 @@ BLOCKSIZE = 512 * 1024 def detect_architecture(image): """Detect CPU architecture""" mdir = subprocess.run(['mdir', '-b', '-i', image, '::/EFI/BOOT'], - capture_output=True) + stdout=subprocess.PIPE, stderr=subprocess.PIPE) if any(b'BOOTAA64.EFI' in x for x in mdir.stdout.splitlines()): return 'arm64' return 'x86_64' diff --git a/src/Makefile b/src/Makefile index 69139dc1..bc82cc6f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -24,6 +24,7 @@ CP := cp ECHO := echo PRINTF := printf PERL := perl +PYTHON := python TRUE := true CC := $(CROSS_COMPILE)gcc CPP := $(CC) -E @@ -50,7 +51,7 @@ ELF2EFI64 := ./util/elf2efi64 EFIROM := ./util/efirom EFIFATBIN := ./util/efifatbin EINFO := ./util/einfo -GENKEYMAP := ./util/genkeymap.pl +GENKEYMAP := ./util/genkeymap.py DOXYGEN := doxygen LCAB := lcab QEMUIMG := qemu-img @@ -190,7 +191,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 http://ipxe.org/howto/vmware' + @$(ECHO) 'For more information, see https://ipxe.org/howto/vmware' @$(ECHO) @$(ECHO) '===========================================================' diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index 0deb15c1..9bf34b2e 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -918,7 +918,7 @@ $(BIN)/deps/%.d : % $(MAKEDEPS) # Calculate list of dependency files # -AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS)) +AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS) core/version.c) autodeps : @$(ECHO) $(AUTO_DEPS) VERYCLEANUP += $(BIN)/deps @@ -1202,7 +1202,7 @@ endif # Build version # GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index)) -$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX) +$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(version_DEPS) $(GIT_INDEX) $(QM)$(ECHO) " [VERSION] $@" $(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \ -DVERSION_MAJOR=$(VERSION_MAJOR) \ @@ -1563,7 +1563,7 @@ endif # defined(BIN) # hci/keymap/keymap_%.c : - $(Q)$(PERL) $(GENKEYMAP) $* > $@ + $(Q)$(PYTHON) $(GENKEYMAP) $* > $@ ############################################################################### # diff --git a/src/arch/i386/scripts/i386-kir.lds b/src/arch/i386/scripts/i386-kir.lds index 66bf804e..13c36f2b 100644 --- a/src/arch/i386/scripts/i386-kir.lds +++ b/src/arch/i386/scripts/i386-kir.lds @@ -136,6 +136,8 @@ SECTIONS { *(.note.*) *(.discard) *(.discard.*) + *(.sbat) + *(.sbat.*) } /* diff --git a/src/arch/i386/scripts/linux.lds b/src/arch/i386/scripts/linux.lds index 9f2eeaf3..8c3a7b0b 100644 --- a/src/arch/i386/scripts/linux.lds +++ b/src/arch/i386/scripts/linux.lds @@ -100,5 +100,7 @@ SECTIONS { *(.rel.*) *(.discard) *(.discard.*) + *(.sbat) + *(.sbat.*) } } diff --git a/src/arch/x86/include/bios.h b/src/arch/x86/include/bios.h index 14e7acbc..6391a495 100644 --- a/src/arch/x86/include/bios.h +++ b/src/arch/x86/include/bios.h @@ -6,6 +6,11 @@ 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 @@ -13,5 +18,7 @@ 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 */ diff --git a/src/arch/x86/interface/pcbios/acpi_timer.c b/src/arch/x86/interface/pcbios/acpi_timer.c index 82e85a03..2e4047e3 100644 --- a/src/arch/x86/interface/pcbios/acpi_timer.c +++ b/src/arch/x86/interface/pcbios/acpi_timer.c @@ -107,7 +107,7 @@ static int acpi_timer_probe ( void ) { unsigned int pm_tmr_blk; /* Locate FADT */ - fadt = acpi_find ( FADT_SIGNATURE, 0 ); + fadt = acpi_table ( FADT_SIGNATURE, 0 ); if ( ! fadt ) { DBGC ( &acpi_timer, "ACPI could not find FADT\n" ); return -ENOENT; diff --git a/src/arch/x86/interface/pcbios/acpipwr.c b/src/arch/x86/interface/pcbios/acpipwr.c index 3dac6b60..f08b4af2 100644 --- a/src/arch/x86/interface/pcbios/acpipwr.c +++ b/src/arch/x86/interface/pcbios/acpipwr.c @@ -123,7 +123,7 @@ int acpi_poweroff ( void ) { int rc; /* Locate FADT */ - fadt = acpi_find ( FADT_SIGNATURE, 0 ); + fadt = acpi_table ( FADT_SIGNATURE, 0 ); if ( ! fadt ) { DBGC ( colour, "ACPI could not find FADT\n" ); return -ENOENT; diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 80ebf330..0220c856 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -60,6 +60,21 @@ 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 @@ -340,28 +355,15 @@ static const char * bios_ansi_seq ( unsigned int scancode ) { } /** - * 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 * * @ret character Character read from console */ static int bios_getchar ( void ) { uint16_t keypress; + uint8_t kb0; + uint8_t kb2; + unsigned int scancode; unsigned int character; const char *ansi_seq; @@ -383,11 +385,42 @@ 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; + } - /* If it's a normal character, just map and return it */ - if ( character && ( character < 0x80 ) ) - return bios_keymap ( character ); + /* Map and return */ + return key_remap ( character ); + } /* Otherwise, check for a special key that we know about */ if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) { diff --git a/src/arch/x86/interface/pcbios/vesafb.c b/src/arch/x86/interface/pcbios/vesafb.c index 21b3e74c..1b419812 100644 --- a/src/arch/x86/interface/pcbios/vesafb.c +++ b/src/arch/x86/interface/pcbios/vesafb.c @@ -78,6 +78,15 @@ 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; @@ -130,12 +139,24 @@ static int vesafb_rc ( unsigned int status ) { /** * Get character glyph * - * @v character Character + * @v character Unicode character * @v glyph Character glyph to fill in */ static void vesafb_glyph ( unsigned int character, uint8_t *glyph ) { - size_t offset = ( character * VESAFB_CHAR_HEIGHT ); + unsigned int index; + size_t offset; + + /* 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); } diff --git a/src/arch/x86/interface/syslinux/comboot_call.c b/src/arch/x86/interface/syslinux/comboot_call.c index dc308daf..b75e8ef7 100644 --- a/src/arch/x86/interface/syslinux/comboot_call.c +++ b/src/arch/x86/interface/syslinux/comboot_call.c @@ -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, [] ) = " http://ipxe.org"; +static char __data16_array ( syslinux_copyright, [] ) = " https://ipxe.org"; #define syslinux_copyright __use_data16 ( syslinux_copyright ) static char __data16_array ( syslinux_configuration_file, [] ) = ""; diff --git a/src/arch/x86/prefix/libprefix.S b/src/arch/x86/prefix/libprefix.S index ffb21105..d7f26195 100644 --- a/src/arch/x86/prefix/libprefix.S +++ b/src/arch/x86/prefix/libprefix.S @@ -380,6 +380,11 @@ 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 */ @@ -410,8 +415,9 @@ process_bytes: pushw %es pushw %ds pushw %ss - pushw %cs - pushw $2f + pushw %ss /* Far pointer to ljmp code on stack */ + leaw (GDT_LEN + 1)(%bp), %ax + pushw %ax cli data32 lgdt (%bp) movl %cr0, %eax @@ -438,7 +444,7 @@ process_bytes: popfw movl %eax, %cr0 lret -2: /* lret will ljmp to here */ +2: /* lret will ljmp to here (via constructed ljmp on stack) */ popw %ss popw %ds popw %es @@ -461,7 +467,7 @@ process_bytes: /* Restore GDT */ data32 lgdt -8(%bp) - leaw GDT_LEN(%bp), %sp + leaw (GDT_LEN + LJMP_LEN)(%bp), %sp /* Restore registers and return */ popl %ebp diff --git a/src/arch/x86/prefix/romprefix.S b/src/arch/x86/prefix/romprefix.S index a9934a72..4e8793c2 100644 --- a/src/arch/x86/prefix/romprefix.S +++ b/src/arch/x86/prefix/romprefix.S @@ -161,7 +161,7 @@ pnpheader: /* Manufacturer string */ mfgstr: - .asciz "http://ipxe.org" + .asciz "https://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 http://ipxe.org, we prefer you not to do so. + * to iPXE or https://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, diff --git a/src/arch/x86/scripts/pcbios.lds b/src/arch/x86/scripts/pcbios.lds index de59adca..e208b174 100644 --- a/src/arch/x86/scripts/pcbios.lds +++ b/src/arch/x86/scripts/pcbios.lds @@ -229,6 +229,8 @@ SECTIONS { *(.einfo.*) *(.discard) *(.discard.*) + *(.sbat) + *(.sbat.*) } /* diff --git a/src/arch/x86/scripts/prefixonly.lds b/src/arch/x86/scripts/prefixonly.lds index dce0930b..2fe5b03b 100644 --- a/src/arch/x86/scripts/prefixonly.lds +++ b/src/arch/x86/scripts/prefixonly.lds @@ -24,6 +24,8 @@ SECTIONS { *(.einfo.*) *(.discard) *(.discard.*) + *(.sbat) + *(.sbat.*) } } diff --git a/src/arch/x86_64/scripts/linux.lds b/src/arch/x86_64/scripts/linux.lds index 47db2174..a093787e 100644 --- a/src/arch/x86_64/scripts/linux.lds +++ b/src/arch/x86_64/scripts/linux.lds @@ -100,5 +100,7 @@ SECTIONS { *(.rel.*) *(.discard) *(.discard.*) + *(.sbat) + *(.sbat.*) } } diff --git a/src/config/branding.h b/src/config/branding.h index 73f00af9..454bf0c0 100644 --- a/src/config/branding.h +++ b/src/config/branding.h @@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #define PRODUCT_NAME "" #define PRODUCT_SHORT_NAME "iPXE" -#define PRODUCT_URI "http://ipxe.org" +#define PRODUCT_URI "https://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 (http://ipxe.org/2d0c613b)" + * "No such file or directory (https://ipxe.org/2d0c613b)" * * or * - * "Operation not supported (http://ipxe.org/3c092003)" + * "Operation not supported (https://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 - * (http://ipxe.org). This database provides details for all possible + * (https://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 http://ipxe.org, then + * existing support infrastructure provided by https://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 "http://ipxe.org/%08x" +#define PRODUCT_ERROR_URI "https://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 http://ipxe.org/cmd/vcreate for further information" + * "See https://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 http://ipxe.org, then you may + * support infrastructure provided by https://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 "http://ipxe.org/cmd/%s" +#define PRODUCT_COMMAND_URI "https://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 * - * "http://ipxe.org/cfg/initiator-iqn" + * "https://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 http://ipxe.org, then you may define a + * infrastructure provided by https://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,7 +167,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * iPXE project and prohibit the alteration or removal of any * references to "iPXE". ] */ -#define PRODUCT_SETTING_URI "http://ipxe.org/cfg/%s" +#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 #include <config/local/branding.h> diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 9ef34ab6..efa80181 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -58,4 +58,8 @@ 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 */ diff --git a/src/core/acpi.c b/src/core/acpi.c index aa486da9..526bf855 100644 --- a/src/core/acpi.c +++ b/src/core/acpi.c @@ -38,6 +38,12 @@ 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 @@ -83,6 +89,18 @@ void acpi_fix_checksum ( struct acpi_header *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 * * @v signature Requested table signature @@ -230,7 +248,7 @@ int acpi_extract ( uint32_t signature, void *data, int rc; /* Try DSDT first */ - fadt = acpi_find ( FADT_SIGNATURE, 0 ); + fadt = acpi_table ( FADT_SIGNATURE, 0 ); if ( fadt ) { copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) ); dsdt = phys_to_user ( fadtab.dsdt ); @@ -241,7 +259,7 @@ int acpi_extract ( uint32_t signature, void *data, /* Try all SSDTs */ for ( i = 0 ; ; i++ ) { - ssdt = acpi_find ( SSDT_SIGNATURE, i ); + ssdt = acpi_table ( SSDT_SIGNATURE, i ); if ( ! ssdt ) break; if ( ( rc = acpi_zsdt ( ssdt, signature, data, diff --git a/src/core/acpi_settings.c b/src/core/acpi_settings.c index 7ba2e979..b9e2b7f6 100644 --- a/src/core/acpi_settings.c +++ b/src/core/acpi_settings.c @@ -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_find ( tag_signature, tag_index ); + table = acpi_table ( tag_signature, tag_index ); if ( ! table ) return -ENOENT; diff --git a/src/core/acpimac.c b/src/core/acpimac.c index 1cc8220b..5920480d 100644 --- a/src/core/acpimac.c +++ b/src/core/acpimac.c @@ -46,11 +46,79 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** MACA signature */ #define MACA_SIGNATURE ACPI_SIGNATURE ( 'M', 'A', 'C', 'A' ) -/** Maximum number of bytes to skip after AMAC/MACA signature +/** 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 AUXMAC_MAX_SKIP 8 +#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 @@ -59,6 +127,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @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, @@ -72,51 +141,44 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * string that appears shortly after an "AMAC" or "MACA" signature. * This should work for most implementations encountered in practice. */ -static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset, - void *data ) { - static const char prefix[9] = "_AUXMAC_#"; +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 auxmac[ sizeof ( prefix ) /* "_AUXMAC_#" */ + - ( ETH_ALEN * 2 ) /* MAC */ + 1 /* "#" */ + 1 /* NUL */ ]; - char *mac = &auxmac[ sizeof ( prefix ) ]; - int decoded_len; + 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 "_AUXMAC_#.....#" close to signature */ + /* Scan for suitable string close to signature */ for ( skip = 0 ; - ( ( skip < AUXMAC_MAX_SKIP ) && - ( offset + skip + sizeof ( auxmac ) ) < len ) ; + ( ( skip < ACPIMAC_MAX_SKIP ) && + ( offset + skip + sizeof ( buf ) ) <= len ) ; skip++ ) { /* Read value */ - copy_from_user ( auxmac, zsdt, ( offset + skip ), - sizeof ( auxmac ) ); + copy_from_user ( buf, zsdt, ( offset + skip ), + sizeof ( buf ) ); /* Check for expected format */ - if ( memcmp ( auxmac, prefix, sizeof ( prefix ) ) != 0 ) + if ( memcmp ( buf, extractor->prefix, prefix_len ) != 0 ) continue; - if ( auxmac[ sizeof ( auxmac ) - 2 ] != '#' ) + if ( buf[ sizeof ( buf ) - 2 ] != '#' ) continue; - if ( auxmac[ sizeof ( auxmac ) - 1 ] != '\0' ) + if ( buf[ sizeof ( buf ) - 1 ] != '\0' ) continue; - DBGC ( colour, "ACPI found MAC string \"%s\"\n", auxmac ); + DBGC ( colour, "ACPI found MAC:\n" ); + DBGC_HDA ( colour, ( offset + skip ), buf, sizeof ( buf ) ); /* Terminate MAC address string */ - mac = &auxmac[ sizeof ( prefix ) ]; - mac[ ETH_ALEN * 2 ] = '\0'; + mac[extractor->len] = '\0'; /* Decode MAC address */ - decoded_len = base16_decode ( mac, hw_addr, ETH_ALEN ); - if ( decoded_len < 0 ) { - rc = decoded_len; - DBGC ( colour, "ACPI could not decode MAC \"%s\": %s\n", - mac, strerror ( rc ) ); + if ( ( rc = extractor->decode ( mac, hw_addr ) ) != 0 ) return rc; - } /* Check MAC address validity */ if ( ! is_valid_ether_addr ( hw_addr ) ) { @@ -132,6 +194,36 @@ static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset, } /** + * 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 @@ -142,12 +234,17 @@ int acpi_mac ( uint8_t *hw_addr ) { /* Look for an "AMAC" address */ if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr, - acpi_extract_mac ) ) == 0 ) + acpimac_extract_auxmac ) ) == 0 ) return 0; /* Look for a "MACA" address */ if ( ( rc = acpi_extract ( MACA_SIGNATURE, hw_addr, - acpi_extract_mac ) ) == 0 ) + 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; diff --git a/src/core/dynkeymap.c b/src/core/dynkeymap.c new file mode 100644 index 00000000..2f7c4993 --- /dev/null +++ b/src/core/dynkeymap.c @@ -0,0 +1,131 @@ +/* + * 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 ); diff --git a/src/core/fbcon.c b/src/core/fbcon.c index f64bab7c..056b164c 100644 --- a/src/core/fbcon.c +++ b/src/core/fbcon.c @@ -446,6 +446,11 @@ 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': diff --git a/src/core/image.c b/src/core/image.c index ce8cf868..3e236ca6 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -338,9 +338,12 @@ int image_exec ( struct image *image ) { /* Sanity check */ assert ( image->flags & IMAGE_REGISTERED ); - /* Switch current working directory to be that of the image itself */ + /* Switch current working directory to be that of the image + * itself, if applicable + */ old_cwuri = uri_get ( cwuri ); - churi ( image->uri ); + if ( image->uri ) + churi ( image->uri ); /* Preserve record of any currently-running image */ saved_current_image = current_image; diff --git a/src/core/keymap.c b/src/core/keymap.c new file mode 100644 index 00000000..36db7bd4 --- /dev/null +++ b/src/core/keymap.c @@ -0,0 +1,131 @@ +/* + * 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; +} diff --git a/src/core/settings.c b/src/core/settings.c index d6ab6b20..1037b06a 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -412,9 +412,8 @@ struct settings * find_settings ( const char *name ) { /** * Apply all settings * - * @ret rc Return status code */ -static int apply_settings ( void ) { +static void apply_settings ( void ) { struct settings_applicator *applicator; int rc; @@ -423,11 +422,9 @@ static int apply_settings ( void ) { if ( ( rc = applicator->apply() ) != 0 ) { DBG ( "Could not apply settings using applicator " "%p: %s\n", applicator, strerror ( rc ) ); - return rc; + /* Continue to apply remaining settings */ } } - - return 0; } /** @@ -645,8 +642,7 @@ int store_setting ( struct settings *settings, const struct setting *setting, */ for ( ; settings ; settings = settings->parent ) { if ( settings == &settings_root ) { - if ( ( rc = apply_settings() ) != 0 ) - return rc; + apply_settings(); break; } } @@ -2246,7 +2242,7 @@ const struct setting_type setting_type_base64 __setting_type = { }; /** - * Format UUID setting value + * Format UUID/GUID setting value * * @v type Setting type * @v raw Raw setting value @@ -2255,17 +2251,24 @@ 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 __unused, +static int format_uuid_setting ( const struct setting_type *type, const void *raw, size_t raw_len, char *buf, size_t len ) { - const union uuid *uuid = raw; + union uuid uuid; /* 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 */ @@ -2274,6 +2277,12 @@ 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 * diff --git a/src/core/uri.c b/src/core/uri.c index e9e512ab..b82472ef 100644 --- a/src/core/uri.c +++ b/src/core/uri.c @@ -79,12 +79,10 @@ size_t uri_decode ( const char *encoded, void *buf, size_t len ) { /** * Decode URI field in-place * - * @v uri URI - * @v field URI field index + * @v encoded Encoded field, or NULL */ -static void uri_decode_inplace ( struct uri *uri, unsigned int field ) { - const char *encoded = uri_field ( uri, field ); - char *decoded = ( ( char * ) encoded ); +static void uri_decode_inplace ( char *encoded ) { + char *decoded = encoded; size_t len; /* Do nothing if field is not present */ @@ -150,7 +148,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_FIELDS] = { + static const char *escaped[URI_EPATH] = { /* Scheme or default: escape everything */ [URI_SCHEME] = "/#:@?=&", /* Opaque part: escape characters which would affect @@ -172,20 +170,21 @@ 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] = "/#:@?", }; - return ( /* Always escape non-printing characters and whitespace */ - ( ! isprint ( c ) ) || ( c == ' ' ) || - /* Always escape '%' */ - ( c == '%' ) || - /* Escape field-specific characters */ - strchr ( escaped[field], c ) ); + /* 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; } /** @@ -262,10 +261,12 @@ 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->query ) - DBGC ( uri, " query \"%s\"", uri->query ); - if ( uri->fragment ) - DBGC ( uri, " fragment \"%s\"", uri->fragment ); + 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->params ) DBGC ( uri, " params \"%s\"", uri->params->name ); } @@ -298,17 +299,19 @@ 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 a copy of the string */ + /* Allocate space for URI struct and two copies of the string */ raw_len = ( strlen ( uri_string ) + 1 /* NUL */ ); - uri = zalloc ( sizeof ( *uri ) + raw_len ); + uri = zalloc ( sizeof ( *uri ) + ( 2 * 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 ); @@ -328,57 +331,62 @@ struct uri * parse_uri ( const char *uri_string ) { /* Chop off the fragment, if it exists */ if ( ( tmp = strchr ( raw, '#' ) ) ) { *(tmp++) = '\0'; - uri->fragment = tmp; + uri->efragment = tmp; } - /* Identify absolute/relative URI */ - if ( ( tmp = strchr ( raw, ':' ) ) ) { + /* 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; /* Absolute URI: identify hierarchical/opaque */ uri->scheme = raw; *(tmp++) = '\0'; if ( *tmp == '/' ) { /* Absolute URI with hierarchical part */ - path = tmp; + epath = tmp; } else { /* Absolute URI with opaque part */ uri->opaque = tmp; - path = NULL; + epath = NULL; } - } else { - /* Relative URI */ - path = raw; + break; } /* If we don't have a path (i.e. we have an absolute URI with * an opaque portion, we're already finished processing */ - if ( ! path ) + if ( ! epath ) goto done; /* Chop off the query, if it exists */ - if ( ( tmp = strchr ( path, '?' ) ) ) { + if ( ( tmp = strchr ( epath, '?' ) ) ) { *(tmp++) = '\0'; - uri->query = tmp; + uri->equery = tmp; } /* If we have no path remaining, then we're already finished * processing. */ - if ( ! path[0] ) + if ( ! epath[0] ) goto done; /* Identify net/absolute/relative path */ - if ( uri->scheme && ( strncmp ( path, "//", 2 ) == 0 ) ) { + if ( uri->scheme && ( strncmp ( epath, "//", 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 = ( path + 2 ); + authority = ( epath + 2 ); if ( ( tmp = strchr ( authority, '/' ) ) ) { /* Shuffle down */ - uri->path = tmp; + uri->epath = tmp; memmove ( ( authority - 1 ), authority, ( tmp - authority ) ); authority--; @@ -386,10 +394,16 @@ struct uri * parse_uri ( const char *uri_string ) { } } else { /* Absolute/relative path */ - uri->path = path; + uri->epath = epath; authority = NULL; } + /* Create copy of path for decoding */ + if ( uri->epath ) { + strcpy ( path, uri->epath ); + uri->path = path; + } + /* If we don't have an authority (i.e. we have a non-net * path), we're already finished processing */ @@ -421,8 +435,8 @@ struct uri * parse_uri ( const char *uri_string ) { done: /* Decode fields in-place */ - for ( field = 0 ; field < URI_FIELDS ; field++ ) - uri_decode_inplace ( uri, field ); + for ( field = 0 ; field < URI_EPATH ; field++ ) + uri_decode_inplace ( ( char * ) uri_field ( uri, field ) ); DBGC ( uri, "URI parsed \"%s\" to", uri_string ); uri_dump ( uri ); @@ -458,8 +472,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_QUERY] = '?', - [URI_FRAGMENT] = '#', + [URI_EQUERY] = '?', + [URI_EFRAGMENT] = '#', }; char prefix; size_t used = 0; @@ -480,6 +494,10 @@ 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 ) ) @@ -676,6 +694,7 @@ 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; @@ -685,20 +704,27 @@ struct uri * resolve_uri ( const struct uri *base_uri, /* Mangle URI */ memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) ); - if ( relative_uri->path ) { - tmp_path = resolve_path ( ( base_uri->path ? - base_uri->path : "/" ), - relative_uri->path ); + 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; tmp_uri.path = tmp_path; - tmp_uri.query = relative_uri->query; - tmp_uri.fragment = relative_uri->fragment; + tmp_uri.equery = relative_uri->equery; + tmp_uri.efragment = relative_uri->efragment; tmp_uri.params = relative_uri->params; - } else if ( relative_uri->query ) { - tmp_uri.query = relative_uri->query; - tmp_uri.fragment = relative_uri->fragment; + } else if ( relative_uri->equery ) { + tmp_uri.equery = relative_uri->equery; + tmp_uri.efragment = relative_uri->efragment; tmp_uri.params = relative_uri->params; - } else if ( relative_uri->fragment ) { - tmp_uri.fragment = relative_uri->fragment; + } else if ( relative_uri->efragment ) { + tmp_uri.efragment = relative_uri->efragment; tmp_uri.params = relative_uri->params; } else if ( relative_uri->params ) { tmp_uri.params = relative_uri->params; @@ -707,7 +733,14 @@ 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; } /** @@ -746,6 +779,7 @@ 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 ); diff --git a/src/core/utf8.c b/src/core/utf8.c new file mode 100644 index 00000000..4ee01baf --- /dev/null +++ b/src/core/utf8.c @@ -0,0 +1,137 @@ +/* + * 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; +} diff --git a/src/core/version.c b/src/core/version.c index c984335c..22f44406 100644 --- a/src/core/version.c +++ b/src/core/version.c @@ -32,6 +32,7 @@ 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> @@ -92,3 +93,32 @@ 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; diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 1b7350c8..5891e42f 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -121,6 +121,11 @@ 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 ) { diff --git a/src/drivers/bus/virtio-pci.c b/src/drivers/bus/virtio-pci.c index 5d2d6275..8b34c727 100644 --- a/src/drivers/bus/virtio-pci.c +++ b/src/drivers/bus/virtio-pci.c @@ -17,37 +17,47 @@ #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) +static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num, size_t header_size) { - size_t queue_size = PAGE_MASK + vring_size(num); + size_t ring_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 = zalloc(queue_size + vdata_size); + vq->queue = dma_alloc(vq->dma, &vq->map, queue_size, queue_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 + queue_size); + 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); return 0; } void vp_free_vq(struct vring_virtqueue *vq) { - if (vq->queue) { - free(vq->queue); + if (vq->queue && vq->queue_size) { + dma_free(&vq->map, vq->queue, vq->queue_size); 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 vring_virtqueue *vq, struct dma_device *dma_dev, + size_t header_size) { struct vring * vr = &vq->vring; u16 num; @@ -73,9 +83,10 @@ 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); + rc = vp_alloc_vq(vq, num, header_size); if (rc) { DBG("VIRTIO-PCI ERROR: failed to allocate queue memory\n"); return rc; @@ -87,8 +98,7 @@ int vp_find_vq(unsigned int ioaddr, int queue_index, * NOTE: vr->desc is initialized by vring_init() */ - outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT, - ioaddr + VIRTIO_PCI_QUEUE_PFN); + outl(dma(&vq->map, vr->desc) >> PAGE_SHIFT, ioaddr + VIRTIO_PCI_QUEUE_PFN); return num; } @@ -348,7 +358,8 @@ 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) + unsigned nvqs, struct vring_virtqueue *vqs, + struct dma_device *dma_dev, size_t header_size) { unsigned i; struct vring_virtqueue *vq; @@ -392,11 +403,12 @@ 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); + err = vp_alloc_vq(vq, size, header_size); if (err) { DBG("VIRTIO-PCI %p: failed to allocate queue memory\n", vdev); return err; @@ -406,13 +418,16 @@ 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, virt_to_phys(vq->vring.desc), + vpm_iowrite64(vdev, &vdev->common, + dma(&vq->map, vq->vring.desc), COMMON_OFFSET(queue_desc_lo), COMMON_OFFSET(queue_desc_hi)); - vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.avail), + vpm_iowrite64(vdev, &vdev->common, + dma(&vq->map, vq->vring.avail), COMMON_OFFSET(queue_avail_lo), COMMON_OFFSET(queue_avail_hi)); - vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.used), + vpm_iowrite64(vdev, &vdev->common, + dma(&vq->map, vq->vring.used), COMMON_OFFSET(queue_used_lo), COMMON_OFFSET(queue_used_hi)); diff --git a/src/drivers/bus/virtio-ring.c b/src/drivers/bus/virtio-ring.c index 98e787e1..e448c348 100644 --- a/src/drivers/bus/virtio-ring.c +++ b/src/drivers/bus/virtio-ring.c @@ -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 = (u64)virt_to_phys(list->addr); + vr->desc[i].addr = 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 = (u64)virt_to_phys(list->addr); + vr->desc[i].addr = list->addr; vr->desc[i].len = list->length; prev = i; list++; diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index b9f34650..833462e7 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -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 ( TPL_CALLBACK ); + tpl = bs->RaiseTPL ( efi_internal_tpl ); /* Issue command */ DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n", diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c index fb524027..69ec6f5e 100644 --- a/src/drivers/net/efi/snpnet.c +++ b/src/drivers/net/efi/snpnet.c @@ -164,6 +164,10 @@ 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 ); @@ -283,6 +287,10 @@ 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 ); @@ -426,8 +434,9 @@ static void snpnet_close ( struct net_device *netdev ) { EFI_STATUS efirc; int rc; - /* Shut down NIC */ - if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) { + /* Shut down NIC (unless whole system shutdown is in progress) */ + if ( ( ! efi_shutdown_in_progress ) && + ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) { rc = -EEFI ( efirc ); DBGC ( snp, "SNP %s could not shut down: %s\n", netdev->name, strerror ( rc ) ); @@ -589,8 +598,9 @@ void snpnet_stop ( struct efi_device *efidev ) { /* Unregister network device */ unregister_netdev ( netdev ); - /* Stop SNP protocol */ - if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) { + /* Stop SNP protocol (unless whole system shutdown is in progress) */ + if ( ( ! efi_shutdown_in_progress ) && + ( ( 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 ) ); diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c index ccf6b064..f4dad885 100644 --- a/src/drivers/net/intelx.c +++ b/src/drivers/net/intelx.c @@ -481,6 +481,7 @@ static struct pci_device_id intelx_nics[] = { PCI_ROM ( 0x8086, 0x15ab, "x552", "X552", 0 ), PCI_ROM ( 0x8086, 0x15c8, "x553t", "X553/X557-AT", 0 ), PCI_ROM ( 0x8086, 0x15ce, "x553-sfp", "X553 (SFP+)", 0 ), + PCI_ROM ( 0x8086, 0x15e4, "x553a", "X553", 0 ), PCI_ROM ( 0x8086, 0x15e5, "x553", "X553", 0 ), }; diff --git a/src/drivers/net/virtio-net.c b/src/drivers/net/virtio-net.c index 78ec9ac4..0c454192 100644 --- a/src/drivers/net/virtio-net.c +++ b/src/drivers/net/virtio-net.c @@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/iobuf.h> #include <ipxe/netdevice.h> #include <ipxe/pci.h> +#include <ipxe/dma.h> #include <ipxe/if_ether.h> #include <ipxe/ethernet.h> #include <ipxe/virtio-pci.h> @@ -99,8 +100,9 @@ struct virtnet_nic { /** Pending rx packet count */ unsigned int rx_num_iobufs; - /** Virtio net dummy packet headers */ - struct virtio_net_hdr_modern empty_header[QUEUE_NB]; + /** DMA device */ + struct dma_device *dma; + }; /** Add an iobuf to a virtqueue @@ -115,7 +117,7 @@ static void virtnet_enqueue_iob ( struct net_device *netdev, int vq_idx, struct io_buffer *iobuf ) { struct virtnet_nic *virtnet = netdev->priv; struct vring_virtqueue *vq = &virtnet->virtqueue[vq_idx]; - struct virtio_net_hdr_modern *header = &virtnet->empty_header[vq_idx]; + struct virtio_net_hdr_modern *header = vq->empty_header; unsigned int out = ( vq_idx == TX_INDEX ) ? 2 : 0; unsigned int in = ( vq_idx == TX_INDEX ) ? 0 : 2; size_t header_len = ( virtnet->virtio_version ? @@ -132,11 +134,11 @@ static void virtnet_enqueue_iob ( struct net_device *netdev, * to header->flags for received packets. Work around * this by using separate RX and TX headers. */ - .addr = ( char* ) header, + .addr = dma ( &vq->map, header ), .length = header_len, }, { - .addr = ( char* ) iobuf->data, + .addr = iob_dma ( iobuf ), .length = iob_len ( iobuf ), }, }; @@ -161,7 +163,7 @@ static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) { struct io_buffer *iobuf; /* Try to allocate a buffer, stop for now if out of memory */ - iobuf = alloc_iob ( len ); + iobuf = alloc_rx_iob ( len, virtnet->dma ); if ( ! iobuf ) break; @@ -215,7 +217,8 @@ static int virtnet_open_legacy ( struct net_device *netdev ) { /* Initialize rx/tx virtqueues */ for ( i = 0; i < QUEUE_NB; i++ ) { - if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i] ) == -1 ) { + if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i], virtnet->dma, + sizeof ( struct virtio_net_hdr_modern ) ) == -1 ) { DBGC ( virtnet, "VIRTIO-NET %p cannot register queue %d\n", virtnet, i ); virtnet_free_virtqueues ( netdev ); @@ -280,7 +283,8 @@ static int virtnet_open_modern ( struct net_device *netdev ) { } /* Initialize rx/tx virtqueues */ - if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue ) ) { + if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue, + virtnet->dma, sizeof ( struct virtio_net_hdr_modern ) ) ) { DBGC ( virtnet, "VIRTIO-NET %p cannot register queues\n", virtnet ); virtnet_free_virtqueues ( netdev ); @@ -335,7 +339,7 @@ static void virtnet_close ( struct net_device *netdev ) { /* Free rx iobufs */ list_for_each_entry_safe ( iobuf, next_iobuf, &virtnet->rx_iobufs, list ) { - free_iob ( iobuf ); + free_rx_iob ( iobuf ); } INIT_LIST_HEAD ( &virtnet->rx_iobufs ); virtnet->rx_num_iobufs = 0; @@ -478,6 +482,12 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) { /* Enable PCI bus master and reset NIC */ adjust_pci_device ( pci ); + + /* Configure DMA */ + virtnet->dma = &pci->dma; + dma_set_mask_64bit ( virtnet->dma ); + netdev->dma = virtnet->dma; + vp_reset ( ioaddr ); /* Load MAC address and MTU */ @@ -506,7 +516,7 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) { return 0; unregister_netdev ( netdev ); - err_register_netdev: +err_register_netdev: vp_reset ( ioaddr ); netdev_nullify ( netdev ); netdev_put ( netdev ); @@ -586,6 +596,11 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) { /* Enable the PCI device */ adjust_pci_device ( pci ); + /* Configure DMA */ + virtnet->dma = &pci->dma; + dma_set_mask_64bit ( virtnet->dma ); + netdev->dma = virtnet->dma; + /* Reset the device and set initial status bits */ vpm_reset ( &virtnet->vdev ); vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE ); @@ -633,7 +648,6 @@ err_mac_address: vpm_reset ( &virtnet->vdev ); netdev_nullify ( netdev ); netdev_put ( netdev ); - virtio_pci_unmap_capability ( &virtnet->vdev.device ); err_map_device: virtio_pci_unmap_capability ( &virtnet->vdev.isr ); diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index a8ab6ab7..b284e584 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -25,10 +25,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdlib.h> #include <string.h> +#include <ctype.h> #include <errno.h> #include <assert.h> #include <ipxe/console.h> #include <ipxe/keys.h> +#include <ipxe/keymap.h> #include <ipxe/usb.h> #include "usbkbd.h" @@ -69,10 +71,7 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, } else if ( keycode <= USBKBD_KEY_Z ) { /* Alphabetic keys */ key = ( keycode - USBKBD_KEY_A + 'a' ); - if ( modifiers & USBKBD_CTRL ) { - key -= ( 'a' - CTRL_A ); - } else if ( ( modifiers & USBKBD_SHIFT ) || - ( leds & USBKBD_LED_CAPS_LOCK ) ) { + if ( modifiers & USBKBD_SHIFT ) { key -= ( 'a' - 'A' ); } } else if ( keycode <= USBKBD_KEY_0 ) { @@ -118,10 +117,30 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, }; key = keypad[ keycode - USBKBD_KEY_PAD_1 ]; }; + } else if ( keycode == USBKBD_KEY_NON_US ) { + /* Non-US \ and | */ + key = ( ( modifiers & USBKBD_SHIFT ) ? + ( KEYMAP_PSEUDO | '|' ) : ( KEYMAP_PSEUDO | '\\' ) ); } else { key = 0; } + /* Remap key if applicable */ + if ( ( keycode < USBKBD_KEY_CAPS_LOCK ) || + ( keycode == USBKBD_KEY_NON_US ) ) { + + /* Apply modifiers */ + if ( modifiers & USBKBD_CTRL ) + key |= KEYMAP_CTRL; + if ( modifiers & USBKBD_ALT_RIGHT ) + key |= KEYMAP_ALTGR; + if ( leds & USBKBD_LED_CAPS_LOCK ) + key |= KEYMAP_CAPSLOCK; + + /* Remap key */ + key = key_remap ( key ); + } + return key; } diff --git a/src/drivers/usb/usbkbd.h b/src/drivers/usb/usbkbd.h index cedebfe7..1a3fea1b 100644 --- a/src/drivers/usb/usbkbd.h +++ b/src/drivers/usb/usbkbd.h @@ -75,6 +75,7 @@ enum usb_keycode { USBKBD_KEY_PAD_ENTER = 0x58, USBKBD_KEY_PAD_1 = 0x59, USBKBD_KEY_PAD_DOT = 0x63, + USBKBD_KEY_NON_US = 0x64, }; /** USB keyboard LEDs */ diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index cc48af03..3247ee69 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -1165,6 +1165,31 @@ static int xhci_reset ( struct xhci_device *xhci ) { return -ETIMEDOUT; } +/** + * Mark xHCI device as permanently failed + * + * @v xhci xHCI device + * @ret rc Return status code + */ +static int xhci_fail ( struct xhci_device *xhci ) { + size_t len; + int rc; + + /* Mark command mechanism as permanently failed */ + xhci->failed = 1; + + /* Reset device */ + if ( ( rc = xhci_reset ( xhci ) ) != 0 ) + return rc; + + /* Discard DCBAA entries since DCBAAP has been cleared */ + assert ( xhci->dcbaa.context != NULL ); + len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) ); + memset ( xhci->dcbaa.context, 0, len ); + + return 0; +} + /****************************************************************************** * * Transfer request blocks @@ -1720,6 +1745,10 @@ static void xhci_event_poll ( struct xhci_device *xhci ) { unsigned int consumed; unsigned int type; + /* Do nothing if device has permanently failed */ + if ( xhci->failed ) + return; + /* Poll for events */ profile_start ( &xhci_event_profiler ); for ( consumed = 0 ; ; consumed++ ) { @@ -1778,6 +1807,7 @@ static void xhci_event_poll ( struct xhci_device *xhci ) { */ static void xhci_abort ( struct xhci_device *xhci ) { physaddr_t crp; + uint32_t crcr; /* Abort the command */ DBGC2 ( xhci, "XHCI %s aborting command\n", xhci->name ); @@ -1786,8 +1816,18 @@ static void xhci_abort ( struct xhci_device *xhci ) { /* Allow time for command to abort */ mdelay ( XHCI_COMMAND_ABORT_DELAY_MS ); - /* Sanity check */ - assert ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 ); + /* Check for failure to abort */ + crcr = readl ( xhci->op + XHCI_OP_CRCR ); + if ( crcr & XHCI_CRCR_CRR ) { + + /* Device has failed to abort a command and is almost + * certainly beyond repair. Reset device, abandoning + * all state, and mark device as failed to avoid + * delays on any future command attempts. + */ + DBGC ( xhci, "XHCI %s failed to abort command\n", xhci->name ); + xhci_fail ( xhci ); + } /* Consume (and ignore) any final command status */ xhci_event_poll ( xhci ); @@ -1813,6 +1853,12 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) { unsigned int i; int rc; + /* Immediately fail all commands if command mechanism has failed */ + if ( xhci->failed ) { + rc = -EPIPE; + goto err_failed; + } + /* Sanity check */ if ( xhci->pending ) { DBGC ( xhci, "XHCI %s command ring busy\n", xhci->name ); @@ -1863,6 +1909,7 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) { err_enqueue: xhci->pending = NULL; err_pending: + err_failed: return rc; } @@ -3412,14 +3459,36 @@ static int xhci_probe ( struct pci_device *pci ) { static void xhci_remove ( struct pci_device *pci ) { struct xhci_device *xhci = pci_get_drvdata ( pci ); struct usb_bus *bus = xhci->bus; + uint16_t command; + + /* Some systems are observed to disable bus mastering on + * Thunderbolt controllers before we get a chance to shut + * down. Detect this and avoid attempting any DMA operations, + * which are guaranteed to fail and may end up spuriously + * completing after the operating system kernel starts up. + */ + pci_read_config_word ( pci, PCI_COMMAND, &command ); + if ( ! ( command & PCI_COMMAND_MASTER ) ) { + DBGC ( xhci, "XHCI %s DMA was disabled\n", xhci->name ); + xhci_fail ( xhci ); + } + /* Unregister and free USB bus */ unregister_usb_bus ( bus ); free_usb_bus ( bus ); + + /* Reset device and undo any PCH-specific fixes */ xhci_reset ( xhci ); if ( xhci->quirks & XHCI_PCH ) xhci_pch_undo ( xhci, pci ); + + /* Release ownership back to BIOS */ xhci_legacy_release ( xhci ); + + /* Unmap registers */ iounmap ( xhci->regs ); + + /* Free device */ free ( xhci ); } diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h index 6e02d70e..a3c8888a 100644 --- a/src/drivers/usb/xhci.h +++ b/src/drivers/usb/xhci.h @@ -1115,6 +1115,8 @@ struct xhci_device { struct xhci_event_ring event; /** Current command (if any) */ union xhci_trb *pending; + /** Command mechanism has permanently failed */ + int failed; /** Device slots, indexed by slot ID */ struct xhci_slot **slot; diff --git a/src/hci/keymap/keymap_al.c b/src/hci/keymap/keymap_al.c index caf295e8..ad4792b9 100644 --- a/src/hci/keymap/keymap_al.c +++ b/src/hci/keymap/keymap_al.c @@ -10,10 +10,11 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "al" keyboard mapping */ -struct key_mapping al_mapping[] __keymap = { +/** "al" basic remapping */ +static struct keymap_key al_basic[] = { { 0x19, 0x1a }, /* Ctrl-Y => Ctrl-Z */ { 0x1a, 0x19 }, /* Ctrl-Z => Ctrl-Y */ + { 0x1c, 0x1d }, /* 0x1c => 0x1d */ { 0x22, 0x7b }, /* '"' => '{' */ { 0x27, 0x5b }, /* '\'' => '[' */ { 0x3c, 0x3b }, /* '<' => ';' */ @@ -29,4 +30,29 @@ struct key_mapping al_mapping[] __keymap = { { 0x7c, 0x7d }, /* '|' => '}' */ { 0x7d, 0x27 }, /* '}' => '\'' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "al" AltGr remapping */ +static struct keymap_key al_altgr[] = { + { 0x21, 0x7e }, /* '!' => '~' */ + { 0x26, 0x60 }, /* '&' => '`' */ + { 0x29, 0x7e }, /* ')' => '~' */ + { 0x30, 0x7e }, /* '0' => '~' */ + { 0x31, 0x7e }, /* '1' => '~' */ + { 0x34, 0x7e }, /* '4' => '~' */ + { 0x37, 0x60 }, /* '7' => '`' */ + { 0x3a, 0x7e }, /* ':' => '~' */ + { 0x56, 0x60 }, /* 'V' => '`' */ + { 0x7c, 0x7e }, /* '|' => '~' */ + { 0, 0 } +}; + +/** "al" keyboard map */ +struct keymap al_keymap __keymap = { + .name = "al", + .basic = al_basic, + .altgr = al_altgr, }; diff --git a/src/hci/keymap/keymap_az.c b/src/hci/keymap/keymap_az.c deleted file mode 100644 index 27ce91e7..00000000 --- a/src/hci/keymap/keymap_az.c +++ /dev/null @@ -1,24 +0,0 @@ -/** @file - * - * "az" keyboard mapping - * - * This file is automatically generated; do not edit - * - */ - -FILE_LICENCE ( PUBLIC_DOMAIN ); - -#include <ipxe/keymap.h> - -/** "az" keyboard mapping */ -struct key_mapping az_mapping[] __keymap = { - { 0x23, 0x27 }, /* '#' => '\'' */ - { 0x24, 0x3b }, /* '$' => ';' */ - { 0x26, 0x3f }, /* '&' => '?' */ - { 0x2f, 0x2e }, /* '/' => '.' */ - { 0x3a, 0x49 }, /* ':' => 'I' */ - { 0x3f, 0x2c }, /* '?' => ',' */ - { 0x40, 0x22 }, /* '@' => '"' */ - { 0x5e, 0x3a }, /* '^' => ':' */ - { 0x7c, 0x2f }, /* '|' => '/' */ -}; diff --git a/src/hci/keymap/keymap_bg.c b/src/hci/keymap/keymap_bg.c deleted file mode 100644 index 62b6baea..00000000 --- a/src/hci/keymap/keymap_bg.c +++ /dev/null @@ -1,15 +0,0 @@ -/** @file - * - * "bg" keyboard mapping - * - * This file is automatically generated; do not edit - * - */ - -FILE_LICENCE ( PUBLIC_DOMAIN ); - -#include <ipxe/keymap.h> - -/** "bg" keyboard mapping */ -struct key_mapping bg_mapping[] __keymap = { -}; diff --git a/src/hci/keymap/keymap_by.c b/src/hci/keymap/keymap_by.c index 514d0b53..9af6c966 100644 --- a/src/hci/keymap/keymap_by.c +++ b/src/hci/keymap/keymap_by.c @@ -10,6 +10,21 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "by" keyboard mapping */ -struct key_mapping by_mapping[] __keymap = { +/** "by" basic remapping */ +static struct keymap_key by_basic[] = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "by" AltGr remapping */ +static struct keymap_key by_altgr[] = { + { 0, 0 } +}; + +/** "by" keyboard map */ +struct keymap by_keymap __keymap = { + .name = "by", + .basic = by_basic, + .altgr = by_altgr, }; diff --git a/src/hci/keymap/keymap_cf.c b/src/hci/keymap/keymap_cf.c index d7e63b9b..7ecfc444 100644 --- a/src/hci/keymap/keymap_cf.c +++ b/src/hci/keymap/keymap_cf.c @@ -10,15 +10,43 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "cf" keyboard mapping */ -struct key_mapping cf_mapping[] __keymap = { +/** "cf" basic remapping */ +static struct keymap_key cf_basic[] = { + { 0x22, 0x60 }, /* '"' => '`' */ { 0x23, 0x2f }, /* '#' => '/' */ + { 0x27, 0x60 }, /* '\'' => '`' */ { 0x3c, 0x27 }, /* '<' => '\'' */ { 0x3e, 0x2e }, /* '>' => '.' */ { 0x40, 0x22 }, /* '@' => '"' */ + { 0x5b, 0x5e }, /* '[' => '^' */ { 0x5c, 0x3c }, /* '\\' => '<' */ { 0x5e, 0x3f }, /* '^' => '?' */ { 0x60, 0x23 }, /* '`' => '#' */ + { 0x7b, 0x5e }, /* '{' => '^' */ { 0x7c, 0x3e }, /* '|' => '>' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0, 0 } +}; + +/** "cf" AltGr remapping */ +static struct keymap_key cf_altgr[] = { + { 0x22, 0x7b }, /* '"' => '{' */ + { 0x27, 0x7b }, /* '\'' => '{' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x3a, 0x7e }, /* ':' => '~' */ + { 0x3b, 0x7e }, /* ';' => '~' */ + { 0x5c, 0x7d }, /* '\\' => '}' */ + { 0x60, 0x5c }, /* '`' => '\\' */ + { 0x7b, 0x5b }, /* '{' => '[' */ + { 0x7c, 0x7d }, /* '|' => '}' */ + { 0x7d, 0x5d }, /* '}' => ']' */ + { 0x7e, 0x5c }, /* '~' => '\\' */ + { 0, 0 } +}; + +/** "cf" keyboard map */ +struct keymap cf_keymap __keymap = { + .name = "cf", + .basic = cf_basic, + .altgr = cf_altgr, }; diff --git a/src/hci/keymap/keymap_cz.c b/src/hci/keymap/keymap_cz.c index 9280f84f..dd793a8d 100644 --- a/src/hci/keymap/keymap_cz.c +++ b/src/hci/keymap/keymap_cz.c @@ -10,18 +10,87 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "cz" keyboard mapping */ -struct key_mapping cz_mapping[] __keymap = { - { 0x21, 0x2b }, /* '!' => '+' */ +/** "cz" basic remapping */ +static struct keymap_key cz_basic[] = { + { 0x19, 0x1a }, /* Ctrl-Y => Ctrl-Z */ + { 0x1a, 0x19 }, /* Ctrl-Z => Ctrl-Y */ + { 0x1f, 0x1c }, /* 0x1f => 0x1c */ + { 0x21, 0x31 }, /* '!' => '1' */ + { 0x22, 0x21 }, /* '"' => '!' */ + { 0x23, 0x33 }, /* '#' => '3' */ + { 0x24, 0x34 }, /* '$' => '4' */ + { 0x25, 0x35 }, /* '%' => '5' */ + { 0x26, 0x37 }, /* '&' => '7' */ + { 0x28, 0x39 }, /* '(' => '9' */ + { 0x29, 0x30 }, /* ')' => '0' */ + { 0x2a, 0x38 }, /* '*' => '8' */ + { 0x2b, 0x5e }, /* '+' => '^' */ { 0x2d, 0x3d }, /* '-' => '=' */ { 0x2f, 0x2d }, /* '/' => '-' */ { 0x31, 0x2b }, /* '1' => '+' */ - { 0x3c, 0x2c }, /* '<' => ',' */ - { 0x3e, 0x2e }, /* '>' => '.' */ - { 0x3f, 0x2d }, /* '?' => '-' */ + { 0x3a, 0x22 }, /* ':' => '"' */ + { 0x3c, 0x3f }, /* '<' => '?' */ + { 0x3e, 0x3a }, /* '>' => ':' */ + { 0x3f, 0x5f }, /* '?' => '_' */ + { 0x40, 0x32 }, /* '@' => '2' */ + { 0x59, 0x5a }, /* 'Y' => 'Z' */ + { 0x5a, 0x59 }, /* 'Z' => 'Y' */ { 0x5d, 0x29 }, /* ']' => ')' */ - { 0x5f, 0x3d }, /* '_' => '=' */ + { 0x5e, 0x36 }, /* '^' => '6' */ + { 0x5f, 0x25 }, /* '_' => '%' */ { 0x60, 0x3b }, /* '`' => ';' */ - { 0x7d, 0x29 }, /* '}' => ')' */ - { 0x7e, 0x3b }, /* '~' => ';' */ + { 0x79, 0x7a }, /* 'y' => 'z' */ + { 0x7a, 0x79 }, /* 'z' => 'y' */ + { 0x7b, 0x2f }, /* '{' => '/' */ + { 0x7c, 0x27 }, /* '|' => '\'' */ + { 0x7d, 0x28 }, /* '}' => '(' */ + { 0x7e, 0x60 }, /* '~' => '`' */ + { 0, 0 } +}; + +/** "cz" AltGr remapping */ +static struct keymap_key cz_altgr[] = { + { 0x21, 0x7e }, /* '!' => '~' */ + { 0x24, 0x7e }, /* '$' => '~' */ + { 0x28, 0x7b }, /* '(' => '{' */ + { 0x29, 0x7e }, /* ')' => '~' */ + { 0x2c, 0x3c }, /* ',' => '<' */ + { 0x2e, 0x3e }, /* '.' => '>' */ + { 0x2f, 0x2a }, /* '/' => '*' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x34, 0x24 }, /* '4' => '$' */ + { 0x37, 0x26 }, /* '7' => '&' */ + { 0x38, 0x2a }, /* '8' => '*' */ + { 0x39, 0x7b }, /* '9' => '{' */ + { 0x3a, 0x7e }, /* ':' => '~' */ + { 0x3b, 0x24 }, /* ';' => '$' */ + { 0x41, 0x7e }, /* 'A' => '~' */ + { 0x42, 0x7b }, /* 'B' => '{' */ + { 0x43, 0x26 }, /* 'C' => '&' */ + { 0x46, 0x5b }, /* 'F' => '[' */ + { 0x47, 0x5d }, /* 'G' => ']' */ + { 0x4b, 0x26 }, /* 'K' => '&' */ + { 0x56, 0x40 }, /* 'V' => '@' */ + { 0x58, 0x3e }, /* 'X' => '>' */ + { 0x5a, 0x3c }, /* 'Z' => '<' */ + { 0x61, 0x7e }, /* 'a' => '~' */ + { 0x62, 0x7b }, /* 'b' => '{' */ + { 0x63, 0x26 }, /* 'c' => '&' */ + { 0x66, 0x5b }, /* 'f' => '[' */ + { 0x67, 0x5d }, /* 'g' => ']' */ + { 0x6e, 0x7d }, /* 'n' => '}' */ + { 0x76, 0x40 }, /* 'v' => '@' */ + { 0x78, 0x23 }, /* 'x' => '#' */ + { 0x7b, 0x5b }, /* '{' => '[' */ + { 0x7d, 0x5d }, /* '}' => ']' */ + { 0, 0 } +}; + +/** "cz" keyboard map */ +struct keymap cz_keymap __keymap = { + .name = "cz", + .basic = cz_basic, + .altgr = cz_altgr, }; diff --git a/src/hci/keymap/keymap_de.c b/src/hci/keymap/keymap_de.c index ffcf912f..fb1136dc 100644 --- a/src/hci/keymap/keymap_de.c +++ b/src/hci/keymap/keymap_de.c @@ -10,29 +10,25 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "de" keyboard mapping */ -struct key_mapping de_mapping[] __keymap = { +/** "de" basic remapping */ +static struct keymap_key de_basic[] = { { 0x19, 0x1a }, /* Ctrl-Y => Ctrl-Z */ { 0x1a, 0x19 }, /* Ctrl-Z => Ctrl-Y */ - { 0x22, 0x7d }, /* '"' => '}' */ + { 0x1c, 0x23 }, /* 0x1c => '#' */ + { 0x1d, 0x1e }, /* 0x1d => 0x1e */ + { 0x1e, 0x36 }, /* 0x1e => '6' */ { 0x26, 0x2f }, /* '&' => '/' */ - { 0x27, 0x5d }, /* '\'' => ']' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ { 0x2a, 0x28 }, /* '*' => '(' */ { 0x2b, 0x60 }, /* '+' => '`' */ - { 0x2d, 0x5c }, /* '-' => '\\' */ { 0x2f, 0x2d }, /* '/' => '-' */ - { 0x3a, 0x7b }, /* ':' => '{' */ - { 0x3b, 0x5b }, /* ';' => '[' */ { 0x3c, 0x3b }, /* '<' => ';' */ - { 0x3d, 0x27 }, /* '=' => '\'' */ { 0x3e, 0x3a }, /* '>' => ':' */ { 0x3f, 0x5f }, /* '?' => '_' */ { 0x40, 0x22 }, /* '@' => '"' */ { 0x59, 0x5a }, /* 'Y' => 'Z' */ { 0x5a, 0x59 }, /* 'Z' => 'Y' */ - { 0x5b, 0x40 }, /* '[' => '@' */ { 0x5c, 0x23 }, /* '\\' => '#' */ { 0x5d, 0x2b }, /* ']' => '+' */ { 0x5e, 0x26 }, /* '^' => '&' */ @@ -40,7 +36,39 @@ struct key_mapping de_mapping[] __keymap = { { 0x60, 0x5e }, /* '`' => '^' */ { 0x79, 0x7a }, /* 'y' => 'z' */ { 0x7a, 0x79 }, /* 'z' => 'y' */ - { 0x7b, 0x5c }, /* '{' => '\\' */ { 0x7c, 0x27 }, /* '|' => '\'' */ { 0x7d, 0x2a }, /* '}' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "de" AltGr remapping */ +static struct keymap_key de_altgr[] = { + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x3a, 0x7e }, /* ':' => '~' */ + { 0x3b, 0x7e }, /* ';' => '~' */ + { 0x51, 0x40 }, /* 'Q' => '@' */ + { 0x5d, 0x7e }, /* ']' => '~' */ + { 0x5f, 0x5c }, /* '_' => '\\' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0x7c, 0x7e }, /* '|' => '~' */ + { 0x7d, 0x7e }, /* '}' => '~' */ + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + +/** "de" keyboard map */ +struct keymap de_keymap __keymap = { + .name = "de", + .basic = de_basic, + .altgr = de_altgr, }; diff --git a/src/hci/keymap/keymap_dk.c b/src/hci/keymap/keymap_dk.c index e409018c..45cdeb25 100644 --- a/src/hci/keymap/keymap_dk.c +++ b/src/hci/keymap/keymap_dk.c @@ -10,8 +10,10 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "dk" keyboard mapping */ -struct key_mapping dk_mapping[] __keymap = { +/** "dk" basic remapping */ +static struct keymap_key dk_basic[] = { + { 0x1c, 0x27 }, /* 0x1c => '\'' */ + { 0x1e, 0x36 }, /* 0x1e => '6' */ { 0x26, 0x2f }, /* '&' => '/' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ @@ -28,4 +30,38 @@ struct key_mapping dk_mapping[] __keymap = { { 0x5f, 0x3f }, /* '_' => '?' */ { 0x7c, 0x2a }, /* '|' => '*' */ { 0x7d, 0x5e }, /* '}' => '^' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "dk" AltGr remapping */ +static struct keymap_key dk_altgr[] = { + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x2b, 0x7c }, /* '+' => '|' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x34, 0x24 }, /* '4' => '$' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x3a, 0x7e }, /* ':' => '~' */ + { 0x3d, 0x7c }, /* '=' => '|' */ + { 0x51, 0x40 }, /* 'Q' => '@' */ + { 0x5c, 0x7e }, /* '\\' => '~' */ + { 0x5d, 0x7e }, /* ']' => '~' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0x7c, 0x7e }, /* '|' => '~' */ + { 0xfc, 0x5c }, /* Pseudo-'|' => '\\' */ + { 0, 0 } +}; + +/** "dk" keyboard map */ +struct keymap dk_keymap __keymap = { + .name = "dk", + .basic = dk_basic, + .altgr = dk_altgr, }; diff --git a/src/hci/keymap/keymap_es.c b/src/hci/keymap/keymap_es.c index c1fe013a..c1c55b34 100644 --- a/src/hci/keymap/keymap_es.c +++ b/src/hci/keymap/keymap_es.c @@ -10,8 +10,10 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "es" keyboard mapping */ -struct key_mapping es_mapping[] __keymap = { +/** "es" basic remapping */ +static struct keymap_key es_basic[] = { + { 0x1c, 0x1d }, /* 0x1c => 0x1d */ + { 0x1e, 0x36 }, /* 0x1e => '6' */ { 0x26, 0x2f }, /* '&' => '/' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ @@ -22,8 +24,54 @@ struct key_mapping es_mapping[] __keymap = { { 0x3e, 0x3a }, /* '>' => ':' */ { 0x3f, 0x5f }, /* '?' => '_' */ { 0x40, 0x22 }, /* '@' => '"' */ + { 0x5b, 0x60 }, /* '[' => '`' */ { 0x5d, 0x2b }, /* ']' => '+' */ { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ + { 0x7b, 0x5e }, /* '{' => '^' */ { 0x7d, 0x2a }, /* '}' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "es" AltGr remapping */ +static struct keymap_key es_altgr[] = { + { 0x21, 0x7c }, /* '!' => '|' */ + { 0x22, 0x7b }, /* '"' => '{' */ + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x27, 0x7b }, /* '\'' => '{' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x2b, 0x7e }, /* '+' => '~' */ + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x31, 0x7c }, /* '1' => '|' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x34, 0x7e }, /* '4' => '~' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x3a, 0x7e }, /* ':' => '~' */ + { 0x3b, 0x7e }, /* ';' => '~' */ + { 0x3d, 0x7e }, /* '=' => '~' */ + { 0x51, 0x40 }, /* 'Q' => '@' */ + { 0x5c, 0x7d }, /* '\\' => '}' */ + { 0x5f, 0x5c }, /* '_' => '\\' */ + { 0x60, 0x5c }, /* '`' => '\\' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0x7b, 0x5b }, /* '{' => '[' */ + { 0x7c, 0x7e }, /* '|' => '~' */ + { 0x7e, 0x5c }, /* '~' => '\\' */ + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + +/** "es" keyboard map */ +struct keymap es_keymap __keymap = { + .name = "es", + .basic = es_basic, + .altgr = es_altgr, }; diff --git a/src/hci/keymap/keymap_et.c b/src/hci/keymap/keymap_et.c index ad88cecc..4d763266 100644 --- a/src/hci/keymap/keymap_et.c +++ b/src/hci/keymap/keymap_et.c @@ -10,12 +10,13 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "et" keyboard mapping */ -struct key_mapping et_mapping[] __keymap = { +/** "et" basic remapping */ +static struct keymap_key et_basic[] = { { 0x26, 0x2f }, /* '&' => '/' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ { 0x2a, 0x28 }, /* '*' => '(' */ + { 0x2b, 0x60 }, /* '+' => '`' */ { 0x2d, 0x2b }, /* '-' => '+' */ { 0x2f, 0x2d }, /* '/' => '-' */ { 0x3c, 0x3b }, /* '<' => ';' */ @@ -25,6 +26,34 @@ struct key_mapping et_mapping[] __keymap = { { 0x5c, 0x27 }, /* '\\' => '\'' */ { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ + { 0x60, 0x5e }, /* '`' => '^' */ { 0x7c, 0x2a }, /* '|' => '*' */ - { 0x7f, 0x1b }, /* 0x7f => 0x1b */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "et" AltGr remapping */ +static struct keymap_key et_altgr[] = { + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x34, 0x24 }, /* '4' => '$' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x5f, 0x5c }, /* '_' => '\\' */ + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + +/** "et" keyboard map */ +struct keymap et_keymap __keymap = { + .name = "et", + .basic = et_basic, + .altgr = et_altgr, }; diff --git a/src/hci/keymap/keymap_fi.c b/src/hci/keymap/keymap_fi.c index c8f6c3a0..8bcd0c39 100644 --- a/src/hci/keymap/keymap_fi.c +++ b/src/hci/keymap/keymap_fi.c @@ -10,29 +10,51 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "fi" keyboard mapping */ -struct key_mapping fi_mapping[] __keymap = { - { 0x22, 0x5b }, /* '"' => '[' */ +/** "fi" basic remapping */ +static struct keymap_key fi_basic[] = { { 0x26, 0x2f }, /* '&' => '/' */ - { 0x27, 0x7b }, /* '\'' => '{' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ { 0x2a, 0x28 }, /* '*' => '(' */ { 0x2b, 0x60 }, /* '+' => '`' */ { 0x2d, 0x2b }, /* '-' => '+' */ { 0x2f, 0x2d }, /* '/' => '-' */ - { 0x3a, 0x5c }, /* ':' => '\\' */ - { 0x3b, 0x7c }, /* ';' => '|' */ { 0x3c, 0x3b }, /* '<' => ';' */ - { 0x3d, 0x27 }, /* '=' => '\'' */ { 0x3e, 0x3a }, /* '>' => ':' */ { 0x3f, 0x5f }, /* '?' => '_' */ { 0x40, 0x22 }, /* '@' => '"' */ - { 0x5b, 0x7d }, /* '[' => '}' */ { 0x5c, 0x27 }, /* '\\' => '\'' */ { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ - { 0x7b, 0x5d }, /* '{' => ']' */ { 0x7c, 0x2a }, /* '|' => '*' */ { 0x7d, 0x5e }, /* '}' => '^' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "fi" AltGr remapping */ +static struct keymap_key fi_altgr[] = { + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x34, 0x24 }, /* '4' => '$' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x49, 0x7c }, /* 'I' => '|' */ + { 0x5d, 0x7e }, /* ']' => '~' */ + { 0x5f, 0x5c }, /* '_' => '\\' */ + { 0x7d, 0x7e }, /* '}' => '~' */ + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + +/** "fi" keyboard map */ +struct keymap fi_keymap __keymap = { + .name = "fi", + .basic = fi_basic, + .altgr = fi_altgr, }; diff --git a/src/hci/keymap/keymap_fr.c b/src/hci/keymap/keymap_fr.c index fd615a45..23a0837f 100644 --- a/src/hci/keymap/keymap_fr.c +++ b/src/hci/keymap/keymap_fr.c @@ -10,19 +10,22 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "fr" keyboard mapping */ -struct key_mapping fr_mapping[] __keymap = { +/** "fr" basic remapping */ +static struct keymap_key fr_basic[] = { { 0x01, 0x11 }, /* Ctrl-A => Ctrl-Q */ { 0x11, 0x01 }, /* Ctrl-Q => Ctrl-A */ { 0x17, 0x1a }, /* Ctrl-W => Ctrl-Z */ { 0x1a, 0x17 }, /* Ctrl-Z => Ctrl-W */ + { 0x1c, 0x2a }, /* 0x1c => '*' */ + { 0x1d, 0x24 }, /* 0x1d => '$' */ + { 0x1e, 0x1c }, /* 0x1e => 0x1c */ + { 0x1f, 0x1d }, /* 0x1f => 0x1d */ { 0x21, 0x31 }, /* '!' => '1' */ { 0x22, 0x25 }, /* '"' => '%' */ { 0x23, 0x33 }, /* '#' => '3' */ { 0x24, 0x34 }, /* '$' => '4' */ { 0x25, 0x35 }, /* '%' => '5' */ { 0x26, 0x37 }, /* '&' => '7' */ - { 0x27, 0x7c }, /* '\'' => '|' */ { 0x28, 0x39 }, /* '(' => '9' */ { 0x29, 0x30 }, /* ')' => '0' */ { 0x2a, 0x38 }, /* '*' => '8' */ @@ -30,21 +33,16 @@ struct key_mapping fr_mapping[] __keymap = { { 0x2d, 0x29 }, /* '-' => ')' */ { 0x2e, 0x3a }, /* '.' => ':' */ { 0x2f, 0x21 }, /* '/' => '!' */ - { 0x30, 0x40 }, /* '0' => '@' */ { 0x31, 0x26 }, /* '1' => '&' */ - { 0x32, 0x7b }, /* '2' => '{' */ { 0x33, 0x22 }, /* '3' => '"' */ { 0x34, 0x27 }, /* '4' => '\'' */ { 0x35, 0x28 }, /* '5' => '(' */ { 0x36, 0x2d }, /* '6' => '-' */ - { 0x37, 0x7d }, /* '7' => '}' */ { 0x38, 0x5f }, /* '8' => '_' */ - { 0x39, 0x2f }, /* '9' => '/' */ { 0x3a, 0x4d }, /* ':' => 'M' */ { 0x3b, 0x6d }, /* ';' => 'm' */ { 0x3c, 0x2e }, /* '<' => '.' */ { 0x3e, 0x2f }, /* '>' => '/' */ - { 0x3f, 0x5c }, /* '?' => '\\' */ { 0x40, 0x32 }, /* '@' => '2' */ { 0x41, 0x51 }, /* 'A' => 'Q' */ { 0x4d, 0x3f }, /* 'M' => '?' */ @@ -55,14 +53,44 @@ struct key_mapping fr_mapping[] __keymap = { { 0x5c, 0x2a }, /* '\\' => '*' */ { 0x5d, 0x24 }, /* ']' => '$' */ { 0x5e, 0x36 }, /* '^' => '6' */ - { 0x5f, 0x5d }, /* '_' => ']' */ - { 0x60, 0x2a }, /* '`' => '*' */ { 0x61, 0x71 }, /* 'a' => 'q' */ { 0x6d, 0x2c }, /* 'm' => ',' */ { 0x71, 0x61 }, /* 'q' => 'a' */ { 0x77, 0x7a }, /* 'w' => 'z' */ { 0x7a, 0x77 }, /* 'z' => 'w' */ - { 0x7b, 0x3c }, /* '{' => '<' */ - { 0x7c, 0x23 }, /* '|' => '#' */ - { 0x7d, 0x3e }, /* '}' => '>' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "fr" AltGr remapping */ +static struct keymap_key fr_altgr[] = { + { 0x25, 0x5b }, /* '%' => '[' */ + { 0x26, 0x60 }, /* '&' => '`' */ + { 0x29, 0x40 }, /* ')' => '@' */ + { 0x2a, 0x5c }, /* '*' => '\\' */ + { 0x2b, 0x7d }, /* '+' => '}' */ + { 0x2d, 0x5d }, /* '-' => ']' */ + { 0x30, 0x40 }, /* '0' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x34, 0x7b }, /* '4' => '{' */ + { 0x35, 0x5b }, /* '5' => '[' */ + { 0x36, 0x7c }, /* '6' => '|' */ + { 0x37, 0x60 }, /* '7' => '`' */ + { 0x38, 0x5c }, /* '8' => '\\' */ + { 0x3d, 0x7d }, /* '=' => '}' */ + { 0x41, 0x40 }, /* 'A' => '@' */ + { 0x5c, 0x60 }, /* '\\' => '`' */ + { 0x5e, 0x7c }, /* '^' => '|' */ + { 0x5f, 0x5d }, /* '_' => ']' */ + { 0x61, 0x40 }, /* 'a' => '@' */ + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + +/** "fr" keyboard map */ +struct keymap fr_keymap __keymap = { + .name = "fr", + .basic = fr_basic, + .altgr = fr_altgr, }; diff --git a/src/hci/keymap/keymap_gr.c b/src/hci/keymap/keymap_gr.c index 42b6418e..4826c26c 100644 --- a/src/hci/keymap/keymap_gr.c +++ b/src/hci/keymap/keymap_gr.c @@ -10,6 +10,21 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "gr" keyboard mapping */ -struct key_mapping gr_mapping[] __keymap = { +/** "gr" basic remapping */ +static struct keymap_key gr_basic[] = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "gr" AltGr remapping */ +static struct keymap_key gr_altgr[] = { + { 0, 0 } +}; + +/** "gr" keyboard map */ +struct keymap gr_keymap __keymap = { + .name = "gr", + .basic = gr_basic, + .altgr = gr_altgr, }; diff --git a/src/hci/keymap/keymap_hu.c b/src/hci/keymap/keymap_hu.c index 68eff2f4..77167140 100644 --- a/src/hci/keymap/keymap_hu.c +++ b/src/hci/keymap/keymap_hu.c @@ -10,10 +10,11 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "hu" keyboard mapping */ -struct key_mapping hu_mapping[] __keymap = { +/** "hu" basic remapping */ +static struct keymap_key hu_basic[] = { { 0x19, 0x1a }, /* Ctrl-Y => Ctrl-Z */ { 0x1a, 0x19 }, /* Ctrl-Z => Ctrl-Y */ + { 0x1e, 0x36 }, /* 0x1e => '6' */ { 0x21, 0x27 }, /* '!' => '\'' */ { 0x23, 0x2b }, /* '#' => '+' */ { 0x24, 0x21 }, /* '$' => '!' */ @@ -31,4 +32,60 @@ struct key_mapping hu_mapping[] __keymap = { { 0x60, 0x30 }, /* '`' => '0' */ { 0x79, 0x7a }, /* 'y' => 'z' */ { 0x7a, 0x79 }, /* 'z' => 'y' */ + { 0, 0 } +}; + +/** "hu" AltGr remapping */ +static struct keymap_key hu_altgr[] = { + { 0x21, 0x7e }, /* '!' => '~' */ + { 0x23, 0x5e }, /* '#' => '^' */ + { 0x24, 0x7e }, /* '$' => '~' */ + { 0x26, 0x60 }, /* '&' => '`' */ + { 0x29, 0x7e }, /* ')' => '~' */ + { 0x2c, 0x3b }, /* ',' => ';' */ + { 0x2e, 0x3e }, /* '.' => '>' */ + { 0x2f, 0x2a }, /* '/' => '*' */ + { 0x30, 0x7e }, /* '0' => '~' */ + { 0x31, 0x7e }, /* '1' => '~' */ + { 0x32, 0x5e }, /* '2' => '^' */ + { 0x33, 0x5e }, /* '3' => '^' */ + { 0x34, 0x7e }, /* '4' => '~' */ + { 0x37, 0x60 }, /* '7' => '`' */ + { 0x3a, 0x24 }, /* ':' => '$' */ + { 0x3b, 0x24 }, /* ';' => '$' */ + { 0x3c, 0x3b }, /* '<' => ';' */ + { 0x40, 0x5e }, /* '@' => '^' */ + { 0x42, 0x7b }, /* 'B' => '{' */ + { 0x43, 0x26 }, /* 'C' => '&' */ + { 0x46, 0x5b }, /* 'F' => '[' */ + { 0x47, 0x5d }, /* 'G' => ']' */ + { 0x4b, 0x26 }, /* 'K' => '&' */ + { 0x4d, 0x3c }, /* 'M' => '<' */ + { 0x51, 0x5c }, /* 'Q' => '\\' */ + { 0x56, 0x40 }, /* 'V' => '@' */ + { 0x57, 0x7c }, /* 'W' => '|' */ + { 0x58, 0x3e }, /* 'X' => '>' */ + { 0x5a, 0x3c }, /* 'Z' => '<' */ + { 0x62, 0x7b }, /* 'b' => '{' */ + { 0x63, 0x26 }, /* 'c' => '&' */ + { 0x66, 0x5b }, /* 'f' => '[' */ + { 0x67, 0x5d }, /* 'g' => ']' */ + { 0x6d, 0x3c }, /* 'm' => '<' */ + { 0x6e, 0x7d }, /* 'n' => '}' */ + { 0x71, 0x5c }, /* 'q' => '\\' */ + { 0x76, 0x40 }, /* 'v' => '@' */ + { 0x77, 0x7c }, /* 'w' => '|' */ + { 0x78, 0x23 }, /* 'x' => '#' */ + { 0x7a, 0x3e }, /* 'z' => '>' */ + { 0x7c, 0x7e }, /* '|' => '~' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "hu" keyboard map */ +struct keymap hu_keymap __keymap = { + .name = "hu", + .basic = hu_basic, + .altgr = hu_altgr, }; diff --git a/src/hci/keymap/keymap_il.c b/src/hci/keymap/keymap_il.c index 478330c0..b11e7ce7 100644 --- a/src/hci/keymap/keymap_il.c +++ b/src/hci/keymap/keymap_il.c @@ -10,6 +10,39 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "il" keyboard mapping */ -struct key_mapping il_mapping[] __keymap = { +/** "il" basic remapping */ +static struct keymap_key il_basic[] = { + { 0x1d, 0x1b }, /* 0x1d => 0x1b */ + { 0x27, 0x2c }, /* '\'' => ',' */ + { 0x28, 0x29 }, /* '(' => ')' */ + { 0x29, 0x28 }, /* ')' => '(' */ + { 0x2f, 0x2e }, /* '/' => '.' */ + { 0x3c, 0x3e }, /* '<' => '>' */ + { 0x3e, 0x3c }, /* '>' => '<' */ + { 0x5b, 0x5d }, /* '[' => ']' */ + { 0x5d, 0x5b }, /* ']' => '[' */ + { 0x60, 0x3b }, /* '`' => ';' */ + { 0x7b, 0x7d }, /* '{' => '}' */ + { 0x7d, 0x7b }, /* '}' => '{' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "il" AltGr remapping */ +static struct keymap_key il_altgr[] = { + { 0x22, 0x27 }, /* '"' => '\'' */ + { 0x3f, 0x2f }, /* '?' => '/' */ + { 0x5c, 0x60 }, /* '\\' => '`' */ + { 0x71, 0x2f }, /* 'q' => '/' */ + { 0x77, 0x27 }, /* 'w' => '\'' */ + { 0x7c, 0x60 }, /* '|' => '`' */ + { 0, 0 } +}; + +/** "il" keyboard map */ +struct keymap il_keymap __keymap = { + .name = "il", + .basic = il_basic, + .altgr = il_altgr, }; diff --git a/src/hci/keymap/keymap_it.c b/src/hci/keymap/keymap_it.c index 5bb05471..bb14ae1b 100644 --- a/src/hci/keymap/keymap_it.c +++ b/src/hci/keymap/keymap_it.c @@ -10,8 +10,9 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "it" keyboard mapping */ -struct key_mapping it_mapping[] __keymap = { +/** "it" basic remapping */ +static struct keymap_key it_basic[] = { + { 0x1e, 0x36 }, /* 0x1e => '6' */ { 0x26, 0x2f }, /* '&' => '/' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ @@ -29,4 +30,40 @@ struct key_mapping it_mapping[] __keymap = { { 0x60, 0x5c }, /* '`' => '\\' */ { 0x7d, 0x2a }, /* '}' => '*' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "it" AltGr remapping */ +static struct keymap_key it_altgr[] = { + { 0x22, 0x23 }, /* '"' => '#' */ + { 0x23, 0x7e }, /* '#' => '~' */ + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x27, 0x23 }, /* '\'' => '#' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x2d, 0x60 }, /* '-' => '`' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x3a, 0x40 }, /* ':' => '@' */ + { 0x3b, 0x40 }, /* ';' => '@' */ + { 0x3d, 0x7e }, /* '=' => '~' */ + { 0x40, 0x7e }, /* '@' => '~' */ + { 0x51, 0x40 }, /* 'Q' => '@' */ + { 0x5c, 0x60 }, /* '\\' => '`' */ + { 0x5f, 0x60 }, /* '_' => '`' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0x7c, 0x7e }, /* '|' => '~' */ + { 0, 0 } +}; + +/** "it" keyboard map */ +struct keymap it_keymap __keymap = { + .name = "it", + .basic = it_basic, + .altgr = it_altgr, }; diff --git a/src/hci/keymap/keymap_lt.c b/src/hci/keymap/keymap_lt.c index 3e99d8c6..f8e60a5c 100644 --- a/src/hci/keymap/keymap_lt.c +++ b/src/hci/keymap/keymap_lt.c @@ -10,6 +10,24 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "lt" keyboard mapping */ -struct key_mapping lt_mapping[] __keymap = { +/** "lt" basic remapping */ +static struct keymap_key lt_basic[] = { + { 0, 0 } +}; + +/** "lt" AltGr remapping */ +static struct keymap_key lt_altgr[] = { + { 0x22, 0x5e }, /* '"' => '^' */ + { 0x27, 0x5e }, /* '\'' => '^' */ + { 0x4b, 0x26 }, /* 'K' => '&' */ + { 0x51, 0x40 }, /* 'Q' => '@' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0, 0 } +}; + +/** "lt" keyboard map */ +struct keymap lt_keymap __keymap = { + .name = "lt", + .basic = lt_basic, + .altgr = lt_altgr, }; diff --git a/src/hci/keymap/keymap_mk.c b/src/hci/keymap/keymap_mk.c index 8f506077..4b90ef79 100644 --- a/src/hci/keymap/keymap_mk.c +++ b/src/hci/keymap/keymap_mk.c @@ -10,6 +10,21 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "mk" keyboard mapping */ -struct key_mapping mk_mapping[] __keymap = { +/** "mk" basic remapping */ +static struct keymap_key mk_basic[] = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "mk" AltGr remapping */ +static struct keymap_key mk_altgr[] = { + { 0, 0 } +}; + +/** "mk" keyboard map */ +struct keymap mk_keymap __keymap = { + .name = "mk", + .basic = mk_basic, + .altgr = mk_altgr, }; diff --git a/src/hci/keymap/keymap_mt.c b/src/hci/keymap/keymap_mt.c index 094a6fc6..0997bfe9 100644 --- a/src/hci/keymap/keymap_mt.c +++ b/src/hci/keymap/keymap_mt.c @@ -10,11 +10,34 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "mt" keyboard mapping */ -struct key_mapping mt_mapping[] __keymap = { +/** "mt" basic remapping */ +static struct keymap_key mt_basic[] = { + { 0x1c, 0x1e }, /* 0x1c => 0x1e */ { 0x22, 0x40 }, /* '"' => '@' */ - { 0x23, 0x04 }, /* '#' => Ctrl-D */ { 0x40, 0x22 }, /* '@' => '"' */ { 0x5c, 0x23 }, /* '\\' => '#' */ { 0x7c, 0x7e }, /* '|' => '~' */ + { 0, 0 } +}; + +/** "mt" AltGr remapping */ +static struct keymap_key mt_altgr[] = { + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x5c, 0x60 }, /* '\\' => '`' */ + { 0x7e, 0x60 }, /* '~' => '`' */ + { 0, 0 } +}; + +/** "mt" keyboard map */ +struct keymap mt_keymap __keymap = { + .name = "mt", + .basic = mt_basic, + .altgr = mt_altgr, }; diff --git a/src/hci/keymap/keymap_nl.c b/src/hci/keymap/keymap_nl.c index ba051705..97c7e8b5 100644 --- a/src/hci/keymap/keymap_nl.c +++ b/src/hci/keymap/keymap_nl.c @@ -10,8 +10,12 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "nl" keyboard mapping */ -struct key_mapping nl_mapping[] __keymap = { +/** "nl" basic remapping */ +static struct keymap_key nl_basic[] = { + { 0x1c, 0x3c }, /* 0x1c => '<' */ + { 0x1d, 0x1c }, /* 0x1d => 0x1c */ + { 0x1e, 0x36 }, /* 0x1e => '6' */ + { 0x22, 0x60 }, /* '"' => '`' */ { 0x26, 0x5f }, /* '&' => '_' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x27 }, /* ')' => '\'' */ @@ -29,6 +33,26 @@ struct key_mapping nl_mapping[] __keymap = { { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x60, 0x40 }, /* '`' => '@' */ + { 0x7b, 0x5e }, /* '{' => '^' */ { 0x7c, 0x3e }, /* '|' => '>' */ { 0x7d, 0x7c }, /* '}' => '|' */ + { 0xdc, 0x5d }, /* Pseudo-'\\' => ']' */ + { 0xfc, 0x5b }, /* Pseudo-'|' => '[' */ + { 0, 0 } +}; + +/** "nl" AltGr remapping */ +static struct keymap_key nl_altgr[] = { + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x38, 0x7b }, /* '8' => '{' */ + { 0x39, 0x7d }, /* '9' => '}' */ + { 0x5f, 0x5c }, /* '_' => '\\' */ + { 0, 0 } +}; + +/** "nl" keyboard map */ +struct keymap nl_keymap __keymap = { + .name = "nl", + .basic = nl_basic, + .altgr = nl_altgr, }; diff --git a/src/hci/keymap/keymap_no-latin1.c b/src/hci/keymap/keymap_no-latin1.c index 8c3e81b3..80df8488 100644 --- a/src/hci/keymap/keymap_no-latin1.c +++ b/src/hci/keymap/keymap_no-latin1.c @@ -10,8 +10,9 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "no-latin1" keyboard mapping */ -struct key_mapping no_latin1_mapping[] __keymap = { +/** "no-latin1" basic remapping */ +static struct keymap_key no_latin1_basic[] = { + { 0x1d, 0x1e }, /* 0x1d => 0x1e */ { 0x26, 0x2f }, /* '&' => '/' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ @@ -31,4 +32,32 @@ struct key_mapping no_latin1_mapping[] __keymap = { { 0x60, 0x7c }, /* '`' => '|' */ { 0x7c, 0x2a }, /* '|' => '*' */ { 0x7d, 0x5e }, /* '}' => '^' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "no-latin1" AltGr remapping */ +static struct keymap_key no_latin1_altgr[] = { + { 0x22, 0x5b }, /* '"' => '[' */ + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x27, 0x7b }, /* '\'' => '{' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x5b, 0x7d }, /* '[' => '}' */ + { 0x7b, 0x5d }, /* '{' => ']' */ + { 0, 0 } +}; + +/** "no-latin1" keyboard map */ +struct keymap no_latin1_keymap __keymap = { + .name = "no-latin1", + .basic = no_latin1_basic, + .altgr = no_latin1_altgr, }; diff --git a/src/hci/keymap/keymap_no.c b/src/hci/keymap/keymap_no.c index 45cf9e84..0a624c3a 100644 --- a/src/hci/keymap/keymap_no.c +++ b/src/hci/keymap/keymap_no.c @@ -10,96 +10,57 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "no" keyboard mapping */ -struct key_mapping no_mapping[] __keymap = { - { 0x02, 0x18 }, /* Ctrl-B => Ctrl-X */ - { 0x03, 0x0a }, /* Ctrl-C => Ctrl-J */ - { 0x04, 0x05 }, /* Ctrl-D => Ctrl-E */ - { 0x06, 0x15 }, /* Ctrl-F => Ctrl-U */ - { 0x07, 0x09 }, /* Ctrl-G => Ctrl-I */ - { 0x08, 0x04 }, /* Ctrl-H => Ctrl-D */ - { 0x0a, 0x08 }, /* Ctrl-J => Ctrl-H */ - { 0x0b, 0x14 }, /* Ctrl-K => Ctrl-T */ - { 0x0c, 0x0e }, /* Ctrl-L => Ctrl-N */ - { 0x0e, 0x02 }, /* Ctrl-N => Ctrl-B */ - { 0x0f, 0x12 }, /* Ctrl-O => Ctrl-R */ - { 0x10, 0x0c }, /* Ctrl-P => Ctrl-L */ - { 0x12, 0x10 }, /* Ctrl-R => Ctrl-P */ - { 0x13, 0x0f }, /* Ctrl-S => Ctrl-O */ - { 0x14, 0x19 }, /* Ctrl-T => Ctrl-Y */ - { 0x15, 0x07 }, /* Ctrl-U => Ctrl-G */ - { 0x16, 0x0b }, /* Ctrl-V => Ctrl-K */ - { 0x18, 0x11 }, /* Ctrl-X => Ctrl-Q */ - { 0x19, 0x06 }, /* Ctrl-Y => Ctrl-F */ - { 0x22, 0x5f }, /* '"' => '_' */ +/** "no" basic remapping */ +static struct keymap_key no_basic[] = { + { 0x1c, 0x27 }, /* 0x1c => '\'' */ + { 0x1e, 0x36 }, /* 0x1e => '6' */ { 0x26, 0x2f }, /* '&' => '/' */ - { 0x27, 0x2d }, /* '\'' => '-' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ { 0x2a, 0x28 }, /* '*' => '(' */ { 0x2b, 0x60 }, /* '+' => '`' */ - { 0x2c, 0x77 }, /* ',' => 'w' */ { 0x2d, 0x2b }, /* '-' => '+' */ - { 0x2e, 0x76 }, /* '.' => 'v' */ - { 0x2f, 0x7a }, /* '/' => 'z' */ - { 0x3a, 0x53 }, /* ':' => 'S' */ - { 0x3b, 0x73 }, /* ';' => 's' */ - { 0x3c, 0x57 }, /* '<' => 'W' */ + { 0x2f, 0x2d }, /* '/' => '-' */ + { 0x3c, 0x3b }, /* '<' => ';' */ { 0x3d, 0x5c }, /* '=' => '\\' */ - { 0x3e, 0x56 }, /* '>' => 'V' */ - { 0x3f, 0x5a }, /* '?' => 'Z' */ + { 0x3e, 0x3a }, /* '>' => ':' */ + { 0x3f, 0x5f }, /* '?' => '_' */ { 0x40, 0x22 }, /* '@' => '"' */ - { 0x42, 0x58 }, /* 'B' => 'X' */ - { 0x43, 0x4a }, /* 'C' => 'J' */ - { 0x44, 0x45 }, /* 'D' => 'E' */ - { 0x45, 0x3a }, /* 'E' => ':' */ - { 0x46, 0x55 }, /* 'F' => 'U' */ - { 0x47, 0x49 }, /* 'G' => 'I' */ - { 0x48, 0x44 }, /* 'H' => 'D' */ - { 0x49, 0x43 }, /* 'I' => 'C' */ - { 0x4a, 0x48 }, /* 'J' => 'H' */ - { 0x4b, 0x54 }, /* 'K' => 'T' */ - { 0x4c, 0x4e }, /* 'L' => 'N' */ - { 0x4e, 0x42 }, /* 'N' => 'B' */ - { 0x4f, 0x52 }, /* 'O' => 'R' */ - { 0x50, 0x4c }, /* 'P' => 'L' */ - { 0x52, 0x50 }, /* 'R' => 'P' */ - { 0x53, 0x4f }, /* 'S' => 'O' */ - { 0x54, 0x59 }, /* 'T' => 'Y' */ - { 0x55, 0x47 }, /* 'U' => 'G' */ - { 0x56, 0x4b }, /* 'V' => 'K' */ - { 0x57, 0x3b }, /* 'W' => ';' */ - { 0x58, 0x51 }, /* 'X' => 'Q' */ - { 0x59, 0x46 }, /* 'Y' => 'F' */ - { 0x5b, 0x27 }, /* '[' => '\'' */ - { 0x5c, 0x3c }, /* '\\' => '<' */ - { 0x5d, 0x7e }, /* ']' => '~' */ + { 0x5c, 0x27 }, /* '\\' => '\'' */ { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x60, 0x7c }, /* '`' => '|' */ - { 0x62, 0x78 }, /* 'b' => 'x' */ - { 0x63, 0x6a }, /* 'c' => 'j' */ - { 0x64, 0x65 }, /* 'd' => 'e' */ - { 0x65, 0x2e }, /* 'e' => '.' */ - { 0x66, 0x75 }, /* 'f' => 'u' */ - { 0x67, 0x69 }, /* 'g' => 'i' */ - { 0x68, 0x64 }, /* 'h' => 'd' */ - { 0x69, 0x63 }, /* 'i' => 'c' */ - { 0x6a, 0x68 }, /* 'j' => 'h' */ - { 0x6b, 0x74 }, /* 'k' => 't' */ - { 0x6c, 0x6e }, /* 'l' => 'n' */ - { 0x6e, 0x62 }, /* 'n' => 'b' */ - { 0x6f, 0x72 }, /* 'o' => 'r' */ - { 0x70, 0x6c }, /* 'p' => 'l' */ - { 0x72, 0x70 }, /* 'r' => 'p' */ - { 0x73, 0x6f }, /* 's' => 'o' */ - { 0x74, 0x79 }, /* 't' => 'y' */ - { 0x75, 0x67 }, /* 'u' => 'g' */ - { 0x76, 0x6b }, /* 'v' => 'k' */ - { 0x77, 0x2c }, /* 'w' => ',' */ - { 0x78, 0x71 }, /* 'x' => 'q' */ - { 0x79, 0x66 }, /* 'y' => 'f' */ - { 0x7b, 0x2a }, /* '{' => '*' */ - { 0x7c, 0x3e }, /* '|' => '>' */ + { 0x7c, 0x2a }, /* '|' => '*' */ { 0x7d, 0x5e }, /* '}' => '^' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "no" AltGr remapping */ +static struct keymap_key no_altgr[] = { + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x34, 0x24 }, /* '4' => '$' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x3a, 0x7e }, /* ':' => '~' */ + { 0x51, 0x40 }, /* 'Q' => '@' */ + { 0x5c, 0x7e }, /* '\\' => '~' */ + { 0x5d, 0x7e }, /* ']' => '~' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0x7c, 0x7e }, /* '|' => '~' */ + { 0, 0 } +}; + +/** "no" keyboard map */ +struct keymap no_keymap __keymap = { + .name = "no", + .basic = no_basic, + .altgr = no_altgr, }; diff --git a/src/hci/keymap/keymap_pl.c b/src/hci/keymap/keymap_pl.c index 51822e07..a76181fb 100644 --- a/src/hci/keymap/keymap_pl.c +++ b/src/hci/keymap/keymap_pl.c @@ -10,6 +10,21 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "pl" keyboard mapping */ -struct key_mapping pl_mapping[] __keymap = { +/** "pl" basic remapping */ +static struct keymap_key pl_basic[] = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "pl" AltGr remapping */ +static struct keymap_key pl_altgr[] = { + { 0, 0 } +}; + +/** "pl" keyboard map */ +struct keymap pl_keymap __keymap = { + .name = "pl", + .basic = pl_basic, + .altgr = pl_altgr, }; diff --git a/src/hci/keymap/keymap_pt.c b/src/hci/keymap/keymap_pt.c index a8e44b6a..3133c156 100644 --- a/src/hci/keymap/keymap_pt.c +++ b/src/hci/keymap/keymap_pt.c @@ -10,20 +10,53 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "pt" keyboard mapping */ -struct key_mapping pt_mapping[] __keymap = { - { 0x1c, 0x1d }, /* 0x1c => 0x1d */ - { 0x1d, 0x1b }, /* 0x1d => 0x1b */ - { 0x22, 0x5e }, /* '"' => '^' */ - { 0x27, 0x7e }, /* '\'' => '~' */ - { 0x2f, 0x3b }, /* '/' => ';' */ - { 0x3f, 0x3a }, /* '?' => ':' */ - { 0x5b, 0x27 }, /* '[' => '\'' */ - { 0x5c, 0x5d }, /* '\\' => ']' */ - { 0x5d, 0x5b }, /* ']' => '[' */ - { 0x60, 0x27 }, /* '`' => '\'' */ - { 0x7b, 0x60 }, /* '{' => '`' */ - { 0x7c, 0x7d }, /* '|' => '}' */ - { 0x7d, 0x7b }, /* '}' => '{' */ - { 0x7e, 0x22 }, /* '~' => '"' */ +/** "pt" basic remapping */ +static struct keymap_key pt_basic[] = { + { 0x1c, 0x7e }, /* 0x1c => '~' */ + { 0x1e, 0x36 }, /* 0x1e => '6' */ + { 0x26, 0x2f }, /* '&' => '/' */ + { 0x28, 0x29 }, /* '(' => ')' */ + { 0x29, 0x3d }, /* ')' => '=' */ + { 0x2a, 0x28 }, /* '*' => '(' */ + { 0x2d, 0x27 }, /* '-' => '\'' */ + { 0x2f, 0x2d }, /* '/' => '-' */ + { 0x3c, 0x3b }, /* '<' => ';' */ + { 0x3e, 0x3a }, /* '>' => ':' */ + { 0x3f, 0x5f }, /* '?' => '_' */ + { 0x40, 0x22 }, /* '@' => '"' */ + { 0x5b, 0x2b }, /* '[' => '+' */ + { 0x5c, 0x7e }, /* '\\' => '~' */ + { 0x5e, 0x26 }, /* '^' => '&' */ + { 0x5f, 0x3f }, /* '_' => '?' */ + { 0x60, 0x5c }, /* '`' => '\\' */ + { 0x7b, 0x2a }, /* '{' => '*' */ + { 0x7c, 0x5e }, /* '|' => '^' */ + { 0x7d, 0x60 }, /* '}' => '`' */ + { 0x7e, 0x7c }, /* '~' => '|' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "pt" AltGr remapping */ +static struct keymap_key pt_altgr[] = { + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x51, 0x40 }, /* 'Q' => '@' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0, 0 } +}; + +/** "pt" keyboard map */ +struct keymap pt_keymap __keymap = { + .name = "pt", + .basic = pt_basic, + .altgr = pt_altgr, }; diff --git a/src/hci/keymap/keymap_ro.c b/src/hci/keymap/keymap_ro.c index 0eef7d53..62045000 100644 --- a/src/hci/keymap/keymap_ro.c +++ b/src/hci/keymap/keymap_ro.c @@ -10,6 +10,19 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "ro" keyboard mapping */ -struct key_mapping ro_mapping[] __keymap = { +/** "ro" basic remapping */ +static struct keymap_key ro_basic[] = { + { 0, 0 } +}; + +/** "ro" AltGr remapping */ +static struct keymap_key ro_altgr[] = { + { 0, 0 } +}; + +/** "ro" keyboard map */ +struct keymap ro_keymap __keymap = { + .name = "ro", + .basic = ro_basic, + .altgr = ro_altgr, }; diff --git a/src/hci/keymap/keymap_ru.c b/src/hci/keymap/keymap_ru.c index 422b6c69..2aafcf9b 100644 --- a/src/hci/keymap/keymap_ru.c +++ b/src/hci/keymap/keymap_ru.c @@ -10,6 +10,22 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "ru" keyboard mapping */ -struct key_mapping ru_mapping[] __keymap = { +/** "ru" basic remapping */ +static struct keymap_key ru_basic[] = { + { 0x0d, 0x0a }, /* Ctrl-M => Ctrl-J */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "ru" AltGr remapping */ +static struct keymap_key ru_altgr[] = { + { 0, 0 } +}; + +/** "ru" keyboard map */ +struct keymap ru_keymap __keymap = { + .name = "ru", + .basic = ru_basic, + .altgr = ru_altgr, }; diff --git a/src/hci/keymap/keymap_se.c b/src/hci/keymap/keymap_se.c new file mode 100644 index 00000000..2bac9698 --- /dev/null +++ b/src/hci/keymap/keymap_se.c @@ -0,0 +1,64 @@ +/** @file + * + * "se" keyboard mapping + * + * This file is automatically generated; do not edit + * + */ + +FILE_LICENCE ( PUBLIC_DOMAIN ); + +#include <ipxe/keymap.h> + +/** "se" basic remapping */ +static struct keymap_key se_basic[] = { + { 0x1c, 0x27 }, /* 0x1c => '\'' */ + { 0x1e, 0x36 }, /* 0x1e => '6' */ + { 0x26, 0x2f }, /* '&' => '/' */ + { 0x28, 0x29 }, /* '(' => ')' */ + { 0x29, 0x3d }, /* ')' => '=' */ + { 0x2a, 0x28 }, /* '*' => '(' */ + { 0x2b, 0x60 }, /* '+' => '`' */ + { 0x2d, 0x2b }, /* '-' => '+' */ + { 0x2f, 0x2d }, /* '/' => '-' */ + { 0x3c, 0x3b }, /* '<' => ';' */ + { 0x3e, 0x3a }, /* '>' => ':' */ + { 0x3f, 0x5f }, /* '?' => '_' */ + { 0x40, 0x22 }, /* '@' => '"' */ + { 0x5c, 0x27 }, /* '\\' => '\'' */ + { 0x5e, 0x26 }, /* '^' => '&' */ + { 0x5f, 0x3f }, /* '_' => '?' */ + { 0x7c, 0x2a }, /* '|' => '*' */ + { 0x7d, 0x5e }, /* '}' => '^' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "se" AltGr remapping */ +static struct keymap_key se_altgr[] = { + { 0x26, 0x7b }, /* '&' => '{' */ + { 0x28, 0x5d }, /* '(' => ']' */ + { 0x29, 0x7d }, /* ')' => '}' */ + { 0x2a, 0x5b }, /* '*' => '[' */ + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x34, 0x24 }, /* '4' => '$' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x51, 0x40 }, /* 'Q' => '@' */ + { 0x5d, 0x7e }, /* ']' => '~' */ + { 0x5f, 0x5c }, /* '_' => '\\' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + +/** "se" keyboard map */ +struct keymap se_keymap __keymap = { + .name = "se", + .basic = se_basic, + .altgr = se_altgr, +}; diff --git a/src/hci/keymap/keymap_sg.c b/src/hci/keymap/keymap_sg.c index 0b082092..c4200099 100644 --- a/src/hci/keymap/keymap_sg.c +++ b/src/hci/keymap/keymap_sg.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "sg" keyboard mapping */ -struct key_mapping sg_mapping[] __keymap = { +/** "sg" basic remapping */ +static struct keymap_key sg_basic[] = { { 0x19, 0x1a }, /* Ctrl-Y => Ctrl-Z */ { 0x1a, 0x19 }, /* Ctrl-Z => Ctrl-Y */ { 0x21, 0x2b }, /* '!' => '+' */ @@ -38,4 +38,32 @@ struct key_mapping sg_mapping[] __keymap = { { 0x7a, 0x79 }, /* 'z' => 'y' */ { 0x7c, 0x24 }, /* '|' => '$' */ { 0x7d, 0x21 }, /* '}' => '!' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "sg" AltGr remapping */ +static struct keymap_key sg_altgr[] = { + { 0x22, 0x7b }, /* '"' => '{' */ + { 0x26, 0x7c }, /* '&' => '|' */ + { 0x27, 0x7b }, /* '\'' => '{' */ + { 0x2b, 0x7e }, /* '+' => '~' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x37, 0x7c }, /* '7' => '|' */ + { 0x3d, 0x7e }, /* '=' => '~' */ + { 0x5c, 0x7d }, /* '\\' => '}' */ + { 0x7b, 0x5b }, /* '{' => '[' */ + { 0x7c, 0x7d }, /* '|' => '}' */ + { 0x7d, 0x5d }, /* '}' => ']' */ + { 0xfc, 0x5c }, /* Pseudo-'|' => '\\' */ + { 0, 0 } +}; + +/** "sg" keyboard map */ +struct keymap sg_keymap __keymap = { + .name = "sg", + .basic = sg_basic, + .altgr = sg_altgr, }; diff --git a/src/hci/keymap/keymap_sr-latin.c b/src/hci/keymap/keymap_sr-latin.c new file mode 100644 index 00000000..7e55714a --- /dev/null +++ b/src/hci/keymap/keymap_sr-latin.c @@ -0,0 +1,30 @@ +/** @file + * + * "sr-latin" keyboard mapping + * + * This file is automatically generated; do not edit + * + */ + +FILE_LICENCE ( PUBLIC_DOMAIN ); + +#include <ipxe/keymap.h> + +/** "sr-latin" basic remapping */ +static struct keymap_key sr_latin_basic[] = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "sr-latin" AltGr remapping */ +static struct keymap_key sr_latin_altgr[] = { + { 0, 0 } +}; + +/** "sr-latin" keyboard map */ +struct keymap sr_latin_keymap __keymap = { + .name = "sr-latin", + .basic = sr_latin_basic, + .altgr = sr_latin_altgr, +}; diff --git a/src/hci/keymap/keymap_sr.c b/src/hci/keymap/keymap_sr.c deleted file mode 100644 index 0552f4d9..00000000 --- a/src/hci/keymap/keymap_sr.c +++ /dev/null @@ -1,35 +0,0 @@ -/** @file - * - * "sr" keyboard mapping - * - * This file is automatically generated; do not edit - * - */ - -FILE_LICENCE ( PUBLIC_DOMAIN ); - -#include <ipxe/keymap.h> - -/** "sr" keyboard mapping */ -struct key_mapping sr_mapping[] __keymap = { - { 0x19, 0x1a }, /* Ctrl-Y => Ctrl-Z */ - { 0x1a, 0x19 }, /* Ctrl-Z => Ctrl-Y */ - { 0x26, 0x2f }, /* '&' => '/' */ - { 0x28, 0x29 }, /* '(' => ')' */ - { 0x29, 0x3d }, /* ')' => '=' */ - { 0x2a, 0x28 }, /* '*' => '(' */ - { 0x2b, 0x2a }, /* '+' => '*' */ - { 0x2d, 0x27 }, /* '-' => '\'' */ - { 0x2f, 0x2d }, /* '/' => '-' */ - { 0x3c, 0x3b }, /* '<' => ';' */ - { 0x3d, 0x2b }, /* '=' => '+' */ - { 0x3e, 0x3a }, /* '>' => ':' */ - { 0x3f, 0x5f }, /* '?' => '_' */ - { 0x40, 0x22 }, /* '@' => '"' */ - { 0x59, 0x5a }, /* 'Y' => 'Z' */ - { 0x5a, 0x59 }, /* 'Z' => 'Y' */ - { 0x5e, 0x26 }, /* '^' => '&' */ - { 0x5f, 0x3f }, /* '_' => '?' */ - { 0x79, 0x7a }, /* 'y' => 'z' */ - { 0x7a, 0x79 }, /* 'z' => 'y' */ -}; diff --git a/src/hci/keymap/keymap_th.c b/src/hci/keymap/keymap_th.c deleted file mode 100644 index e8b44d1e..00000000 --- a/src/hci/keymap/keymap_th.c +++ /dev/null @@ -1,15 +0,0 @@ -/** @file - * - * "th" keyboard mapping - * - * This file is automatically generated; do not edit - * - */ - -FILE_LICENCE ( PUBLIC_DOMAIN ); - -#include <ipxe/keymap.h> - -/** "th" keyboard mapping */ -struct key_mapping th_mapping[] __keymap = { -}; diff --git a/src/hci/keymap/keymap_ua.c b/src/hci/keymap/keymap_ua.c index 1106a8b2..44e82cb2 100644 --- a/src/hci/keymap/keymap_ua.c +++ b/src/hci/keymap/keymap_ua.c @@ -10,6 +10,21 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "ua" keyboard mapping */ -struct key_mapping ua_mapping[] __keymap = { +/** "ua" basic remapping */ +static struct keymap_key ua_basic[] = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "ua" AltGr remapping */ +static struct keymap_key ua_altgr[] = { + { 0, 0 } +}; + +/** "ua" keyboard map */ +struct keymap ua_keymap __keymap = { + .name = "ua", + .basic = ua_basic, + .altgr = ua_altgr, }; diff --git a/src/hci/keymap/keymap_uk.c b/src/hci/keymap/keymap_uk.c index 6550d8ee..28cf7aac 100644 --- a/src/hci/keymap/keymap_uk.c +++ b/src/hci/keymap/keymap_uk.c @@ -10,10 +10,23 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "uk" keyboard mapping */ -struct key_mapping uk_mapping[] __keymap = { +/** "uk" basic remapping */ +static struct keymap_key uk_basic[] = { { 0x22, 0x40 }, /* '"' => '@' */ { 0x40, 0x22 }, /* '@' => '"' */ { 0x5c, 0x23 }, /* '\\' => '#' */ { 0x7c, 0x7e }, /* '|' => '~' */ + { 0, 0 } +}; + +/** "uk" AltGr remapping */ +static struct keymap_key uk_altgr[] = { + { 0, 0 } +}; + +/** "uk" keyboard map */ +struct keymap uk_keymap __keymap = { + .name = "uk", + .basic = uk_basic, + .altgr = uk_altgr, }; diff --git a/src/hci/keymap/keymap_us.c b/src/hci/keymap/keymap_us.c index 73d01a30..b8e604a4 100644 --- a/src/hci/keymap/keymap_us.c +++ b/src/hci/keymap/keymap_us.c @@ -10,6 +10,19 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include <ipxe/keymap.h> -/** "us" keyboard mapping */ -struct key_mapping us_mapping[] __keymap = { +/** "us" basic remapping */ +static struct keymap_key us_basic[] = { + { 0, 0 } +}; + +/** "us" AltGr remapping */ +static struct keymap_key us_altgr[] = { + { 0, 0 } +}; + +/** "us" keyboard map */ +struct keymap us_keymap __keymap_default = { + .name = "us", + .basic = us_basic, + .altgr = us_altgr, }; diff --git a/src/hci/keymap/keymap_wo.c b/src/hci/keymap/keymap_wo.c deleted file mode 100644 index b4535761..00000000 --- a/src/hci/keymap/keymap_wo.c +++ /dev/null @@ -1,55 +0,0 @@ -/** @file - * - * "wo" keyboard mapping - * - * This file is automatically generated; do not edit - * - */ - -FILE_LICENCE ( PUBLIC_DOMAIN ); - -#include <ipxe/keymap.h> - -/** "wo" keyboard mapping */ -struct key_mapping wo_mapping[] __keymap = { - { 0x01, 0x11 }, /* Ctrl-A => Ctrl-Q */ - { 0x11, 0x01 }, /* Ctrl-Q => Ctrl-A */ - { 0x17, 0x1a }, /* Ctrl-W => Ctrl-Z */ - { 0x1a, 0x17 }, /* Ctrl-Z => Ctrl-W */ - { 0x21, 0x31 }, /* '!' => '1' */ - { 0x23, 0x33 }, /* '#' => '3' */ - { 0x24, 0x34 }, /* '$' => '4' */ - { 0x25, 0x35 }, /* '%' => '5' */ - { 0x26, 0x37 }, /* '&' => '7' */ - { 0x28, 0x39 }, /* '(' => '9' */ - { 0x29, 0x30 }, /* ')' => '0' */ - { 0x2a, 0x38 }, /* '*' => '8' */ - { 0x2c, 0x3b }, /* ',' => ';' */ - { 0x2d, 0x29 }, /* '-' => ')' */ - { 0x2e, 0x3a }, /* '.' => ':' */ - { 0x2f, 0x21 }, /* '/' => '!' */ - { 0x31, 0x26 }, /* '1' => '&' */ - { 0x33, 0x22 }, /* '3' => '"' */ - { 0x34, 0x27 }, /* '4' => '\'' */ - { 0x35, 0x28 }, /* '5' => '(' */ - { 0x36, 0x2d }, /* '6' => '-' */ - { 0x38, 0x5f }, /* '8' => '_' */ - { 0x3a, 0x4d }, /* ':' => 'M' */ - { 0x3b, 0x6d }, /* ';' => 'm' */ - { 0x3c, 0x2e }, /* '<' => '.' */ - { 0x3e, 0x2f }, /* '>' => '/' */ - { 0x40, 0x32 }, /* '@' => '2' */ - { 0x41, 0x51 }, /* 'A' => 'Q' */ - { 0x4d, 0x3f }, /* 'M' => '?' */ - { 0x51, 0x41 }, /* 'Q' => 'A' */ - { 0x57, 0x5a }, /* 'W' => 'Z' */ - { 0x5a, 0x57 }, /* 'Z' => 'W' */ - { 0x5d, 0x24 }, /* ']' => '$' */ - { 0x5e, 0x36 }, /* '^' => '6' */ - { 0x61, 0x71 }, /* 'a' => 'q' */ - { 0x6d, 0x2c }, /* 'm' => ',' */ - { 0x71, 0x61 }, /* 'q' => 'a' */ - { 0x77, 0x7a }, /* 'w' => 'z' */ - { 0x7a, 0x77 }, /* 'z' => 'w' */ - { 0x7e, 0x25 }, /* '~' => '%' */ -}; diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index 7df3ec21..c3468123 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -386,7 +386,10 @@ acpi_describe ( struct interface *interface ); #define acpi_describe_TYPE( object_type ) \ typeof ( struct acpi_descriptor * ( object_type ) ) +extern userptr_t ( * acpi_finder ) ( uint32_t signature, unsigned int index ); + extern void acpi_fix_checksum ( struct acpi_header *acpi ); +extern userptr_t acpi_table ( uint32_t signature, unsigned int index ); extern int acpi_extract ( uint32_t signature, void *data, int ( * extract ) ( userptr_t zsdt, size_t len, size_t offset, void *data ) ); diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index a83fa0f2..1dd0d445 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -223,6 +223,7 @@ extern EFI_HANDLE efi_image_handle; extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image; extern EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path; extern EFI_SYSTEM_TABLE *efi_systab; +extern EFI_TPL efi_internal_tpl; extern EFI_TPL efi_external_tpl; extern int efi_shutdown_in_progress; diff --git a/src/include/ipxe/efi/efi_wrap.h b/src/include/ipxe/efi/efi_wrap.h index 6c7ccf2e..2747a9e3 100644 --- a/src/include/ipxe/efi/efi_wrap.h +++ b/src/include/ipxe/efi/efi_wrap.h @@ -10,7 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/efi/efi.h> -extern EFI_SYSTEM_TABLE * efi_wrap_systab ( void ); +extern EFI_BOOT_SERVICES * efi_wrap_bs ( void ); extern void efi_wrap ( EFI_HANDLE handle ); #endif /* _IPXE_EFI_WRAP_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 23e406b6..81f55572 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -395,6 +395,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_efi_cachedhcp ( ERRFILE_OTHER | 0x00550000 ) #define ERRFILE_linux_sysfs ( ERRFILE_OTHER | 0x00560000 ) #define ERRFILE_linux_acpi ( ERRFILE_OTHER | 0x00570000 ) +#define ERRFILE_dynkeymap ( ERRFILE_OTHER | 0x00580000 ) /** @} */ diff --git a/src/include/ipxe/fbcon.h b/src/include/ipxe/fbcon.h index 42ffca3d..a4c7a9ab 100644 --- a/src/include/ipxe/fbcon.h +++ b/src/include/ipxe/fbcon.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> #include <ipxe/ansiesc.h> +#include <ipxe/utf8.h> #include <ipxe/uaccess.h> #include <ipxe/console.h> @@ -36,7 +37,7 @@ struct fbcon_font { /** * Get character glyph * - * @v character Character + * @v character Unicode character * @v glyph Character glyph to fill in */ void ( * glyph ) ( unsigned int character, uint8_t *glyph ); @@ -92,7 +93,7 @@ struct fbcon_text_cell { uint32_t foreground; /** Background colour */ uint32_t background; - /** Character */ + /** Unicode character */ unsigned int character; }; @@ -138,6 +139,8 @@ struct fbcon { unsigned int ypos; /** ANSI escape sequence context */ struct ansiesc_context ctx; + /** UTF-8 accumulator */ + struct utf8_accumulator utf8; /** Text array */ struct fbcon_text text; /** Background picture */ diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index 0f1b0c65..8bfbe07a 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -13,18 +13,67 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> #include <ipxe/tables.h> -/** A keyboard mapping */ -struct key_mapping { +/** A remapped key + * + * Represents a mapping from an ASCII character (as interpreted from a + * keyboard scancode by the US-only keyboard driver provided by the + * BIOS) to the appropriate ASCII value for the keyboard layout. + */ +struct keymap_key { /** Character read from keyboard */ uint8_t from; /** Character to be used instead */ uint8_t to; } __attribute__ (( packed )); +/** A keyboard mapping */ +struct keymap { + /** Name */ + const char *name; + /** Basic remapping table (zero-terminated) */ + struct keymap_key *basic; + /** AltGr remapping table (zero-terminated) */ + struct keymap_key *altgr; +}; + /** Keyboard mapping table */ -#define KEYMAP __table ( struct key_mapping, "keymap" ) +#define KEYMAP __table ( struct keymap, "keymap" ) + +/** Define a default keyboard mapping */ +#define __keymap_default __table_entry ( KEYMAP, 01 ) /** Define a keyboard mapping */ -#define __keymap __table_entry ( KEYMAP, 01 ) +#define __keymap __table_entry ( KEYMAP, 02 ) + +/** Mappable character mask */ +#define KEYMAP_MASK 0xff + +/** Pseudo key flag */ +#define KEYMAP_PSEUDO 0x80 + +/** Ctrl key flag */ +#define KEYMAP_CTRL 0x0100 + +/** CapsLock key flag */ +#define KEYMAP_CAPSLOCK 0x0200 + +/** Undo CapsLock key flag + * + * Used when the keyboard driver has already interpreted the CapsLock + * key, in which case the effect needs to be undone before remapping + * in order to correctly handle keyboard mappings that swap alphabetic + * and non-alphabetic keys. + */ +#define KEYMAP_CAPSLOCK_UNDO 0x0400 + +/** Undo and redo CapsLock key flags */ +#define KEYMAP_CAPSLOCK_REDO ( KEYMAP_CAPSLOCK | KEYMAP_CAPSLOCK_UNDO ) + +/** AltGr key flag */ +#define KEYMAP_ALTGR 0x0800 + +extern unsigned int key_remap ( unsigned int character ); +extern struct keymap * keymap_find ( const char *name ); +extern void keymap_set ( struct keymap *keymap ); #endif /* _IPXE_KEYMAP_H */ diff --git a/src/include/ipxe/linux/linux_uaccess.h b/src/include/ipxe/linux/linux_uaccess.h index acd919a8..a642b616 100644 --- a/src/include/ipxe/linux/linux_uaccess.h +++ b/src/include/ipxe/linux/linux_uaccess.h @@ -25,7 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #endif /** - * Convert user buffer to physical address + * Convert user pointer to physical address * * @v userptr User pointer * @v offset Offset from user pointer @@ -46,6 +46,19 @@ UACCESS_INLINE ( linux, user_to_phys ) ( userptr_t userptr, off_t offset ) { return ( userptr + offset ); } +/** + * Convert physical address to user pointer + * + * @v phys_addr Physical address + * @ret userptr User pointer + */ +static inline __always_inline userptr_t +UACCESS_INLINE ( linux, phys_to_user ) ( physaddr_t phys_addr ) { + + /* For symmetry with the stub user_to_phys() */ + return phys_addr; +} + static inline __always_inline userptr_t UACCESS_INLINE ( linux, virt_to_user ) ( volatile const void *addr ) { return trivial_virt_to_user ( addr ); diff --git a/src/include/ipxe/sbat.h b/src/include/ipxe/sbat.h new file mode 100644 index 00000000..4b74670e --- /dev/null +++ b/src/include/ipxe/sbat.h @@ -0,0 +1,68 @@ +#ifndef _IPXE_SBAT_H +#define _IPXE_SBAT_H + +/** @file + * + * Secure Boot Advanced Targeting (SBAT) + * + * SBAT defines an encoding for security generation numbers stored as + * a CSV file within a special ".sbat" section in the signed binary. + * If a Secure Boot exploit is discovered then the generation number + * will be incremented alongside the corresponding fix. + * + * Platforms may then record the minimum generation number required + * for any given product. This allows for an efficient revocation + * mechanism that consumes minimal flash storage space (in contrast to + * the DBX mechanism, which allows for only a single-digit number of + * revocation events to ever take place across all possible signed + * binaries). + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * A single line within an SBAT CSV file + * + * @v name Machine-readable component name + * @v generation Security generation number + * @v vendor Human-readable vendor name + * @v package Human-readable package name + * @v version Human-readable package version + * @v uri Contact URI + * @ret line CSV line + */ +#define SBAT_LINE( name, generation, vendor, package, version, uri ) \ + name "," _S2 ( generation ) "," vendor "," package "," \ + version "," uri "\n" + +/** SBAT format generation */ +#define SBAT_GENERATION 1 + +/** Upstream security generation + * + * This represents the security generation of the upstream codebase. + * It will be incremented whenever a Secure Boot exploit is fixed in + * the upstream codebase. + * + * If you do not have commit access to the upstream iPXE repository, + * then you may not modify this value under any circumstances. + */ +#define IPXE_SBAT_GENERATION 1 + +/* Seriously, do not modify this value */ +#if IPXE_SBAT_GENERATION != 1 +#error "You may not modify IPXE_SBAT_GENERATION" +#endif + +/** SBAT header line */ +#define SBAT_HEADER \ + SBAT_LINE ( "sbat", SBAT_GENERATION, "SBAT Version", "sbat", \ + _S2 ( SBAT_GENERATION ), \ + "https://github.com/rhboot/shim/blob/main/SBAT.md" ) + +/** Mark variable as being in the ".sbat" section */ +#define __sbat __attribute__ (( section ( ".sbat" ), aligned ( 512 ) )) + +extern const char sbat[] __sbat; + +#endif /* _IPXE_SBAT_H */ diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 2bffe2fb..9759a600 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -427,6 +427,7 @@ extern const struct setting_type setting_type_hexraw __setting_type; extern const struct setting_type setting_type_md5 __setting_type; extern const struct setting_type setting_type_base64 __setting_type; extern const struct setting_type setting_type_uuid __setting_type; +extern const struct setting_type setting_type_guid __setting_type; extern const struct setting_type setting_type_busdevfn __setting_type; extern const struct setting_type setting_type_dnssl __setting_type; diff --git a/src/include/ipxe/srp.h b/src/include/ipxe/srp.h index 3abb0995..1f66a22b 100644 --- a/src/include/ipxe/srp.h +++ b/src/include/ipxe/srp.h @@ -774,7 +774,7 @@ struct srp_aer_rsp { * The working draft specification for the SRP boot firmware table can * be found at * - * http://ipxe.org/wiki/srp/sbft + * https://ipxe.org/wiki/srp/sbft * ***************************************************************************** */ diff --git a/src/include/ipxe/tables.h b/src/include/ipxe/tables.h index 28a87da9..de5b1f29 100644 --- a/src/include/ipxe/tables.h +++ b/src/include/ipxe/tables.h @@ -253,6 +253,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); __table_entries; } ) /** + * Declare start of linker table entries + * + * @v entries Start of entries + * @v table Linker table + * @v idx Sub-table index + */ +#define __TABLE_ENTRIES( entries, table, idx ) \ + __table_type ( table ) entries[0] \ + __table_entry ( table, idx ) + +/** * Get start of linker table * * @v table Linker table @@ -271,6 +282,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define table_start( table ) __table_entries ( table, 00 ) /** + * Declare start of linker table + * + * @v start Start of linker table + * @v table Linker table + */ +#define TABLE_START( start, table ) __TABLE_ENTRIES ( start, table, 00 ) + +/** * Get end of linker table * * @v table Linker table @@ -289,6 +308,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define table_end( table ) __table_entries ( table, 99 ) /** + * Declare end of linker table + * + * @v end End of linker table + * @v table Linker table + */ +#define TABLE_END( end, table ) __TABLE_ENTRIES ( end, table, 99 ) + +/** * Get number of entries in linker table * * @v table Linker table diff --git a/src/include/ipxe/uri.h b/src/include/ipxe/uri.h index 3879a0e7..e5b7c861 100644 --- a/src/include/ipxe/uri.h +++ b/src/include/ipxe/uri.h @@ -46,6 +46,20 @@ struct parameters; * scheme = "ftp", user = "joe", password = "secret", * host = "insecure.org", port = "8081", path = "/hidden/path/to", * query = "what=is", fragment = "this" + * + * The URI syntax includes a percent-encoding mechanism that can be + * used to represent characters that would otherwise not be possible, + * such as a '/' character within the password field. These encodings + * are decoded during the URI parsing stage, thereby allowing protocol + * implementations to consume the raw field values directly without + * further decoding. + * + * Some protocols (such as HTTP) communicate using URI-encoded values. + * For these protocols, the original encoded substring must be + * retained verbatim since the choice of whether or not to encode a + * particular character may have significance to the receiving + * application. We therefore retain the originally-encoded substrings + * for the path, query, and fragment fields. */ struct uri { /** Reference count */ @@ -62,12 +76,14 @@ struct uri { const char *host; /** Port number */ const char *port; - /** Path */ + /** Path (after URI decoding) */ const char *path; - /** Query */ - const char *query; - /** Fragment */ - const char *fragment; + /** Path (with original URI encoding) */ + const char *epath; + /** Query (with original URI encoding) */ + const char *equery; + /** Fragment (with original URI encoding) */ + const char *efragment; /** Form parameters */ struct parameters *params; } __attribute__ (( packed )); @@ -100,8 +116,9 @@ enum uri_fields { URI_HOST = URI_FIELD ( host ), URI_PORT = URI_FIELD ( port ), URI_PATH = URI_FIELD ( path ), - URI_QUERY = URI_FIELD ( query ), - URI_FRAGMENT = URI_FIELD ( fragment ), + URI_EPATH = URI_FIELD ( epath ), + URI_EQUERY = URI_FIELD ( equery ), + URI_EFRAGMENT = URI_FIELD ( efragment ), URI_FIELDS }; diff --git a/src/include/ipxe/utf8.h b/src/include/ipxe/utf8.h new file mode 100644 index 00000000..299c2551 --- /dev/null +++ b/src/include/ipxe/utf8.h @@ -0,0 +1,69 @@ +#ifndef _IPXE_UTF8_H +#define _IPXE_UTF8_H + +/** @file + * + * UTF-8 Unicode encoding + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> + +/** Maximum length of UTF-8 sequence */ +#define UTF8_MAX_LEN 4 + +/** Minimum legal value for two-byte UTF-8 sequence */ +#define UTF8_MIN_TWO 0x80 + +/** Minimum legal value for three-byte UTF-8 sequence */ +#define UTF8_MIN_THREE 0x800 + +/** Minimum legal value for four-byte UTF-8 sequence */ +#define UTF8_MIN_FOUR 0x10000 + +/** High bit of UTF-8 bytes */ +#define UTF8_HIGH_BIT 0x80 + +/** Number of data bits in each continuation byte */ +#define UTF8_CONTINUATION_BITS 6 + +/** Bit mask for data bits in a continuation byte */ +#define UTF8_CONTINUATION_MASK ( ( 1 << UTF8_CONTINUATION_BITS ) - 1 ) + +/** Non-data bits in a continuation byte */ +#define UTF8_CONTINUATION 0x80 + +/** Check for a continuation byte + * + * @v byte UTF-8 byte + * @ret is_continuation Byte is a continuation byte + */ +#define UTF8_IS_CONTINUATION( byte ) \ + ( ( (byte) & ~UTF8_CONTINUATION_MASK ) == UTF8_CONTINUATION ) + +/** Check for an ASCII byte + * + * @v byte UTF-8 byte + * @ret is_ascii Byte is an ASCII byte + */ +#define UTF8_IS_ASCII( byte ) ( ! ( (byte) & UTF8_HIGH_BIT ) ) + +/** Invalid character returned when decoding fails */ +#define UTF8_INVALID 0xfffd + +/** A UTF-8 character accumulator */ +struct utf8_accumulator { + /** Character in progress */ + unsigned int character; + /** Number of remaining continuation bytes */ + unsigned int remaining; + /** Minimum legal character */ + unsigned int min; +}; + +extern unsigned int utf8_accumulate ( struct utf8_accumulator *utf8, + uint8_t byte ); + +#endif /* _IPXE_UTF8_H */ diff --git a/src/include/ipxe/virtio-pci.h b/src/include/ipxe/virtio-pci.h index f3074f14..7abae26f 100644 --- a/src/include/ipxe/virtio-pci.h +++ b/src/include/ipxe/virtio-pci.h @@ -1,6 +1,8 @@ #ifndef _VIRTIO_PCI_H_ # define _VIRTIO_PCI_H_ +#include <ipxe/dma.h> + /* A 32-bit r/o bitmask of the features supported by the host */ #define VIRTIO_PCI_HOST_FEATURES 0 @@ -198,7 +200,8 @@ struct vring_virtqueue; void vp_free_vq(struct vring_virtqueue *vq); int vp_find_vq(unsigned int ioaddr, int queue_index, - struct vring_virtqueue *vq); + struct vring_virtqueue *vq, struct dma_device *dma_dev, + size_t header_size); /* Virtio 1.0 I/O routines abstract away the three possible HW access @@ -298,7 +301,8 @@ void vpm_notify(struct virtio_pci_modern_device *vdev, struct vring_virtqueue *vq); int vpm_find_vqs(struct virtio_pci_modern_device *vdev, - unsigned nvqs, struct vring_virtqueue *vqs); + unsigned nvqs, struct vring_virtqueue *vqs, + struct dma_device *dma_dev, size_t header_size); int virtio_pci_find_capability(struct pci_device *pci, uint8_t cfg_type); diff --git a/src/include/ipxe/virtio-ring.h b/src/include/ipxe/virtio-ring.h index 852769f2..d082139e 100644 --- a/src/include/ipxe/virtio-ring.h +++ b/src/include/ipxe/virtio-ring.h @@ -2,6 +2,7 @@ # define _VIRTIO_RING_H_ #include <ipxe/virtio-pci.h> +#include <ipxe/dma.h> /* Status byte for guest to report progress, and synchronize features. */ /* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ @@ -74,17 +75,21 @@ struct vring { struct vring_virtqueue { unsigned char *queue; + size_t queue_size; + struct dma_mapping map; + struct dma_device *dma; struct vring vring; u16 free_head; u16 last_used_idx; void **vdata; + struct virtio_net_hdr_modern *empty_header; /* PCI */ int queue_index; struct virtio_pci_region notification; }; struct vring_list { - char *addr; + physaddr_t addr; unsigned int length; }; diff --git a/src/interface/efi/efi_autoexec.c b/src/interface/efi/efi_autoexec.c index 88eb379b..79d4a4ca 100644 --- a/src/interface/efi/efi_autoexec.c +++ b/src/interface/efi/efi_autoexec.c @@ -24,11 +24,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <string.h> +#include <stdlib.h> #include <errno.h> #include <ipxe/image.h> #include <ipxe/init.h> +#include <ipxe/in.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/efi_autoexec.h> +#include <ipxe/efi/Protocol/PxeBaseCode.h> #include <ipxe/efi/Protocol/SimpleFileSystem.h> #include <ipxe/efi/Guid/FileInfo.h> @@ -39,10 +42,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ /** Autoexec script filename */ -#define AUTOEXEC_FILENAME L"autoexec.ipxe" +static wchar_t efi_autoexec_wname[] = L"autoexec.ipxe"; /** Autoexec script image name */ -#define AUTOEXEC_NAME "autoexec.ipxe" +static char efi_autoexec_name[] = "autoexec.ipxe"; /** Autoexec script (if any) */ static void *efi_autoexec; @@ -51,21 +54,21 @@ static void *efi_autoexec; static size_t efi_autoexec_len; /** - * Load autoexec script + * Load autoexec script from filesystem * * @v device Device handle * @ret rc Return status code */ -int efi_autoexec_load ( EFI_HANDLE device ) { +static int efi_autoexec_filesystem ( EFI_HANDLE device ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - static wchar_t name[] = AUTOEXEC_FILENAME; union { void *interface; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; } u; struct { EFI_FILE_INFO info; - CHAR16 name[ sizeof ( name ) / sizeof ( name[0] ) ]; + CHAR16 name[ sizeof ( efi_autoexec_wname ) / + sizeof ( efi_autoexec_wname[0] ) ]; } info; EFI_FILE_PROTOCOL *root; EFI_FILE_PROTOCOL *file; @@ -74,10 +77,6 @@ int efi_autoexec_load ( EFI_HANDLE device ) { EFI_STATUS efirc; int rc; - /* Sanity check */ - assert ( efi_autoexec == NULL ); - assert ( efi_autoexec_len == 0 ); - /* Open simple file system protocol */ if ( ( efirc = bs->OpenProtocol ( device, &efi_simple_file_system_protocol_guid, @@ -99,11 +98,12 @@ int efi_autoexec_load ( EFI_HANDLE device ) { } /* Open autoexec script */ - if ( ( efirc = root->Open ( root, &file, name, + if ( ( efirc = root->Open ( root, &file, efi_autoexec_wname, EFI_FILE_MODE_READ, 0 ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s has no %ls: %s\n", - efi_handle_name ( device ), name, strerror ( rc ) ); + efi_handle_name ( device ), efi_autoexec_wname, + strerror ( rc ) ); goto err_open; } @@ -113,7 +113,8 @@ int efi_autoexec_load ( EFI_HANDLE device ) { &info ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s could not get %ls info: %s\n", - efi_handle_name ( device ), name, strerror ( rc ) ); + efi_handle_name ( device ), efi_autoexec_wname, + strerror ( rc ) ); goto err_getinfo; } size = info.info.FileSize; @@ -122,7 +123,7 @@ int efi_autoexec_load ( EFI_HANDLE device ) { if ( ! size ) { rc = -EINVAL; DBGC ( device, "EFI %s has zero-length %ls\n", - efi_handle_name ( device ), name ); + efi_handle_name ( device ), efi_autoexec_wname ); goto err_empty; } @@ -131,7 +132,8 @@ int efi_autoexec_load ( EFI_HANDLE device ) { &data ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s could not allocate %ls: %s\n", - efi_handle_name ( device ), name, strerror ( rc ) ); + efi_handle_name ( device ), efi_autoexec_wname, + strerror ( rc ) ); goto err_alloc; } @@ -139,7 +141,8 @@ int efi_autoexec_load ( EFI_HANDLE device ) { if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( device, "EFI %s could not read %ls: %s\n", - efi_handle_name ( device ), name, strerror ( rc ) ); + efi_handle_name ( device ), efi_autoexec_wname, + strerror ( rc ) ); goto err_read; } @@ -148,7 +151,7 @@ int efi_autoexec_load ( EFI_HANDLE device ) { efi_autoexec_len = size; data = NULL; DBGC ( device, "EFI %s found %ls\n", - efi_handle_name ( device ), name ); + efi_handle_name ( device ), efi_autoexec_wname ); /* Success */ rc = 0; @@ -170,13 +173,205 @@ int efi_autoexec_load ( EFI_HANDLE device ) { } /** + * Load autoexec script from TFTP server + * + * @v device Device handle + * @ret rc Return status code + */ +static int efi_autoexec_tftp ( EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + void *interface; + EFI_PXE_BASE_CODE_PROTOCOL *pxe; + } u; + EFI_PXE_BASE_CODE_MODE *mode; + EFI_PXE_BASE_CODE_PACKET *packet; + union { + struct in_addr in; + EFI_IP_ADDRESS ip; + } server; + size_t filename_max; + char *filename; + char *sep; + UINT64 size; + VOID *data; + EFI_STATUS efirc; + int rc; + + /* Open PXE base code protocol */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_pxe_base_code_protocol_guid, + &u.interface, efi_image_handle, + device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s has no PXE base code instance: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_pxe; + } + + /* Do not attempt to parse DHCPv6 packets */ + mode = u.pxe->Mode; + if ( mode->UsingIpv6 ) { + rc = -ENOTSUP; + DBGC ( device, "EFI %s has IPv6 PXE base code\n", + efi_handle_name ( device ) ); + goto err_ipv6; + } + + /* Identify relevant reply packet */ + if ( mode->PxeReplyReceived && + mode->PxeReply.Dhcpv4.BootpBootFile[0] ) { + /* Use boot filename if present in PXE reply */ + DBGC ( device, "EFI %s using PXE reply filename\n", + efi_handle_name ( device ) ); + packet = &mode->PxeReply; + } else if ( mode->DhcpAckReceived && + mode->DhcpAck.Dhcpv4.BootpBootFile[0] ) { + /* Otherwise, use boot filename if present in DHCPACK */ + DBGC ( device, "EFI %s using DHCPACK filename\n", + efi_handle_name ( device ) ); + packet = &mode->DhcpAck; + } else if ( mode->ProxyOfferReceived && + mode->ProxyOffer.Dhcpv4.BootpBootFile[0] ) { + /* Otherwise, use boot filename if present in ProxyDHCPOFFER */ + DBGC ( device, "EFI %s using ProxyDHCPOFFER filename\n", + efi_handle_name ( device ) ); + packet = &mode->ProxyOffer; + } else { + /* No boot filename available */ + rc = -ENOENT; + DBGC ( device, "EFI %s has no PXE boot filename\n", + efi_handle_name ( device ) ); + goto err_packet; + } + + /* Allocate filename */ + filename_max = ( sizeof ( packet->Dhcpv4.BootpBootFile ) + + ( sizeof ( efi_autoexec_name ) - 1 /* NUL */ ) + + 1 /* NUL */ ); + filename = zalloc ( filename_max ); + if ( ! filename ) { + rc = -ENOMEM; + goto err_filename; + } + + /* Extract next-server address and boot filename */ + memset ( &server, 0, sizeof ( server ) ); + memcpy ( &server.in, packet->Dhcpv4.BootpSiAddr, + sizeof ( server.in ) ); + memcpy ( filename, packet->Dhcpv4.BootpBootFile, + sizeof ( packet->Dhcpv4.BootpBootFile ) ); + + /* Update filename to autoexec script name */ + sep = strrchr ( filename, '/' ); + if ( ! sep ) + sep = strrchr ( filename, '\\' ); + if ( ! sep ) + sep = ( filename - 1 ); + strcpy ( ( sep + 1 ), efi_autoexec_name ); + + /* Get file size */ + if ( ( efirc = u.pxe->Mtftp ( u.pxe, + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + NULL, FALSE, &size, NULL, &server.ip, + ( ( UINT8 * ) filename ), NULL, + FALSE ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not get size of %s:%s: %s\n", + efi_handle_name ( device ), inet_ntoa ( server.in ), + filename, strerror ( rc ) ); + goto err_size; + } + + /* Ignore zero-length files */ + if ( ! size ) { + rc = -EINVAL; + DBGC ( device, "EFI %s has zero-length %s:%s\n", + efi_handle_name ( device ), inet_ntoa ( server.in ), + filename ); + goto err_empty; + } + + /* Allocate temporary copy */ + if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, size, + &data ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not allocate %s:%s: %s\n", + efi_handle_name ( device ), inet_ntoa ( server.in ), + filename, strerror ( rc ) ); + goto err_alloc; + } + + /* Download file */ + if ( ( efirc = u.pxe->Mtftp ( u.pxe, EFI_PXE_BASE_CODE_TFTP_READ_FILE, + data, FALSE, &size, NULL, &server.ip, + ( ( UINT8 * ) filename ), NULL, + FALSE ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not download %s:%s: %s\n", + efi_handle_name ( device ), inet_ntoa ( server.in ), + filename, strerror ( rc ) ); + goto err_download; + } + + /* Record autoexec script */ + efi_autoexec = data; + efi_autoexec_len = size; + data = NULL; + DBGC ( device, "EFI %s found %s:%s\n", efi_handle_name ( device ), + inet_ntoa ( server.in ), filename ); + + /* Success */ + rc = 0; + + err_download: + if ( data ) + bs->FreePool ( data ); + err_alloc: + err_empty: + err_size: + free ( filename ); + err_filename: + err_packet: + err_ipv6: + bs->CloseProtocol ( device, &efi_pxe_base_code_protocol_guid, + efi_image_handle, device ); + err_pxe: + return rc; +} + +/** + * Load autoexec script + * + * @v device Device handle + * @ret rc Return status code + */ +int efi_autoexec_load ( EFI_HANDLE device ) { + int rc; + + /* Sanity check */ + assert ( efi_autoexec == NULL ); + assert ( efi_autoexec_len == 0 ); + + /* Try loading from file system, if supported */ + if ( ( rc = efi_autoexec_filesystem ( device ) ) == 0 ) + return 0; + + /* Try loading via TFTP, if supported */ + if ( ( rc = efi_autoexec_tftp ( device ) ) == 0 ) + return 0; + + return -ENOENT; +} + +/** * Register autoexec script * */ static void efi_autoexec_startup ( void ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE device = efi_loaded_image->DeviceHandle; - const char *name = AUTOEXEC_NAME; struct image *image; /* Do nothing if we have no autoexec script */ @@ -184,15 +379,16 @@ static void efi_autoexec_startup ( void ) { return; /* Create autoexec image */ - image = image_memory ( name, virt_to_user ( efi_autoexec ), + image = image_memory ( efi_autoexec_name, + virt_to_user ( efi_autoexec ), efi_autoexec_len ); if ( ! image ) { DBGC ( device, "EFI %s could not create %s\n", - efi_handle_name ( device ), name ); + efi_handle_name ( device ), efi_autoexec_name ); return; } DBGC ( device, "EFI %s registered %s\n", - efi_handle_name ( device ), name ); + efi_handle_name ( device ), efi_autoexec_name ); /* Free temporary copy */ bs->FreePool ( efi_autoexec ); diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c index 98ebbf3a..04bbd9e0 100644 --- a/src/interface/efi/efi_console.c +++ b/src/interface/efi/efi_console.c @@ -26,7 +26,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/efi/efi.h> #include <ipxe/efi/Protocol/ConsoleControl/ConsoleControl.h> #include <ipxe/ansiesc.h> +#include <ipxe/utf8.h> #include <ipxe/console.h> +#include <ipxe/keymap.h> #include <ipxe/init.h> #include <config/console.h> @@ -54,8 +56,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ATTR_DEFAULT ATTR_FCOL_WHITE -#define CTRL_MASK 0x1f - /* Set default console usage if applicable */ #if ! ( defined ( CONSOLE_EFI ) && CONSOLE_EXPLICIT ( CONSOLE_EFI ) ) #undef CONSOLE_EFI @@ -202,6 +202,9 @@ static struct ansiesc_context efi_ansiesc_ctx = { .handlers = efi_ansiesc_handlers, }; +/** EFI console UTF-8 accumulator */ +static struct utf8_accumulator efi_utf8_acc; + /** * Print a character to EFI console * @@ -209,13 +212,25 @@ static struct ansiesc_context efi_ansiesc_ctx = { */ static void efi_putchar ( int character ) { EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut; - wchar_t wstr[] = { character, 0 }; + wchar_t wstr[2]; /* Intercept ANSI escape sequences */ character = ansiesc_process ( &efi_ansiesc_ctx, character ); if ( character < 0 ) return; + /* Accumulate Unicode characters */ + character = utf8_accumulate ( &efi_utf8_acc, character ); + if ( character == 0 ) + return; + + /* Treat unrepresentable (non-UCS2) characters as invalid */ + if ( character & ~( ( wchar_t ) -1UL ) ) + character = UTF8_INVALID; + + /* Output character */ + wstr[0] = character; + wstr[1] = L'\0'; conout->OutputString ( conout, wstr ); } @@ -285,6 +300,9 @@ static int efi_getchar ( void ) { EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *conin_ex = efi_conin_ex; const char *ansi_seq; + unsigned int character; + unsigned int shift; + unsigned int toggle; EFI_KEY_DATA key; EFI_STATUS efirc; int rc; @@ -317,16 +335,37 @@ static int efi_getchar ( void ) { key.KeyState.KeyToggleState, key.Key.UnicodeChar, key.Key.ScanCode ); - /* Translate Ctrl-<key> */ - if ( ( key.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID ) && - ( key.KeyState.KeyShiftState & ( EFI_LEFT_CONTROL_PRESSED | - EFI_RIGHT_CONTROL_PRESSED ) ) ) { - key.Key.UnicodeChar &= CTRL_MASK; - } + /* If key has a Unicode representation, remap and return it. + * There is unfortunately no way to avoid remapping the + * numeric keypad, since EFI destroys the scan code + * information that would allow us to differentiate between + * main keyboard and numeric keypad. + */ + if ( ( character = key.Key.UnicodeChar ) != 0 ) { + + /* Apply shift state */ + shift = key.KeyState.KeyShiftState; + if ( shift & EFI_SHIFT_STATE_VALID ) { + if ( shift & ( EFI_LEFT_CONTROL_PRESSED | + EFI_RIGHT_CONTROL_PRESSED ) ) { + character |= KEYMAP_CTRL; + } + if ( shift & EFI_RIGHT_ALT_PRESSED ) { + character |= KEYMAP_ALTGR; + } + } - /* If key has a Unicode representation, return it */ - if ( key.Key.UnicodeChar ) - return key.Key.UnicodeChar; + /* Apply toggle state */ + toggle = key.KeyState.KeyToggleState; + if ( toggle & EFI_TOGGLE_STATE_VALID ) { + if ( toggle & EFI_CAPS_LOCK_ACTIVE ) { + character |= KEYMAP_CAPSLOCK_REDO; + } + } + + /* Remap and return key */ + return key_remap ( character ); + } /* Otherwise, check for a special key that we know about */ if ( ( ansi_seq = scancode_to_ansi_seq ( key.Key.ScanCode ) ) ) { diff --git a/src/interface/efi/efi_entropy.c b/src/interface/efi/efi_entropy.c index b7cb6a40..71341d9d 100644 --- a/src/interface/efi/efi_entropy.c +++ b/src/interface/efi/efi_entropy.c @@ -109,8 +109,8 @@ static void efi_entropy_disable ( void ) { /* Close timer tick event */ bs->CloseEvent ( tick ); - /* Return to TPL_CALLBACK */ - bs->RaiseTPL ( TPL_CALLBACK ); + /* Return to internal TPL */ + bs->RaiseTPL ( efi_internal_tpl ); } /** diff --git a/src/interface/efi/efi_fbcon.c b/src/interface/efi/efi_fbcon.c index 1ea25df0..e3c4d001 100644 --- a/src/interface/efi/efi_fbcon.c +++ b/src/interface/efi/efi_fbcon.c @@ -62,6 +62,12 @@ struct console_driver efi_console __attribute__ (( weak )); #define CONSOLE_EFIFB ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) #endif +/** Number of ASCII glyphs in cache */ +#define EFIFB_ASCII 128 + +/** Number of dynamic non-ASCII glyphs in cache */ +#define EFIFB_DYNAMIC 32 + /* Forward declaration */ struct console_driver efifb_console __console_driver; @@ -84,22 +90,159 @@ struct efifb { struct fbcon_colour_map map; /** Font definition */ struct fbcon_font font; - /** Character glyphs */ + /** Character glyph cache */ userptr_t glyphs; + /** Dynamic characters in cache */ + unsigned int dynamic[EFIFB_DYNAMIC]; + /** Next dynamic character cache entry to evict */ + unsigned int next; }; /** The EFI frame buffer */ static struct efifb efifb; /** - * Get character glyph + * Draw character glyph * * @v character Character + * @v index Index within glyph cache + * @v toggle Bits to toggle in each bitmask + * @ret height Character height, or negative error + */ +static int efifb_draw ( unsigned int character, unsigned int index, + unsigned int toggle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_IMAGE_OUTPUT *blt; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *pixel; + unsigned int height; + unsigned int x; + unsigned int y; + uint8_t bitmask; + size_t offset; + EFI_STATUS efirc; + int rc; + + /* Clear existing glyph */ + offset = ( index * efifb.font.height ); + memset_user ( efifb.glyphs, offset, 0, efifb.font.height ); + + /* Get glyph */ + blt = NULL; + if ( ( efirc = efifb.hiifont->GetGlyph ( efifb.hiifont, character, + NULL, &blt, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efifb, "EFIFB could not get glyph %#02x: %s\n", + character, strerror ( rc ) ); + goto err_get; + } + assert ( blt != NULL ); + + /* Sanity check */ + if ( blt->Width > 8 ) { + DBGC ( &efifb, "EFIFB glyph %#02x invalid width %d\n", + character, blt->Width ); + rc = -EINVAL; + goto err_width; + } + + /* Convert glyph to bitmap */ + pixel = blt->Image.Bitmap; + height = blt->Height; + for ( y = 0 ; ( ( y < height ) && ( y < efifb.font.height ) ) ; y++ ) { + bitmask = 0; + for ( x = 0 ; x < blt->Width ; x++ ) { + bitmask = rol8 ( bitmask, 1 ); + if ( pixel->Blue || pixel->Green || pixel->Red ) + bitmask |= 0x01; + pixel++; + } + bitmask ^= toggle; + copy_to_user ( efifb.glyphs, offset++, &bitmask, + sizeof ( bitmask ) ); + } + + /* Free glyph */ + bs->FreePool ( blt ); + + return height; + + err_width: + bs->FreePool ( blt ); + err_get: + return rc; +} + +/** + * Draw "unknown character" glyph + * + * @v index Index within glyph cache + * @ret rc Return status code + */ +static int efifb_draw_unknown ( unsigned int index ) { + + /* Draw an inverted '?' glyph */ + return efifb_draw ( '?', index, -1U ); +} + +/** + * Get dynamic glyph index + * + * @v character Unicode character + * @ret index Glyph cache index + */ +static unsigned int efifb_dynamic ( unsigned int character ) { + unsigned int dynamic; + unsigned int index; + unsigned int i; + int height; + + /* Search existing cached entries */ + for ( i = 0 ; i < EFIFB_DYNAMIC ; i++ ) { + if ( character == efifb.dynamic[i] ) + return ( EFIFB_ASCII + i ); + } + + /* Overwrite the oldest cache entry */ + dynamic = ( efifb.next++ % EFIFB_DYNAMIC ); + index = ( EFIFB_ASCII + dynamic ); + DBGC2 ( &efifb, "EFIFB dynamic %#02x is glyph %#02x\n", + dynamic, character ); + + /* Draw glyph */ + height = efifb_draw ( character, index, 0 ); + if ( height < 0 ) + efifb_draw_unknown ( index ); + + /* Record cached character */ + efifb.dynamic[dynamic] = character; + + return index; +} + +/** + * Get character glyph + * + * @v character Unicode character * @v glyph Character glyph to fill in */ static void efifb_glyph ( unsigned int character, uint8_t *glyph ) { - size_t offset = ( character * efifb.font.height ); + unsigned int index; + size_t offset; + + /* Identify glyph */ + if ( character < EFIFB_ASCII ) { + + /* ASCII character: use fixed cache entry */ + index = character; + + } else { + + /* Non-ASCII character: use dynamic glyph cache */ + index = efifb_dynamic ( character ); + } + /* Copy cached glyph */ + offset = ( index * efifb.font.height ); copy_from_user ( glyph, efifb.glyphs, offset, efifb.font.height ); } @@ -109,16 +252,10 @@ static void efifb_glyph ( unsigned int character, uint8_t *glyph ) { * @ret rc Return status code */ static int efifb_glyphs ( void ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_IMAGE_OUTPUT *blt; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *pixel; - size_t offset; - size_t len; - uint8_t bitmask; unsigned int character; - unsigned int x; - unsigned int y; - EFI_STATUS efirc; + int height; + int max; + size_t len; int rc; /* Get font height. The GetFontInfo() call nominally returns @@ -128,38 +265,32 @@ static int efifb_glyphs ( void ) { * height. */ efifb.font.height = 0; - for ( character = 0 ; character < 256 ; character++ ) { + max = 0; + for ( character = 0 ; character < EFIFB_ASCII ; character++ ) { /* Skip non-printable characters */ if ( ! isprint ( character ) ) continue; /* Get glyph */ - blt = NULL; - if ( ( efirc = efifb.hiifont->GetGlyph ( efifb.hiifont, - character, NULL, &blt, - NULL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( &efifb, "EFIFB could not get glyph %d: %s\n", - character, strerror ( rc ) ); - continue; + height = efifb_draw ( character, 0, 0 ); + if ( height < 0 ) { + rc = height; + goto err_height; } - assert ( blt != NULL ); /* Calculate maximum height */ - if ( efifb.font.height < blt->Height ) - efifb.font.height = blt->Height; - - /* Free glyph */ - bs->FreePool ( blt ); + if ( max < height ) + max = height; } - if ( ! efifb.font.height ) { + if ( ! max ) { DBGC ( &efifb, "EFIFB could not get font height\n" ); return -ENOENT; } + efifb.font.height = max; /* Allocate glyph data */ - len = ( 256 * efifb.font.height * sizeof ( bitmask ) ); + len = ( ( EFIFB_ASCII + EFIFB_DYNAMIC ) * efifb.font.height ); efifb.glyphs = umalloc ( len ); if ( ! efifb.glyphs ) { rc = -ENOMEM; @@ -168,60 +299,32 @@ static int efifb_glyphs ( void ) { memset_user ( efifb.glyphs, 0, 0, len ); /* Get font data */ - for ( character = 0 ; character < 256 ; character++ ) { + for ( character = 0 ; character < EFIFB_ASCII ; character++ ) { /* Skip non-printable characters */ - if ( ! isprint ( character ) ) - continue; - - /* Get glyph */ - blt = NULL; - if ( ( efirc = efifb.hiifont->GetGlyph ( efifb.hiifont, - character, NULL, &blt, - NULL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( &efifb, "EFIFB could not get glyph %d: %s\n", - character, strerror ( rc ) ); - continue; - } - assert ( blt != NULL ); - - /* Sanity check */ - if ( blt->Width > 8 ) { - DBGC ( &efifb, "EFIFB glyph %d invalid width %d\n", - character, blt->Width ); - continue; - } - if ( blt->Height > efifb.font.height ) { - DBGC ( &efifb, "EFIFB glyph %d invalid height %d\n", - character, blt->Height ); + if ( ! isprint ( character ) ) { + efifb_draw_unknown ( character ); continue; } - /* Convert glyph to bitmap */ - pixel = blt->Image.Bitmap; - offset = ( character * efifb.font.height ); - for ( y = 0 ; y < blt->Height ; y++ ) { - bitmask = 0; - for ( x = 0 ; x < blt->Width ; x++ ) { - bitmask = rol8 ( bitmask, 1 ); - if ( pixel->Blue || pixel->Green || pixel->Red ) - bitmask |= 0x01; - pixel++; - } - copy_to_user ( efifb.glyphs, offset++, &bitmask, - sizeof ( bitmask ) ); + /* Get glyph */ + height = efifb_draw ( character, character, 0 ); + if ( height < 0 ) { + rc = height; + goto err_draw; } - - /* Free glyph */ - bs->FreePool ( blt ); } + /* Clear dynamic glyph character cache */ + memset ( efifb.dynamic, 0, sizeof ( efifb.dynamic ) ); + efifb.font.glyph = efifb_glyph; return 0; + err_draw: ufree ( efifb.glyphs ); err_alloc: + err_height: return rc; } diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c index b7cac16e..5d98f9ff 100644 --- a/src/interface/efi/efi_init.c +++ b/src/interface/efi/efi_init.c @@ -47,6 +47,9 @@ EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path; */ EFI_SYSTEM_TABLE * _C2 ( PLATFORM, _systab ); +/** Internal task priority level */ +EFI_TPL efi_internal_tpl = TPL_CALLBACK; + /** External task priority level */ EFI_TPL efi_external_tpl = TPL_APPLICATION; @@ -79,6 +82,17 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle ); static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused, void *context __unused ) { + /* This callback is invoked at TPL_NOTIFY in order to ensure + * that we have an opportunity to shut down cleanly before + * other shutdown hooks perform destructive operations such as + * disabling the IOMMU. + * + * Modify the internal task priority level so that no code + * attempts to raise from TPL_NOTIFY to TPL_CALLBACK (which + * would trigger a fatal exception). + */ + efi_internal_tpl = TPL_NOTIFY; + /* Mark shutdown as being in progress, to indicate that large * parts of the system (e.g. timers) are no longer functional. */ @@ -273,7 +287,7 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, * bother doing so when ExitBootServices() is called. */ if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES, - TPL_CALLBACK, efi_shutdown_hook, + TPL_NOTIFY, efi_shutdown_hook, NULL, &efi_shutdown_event ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( systab, "EFI could not create ExitBootServices event: " @@ -316,9 +330,13 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_SYSTEM_TABLE *systab = efi_systab; + struct efi_saved_tpl tpl; DBGC ( systab, "EFI image unloading\n" ); + /* Raise TPL */ + efi_raise_tpl ( &tpl ); + /* Shut down */ shutdown_exit(); @@ -336,6 +354,9 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) { DBGC ( systab, "EFI image unloaded\n" ); + /* Restore TPL */ + efi_restore_tpl ( &tpl ); + return 0; } @@ -366,7 +387,7 @@ __attribute__ (( noreturn )) void __stack_chk_fail ( void ) { } /** - * Raise task priority level to TPL_CALLBACK + * Raise task priority level to internal level * * @v tpl Saved TPL */ @@ -377,7 +398,7 @@ void efi_raise_tpl ( struct efi_saved_tpl *tpl ) { tpl->previous = efi_external_tpl; /* Raise TPL and record previous TPL as new external TPL */ - tpl->current = bs->RaiseTPL ( TPL_CALLBACK ); + tpl->current = bs->RaiseTPL ( efi_internal_tpl ); efi_external_tpl = tpl->current; } diff --git a/src/interface/efi/efi_timer.c b/src/interface/efi/efi_timer.c index 405cd345..6427eb1d 100644 --- a/src/interface/efi/efi_timer.c +++ b/src/interface/efi/efi_timer.c @@ -137,7 +137,7 @@ static unsigned long efi_currticks ( void ) { efi_jiffies++; } else { bs->RestoreTPL ( efi_external_tpl ); - bs->RaiseTPL ( TPL_CALLBACK ); + bs->RaiseTPL ( efi_internal_tpl ); } return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) ); diff --git a/src/interface/efi/efi_watchdog.c b/src/interface/efi/efi_watchdog.c index 7061f81d..dcc9a566 100644 --- a/src/interface/efi/efi_watchdog.c +++ b/src/interface/efi/efi_watchdog.c @@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <string.h> #include <ipxe/retry.h> #include <ipxe/timer.h> +#include <ipxe/init.h> #include <ipxe/efi/efi.h> #include <ipxe/efi/efi_watchdog.h> @@ -80,3 +81,36 @@ static void efi_watchdog_expired ( struct retry_timer *timer, /** Watchdog holdoff timer */ struct retry_timer efi_watchdog = TIMER_INIT ( efi_watchdog_expired ); + +/** + * Disable watching when shutting down to boot an operating system + * + * @v booting System is shutting down for OS boot + */ +static void efi_watchdog_shutdown ( int booting ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + int rc; + + /* If we are shutting down to boot an operating system, then + * disable the boot services watchdog timer. The UEFI + * specification mandates that the platform firmware does this + * as part of the ExitBootServices() call, but some platforms + * (e.g. Hyper-V) are observed to occasionally forget to do + * so, resulting in a reboot approximately five minutes after + * starting the operating system. + */ + if ( booting && + ( ( efirc = bs->SetWatchdogTimer ( 0, 0, 0, NULL ) ) != 0 ) ) { + rc = -EEFI ( efirc ); + DBGC ( &efi_watchdog, "EFI could not disable watchdog timer: " + "%s\n", strerror ( rc ) ); + /* Nothing we can do */ + } +} + +/** Watchdog startup/shutdown function */ +struct startup_fn efi_watchdog_startup_fn __startup_fn ( STARTUP_EARLY ) = { + .name = "efi_watchdog", + .shutdown = efi_watchdog_shutdown, +}; diff --git a/src/interface/efi/efi_wrap.c b/src/interface/efi/efi_wrap.c index 5c02a7ee..5d5d2cae 100644 --- a/src/interface/efi/efi_wrap.c +++ b/src/interface/efi/efi_wrap.c @@ -196,6 +196,47 @@ static const char * efi_timer_delay ( EFI_TIMER_DELAY type ) { } /** + * Dump information about a loaded image + * + * @v handle Image handle + */ +static void efi_dump_image ( EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_LOADED_IMAGE_PROTOCOL *image; + void *intf; + } loaded; + EFI_STATUS efirc; + int rc; + + /* Open loaded image protocol */ + if ( ( efirc = bs->OpenProtocol ( handle, + &efi_loaded_image_protocol_guid, + &loaded.intf, efi_image_handle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( colour, "WRAP %s could not get loaded image protocol: " + "%s\n", efi_handle_name ( handle ), strerror ( rc ) ); + return; + } + + /* Dump image information */ + DBGC ( colour, "WRAP %s at base %p has protocols:\n", + efi_handle_name ( handle ), loaded.image->ImageBase ); + DBGC_EFI_PROTOCOLS ( colour, handle ); + DBGC ( colour, "WRAP %s parent", efi_handle_name ( handle ) ); + DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->ParentHandle )); + DBGC ( colour, "WRAP %s device", efi_handle_name ( handle ) ); + DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->DeviceHandle )); + DBGC ( colour, "WRAP %s file", efi_handle_name ( handle ) ); + DBGC ( colour, " %s\n", efi_devpath_text ( loaded.image->FilePath ) ); + + /* Close loaded image protocol */ + bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid, + efi_image_handle, NULL ); +} + +/** * Wrap RaiseTPL() * */ @@ -655,9 +696,9 @@ efi_load_image_wrapper ( BOOLEAN boot_policy, EFI_HANDLE parent_image_handle, DBGC ( colour, "%s ", efi_handle_name ( *image_handle ) ); DBGC ( colour, ") -> %p\n", retaddr ); - /* Wrap the new image */ + /* Dump information about loaded image */ if ( efirc == 0 ) - efi_wrap ( *image_handle ); + efi_dump_image ( *image_handle ); return efirc; } @@ -735,11 +776,14 @@ efi_exit_boot_services_wrapper ( EFI_HANDLE image_handle, UINTN map_key ) { void *retaddr = __builtin_return_address ( 0 ); EFI_STATUS efirc; - DBGC ( colour, "ExitBootServices ( %s, %#llx ) ", + DBGC ( colour, "ExitBootServices ( %s, %#llx ) -> %p\n", efi_handle_name ( image_handle ), - ( ( unsigned long long ) map_key ) ); + ( ( unsigned long long ) map_key ), retaddr ); efirc = bs->ExitBootServices ( image_handle, map_key ); - DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + if ( efirc != 0 ) { + DBGC ( colour, "ExitBootServices ( ... ) = %s -> %p\n", + efi_status ( efirc ), retaddr ); + } return efirc; } @@ -1129,12 +1173,11 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl, } /** - * Build table wrappers + * Build boot services table wrapper * - * @ret systab Wrapped system table + * @ret bs Wrapped boot services table */ -EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) { - static EFI_SYSTEM_TABLE efi_systab_wrapper; +EFI_BOOT_SERVICES * efi_wrap_bs ( void ) { static EFI_BOOT_SERVICES efi_bs_wrapper; EFI_BOOT_SERVICES *bs = efi_systab->BootServices; @@ -1194,12 +1237,7 @@ EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) { = efi_uninstall_multiple_protocol_interfaces_wrapper; efi_bs_wrapper.CreateEventEx = efi_create_event_ex_wrapper; - /* Build system table wrapper */ - memcpy ( &efi_systab_wrapper, efi_systab, - sizeof ( efi_systab_wrapper ) ); - efi_systab_wrapper.BootServices = &efi_bs_wrapper; - - return &efi_systab_wrapper; + return &efi_bs_wrapper; } /** @@ -1208,42 +1246,20 @@ EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) { * @v handle Image handle */ void efi_wrap ( EFI_HANDLE handle ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - union { - EFI_LOADED_IMAGE_PROTOCOL *image; - void *intf; - } loaded; - EFI_STATUS efirc; - int rc; + static EFI_SYSTEM_TABLE efi_systab_copy; /* Do nothing unless debugging is enabled */ if ( ! DBG_LOG ) return; - /* Open loaded image protocol */ - if ( ( efirc = bs->OpenProtocol ( handle, - &efi_loaded_image_protocol_guid, - &loaded.intf, efi_image_handle, NULL, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - rc = -EEFI ( efirc ); - DBGC ( colour, "WRAP %s could not get loaded image protocol: " - "%s\n", efi_handle_name ( handle ), strerror ( rc ) ); - return; + /* Construct modified system table */ + if ( efi_systab != &efi_systab_copy ) { + memcpy ( &efi_systab_copy, efi_systab, + sizeof ( efi_systab_copy ) ); + efi_systab->BootServices = efi_wrap_bs(); + efi_systab = &efi_systab_copy; } - /* Provide system table wrapper to image */ - loaded.image->SystemTable = efi_wrap_systab(); - DBGC ( colour, "WRAP %s at base %p has protocols:\n", - efi_handle_name ( handle ), loaded.image->ImageBase ); - DBGC_EFI_PROTOCOLS ( colour, handle ); - DBGC ( colour, "WRAP %s parent", efi_handle_name ( handle ) ); - DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->ParentHandle )); - DBGC ( colour, "WRAP %s device", efi_handle_name ( handle ) ); - DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->DeviceHandle )); - DBGC ( colour, "WRAP %s file", efi_handle_name ( handle ) ); - DBGC ( colour, " %s\n", efi_devpath_text ( loaded.image->FilePath ) ); - - /* Close loaded image protocol */ - bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid, - efi_image_handle, NULL ); + /* Dump image information */ + efi_dump_image ( handle ); } diff --git a/src/interface/smbios/smbios_settings.c b/src/interface/smbios/smbios_settings.c index 2d571f2e..ec31b43f 100644 --- a/src/interface/smbios/smbios_settings.c +++ b/src/interface/smbios/smbios_settings.c @@ -140,7 +140,8 @@ static int smbios_fetch ( struct settings *settings __unused, * is 2.6 or higher; we match this behaviour. */ raw = &buf[tag_offset]; - if ( ( setting->type == &setting_type_uuid ) && + if ( ( ( setting->type == &setting_type_uuid ) || + ( setting->type == &setting_type_guid ) ) && ( tag_len == sizeof ( uuid ) ) && ( smbios_version() >= SMBIOS_VERSION ( 2, 6 ) ) ) { DBG ( "SMBIOS detected mangled UUID\n" ); diff --git a/src/net/infiniband/xsigo.c b/src/net/infiniband/xsigo.c index 0ee753c3..4f5c618d 100644 --- a/src/net/infiniband/xsigo.c +++ b/src/net/infiniband/xsigo.c @@ -870,6 +870,7 @@ static int xsmp_rx_xve_modify ( struct xsigo_manager *xcm, * erroneously transmitted as little-endian. */ mtu = ntohs ( msg->mtu ); + memset ( &tca, 0, sizeof ( tca ) ); tca.qpn = ntohl ( msg->tca.data ); tca.qkey = ntohs ( msg->tca.qkey ); tca.gid_present = 1; diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index 01bb496b..fd94b5f0 100644 --- a/src/net/tcp/httpcore.c +++ b/src/net/tcp/httpcore.c @@ -614,8 +614,8 @@ int http_open ( struct interface *xfer, struct http_method *method, /* Calculate request URI length */ memset ( &request_uri, 0, sizeof ( request_uri ) ); - request_uri.path = ( uri->path ? uri->path : "/" ); - request_uri.query = uri->query; + request_uri.epath = ( uri->epath ? uri->epath : "/" ); + request_uri.equery = uri->equery; request_uri_len = ( format_uri ( &request_uri, NULL, 0 ) + 1 /* NUL */); diff --git a/src/net/udp/dns.c b/src/net/udp/dns.c index e5579174..f46eeb5c 100644 --- a/src/net/udp/dns.c +++ b/src/net/udp/dns.c @@ -87,9 +87,6 @@ static struct dns_server dns6; /** Total number of DNS servers */ static unsigned int dns_count; -/** Current DNS server index */ -static unsigned int dns_index; - /** The DNS search list */ static struct dns_name dns_search; @@ -489,6 +486,8 @@ struct dns_request { size_t offset; /** Search list */ struct dns_name search; + /** Server index */ + unsigned int index; /** Recursion counter */ unsigned int recursion; }; @@ -606,7 +605,7 @@ static int dns_send_packet ( struct dns_request *dns ) { DBGC ( dns, "DNS %p lost DNS servers mid query\n", dns ); return -EINVAL; } - index = ( dns_index % dns_count ); + index = ( dns->index % dns_count ); if ( index < dns6.count ) { nameserver.sin6.sin6_family = AF_INET6; memcpy ( &nameserver.sin6.sin6_addr, &dns6.in6[index], @@ -651,7 +650,7 @@ static void dns_timer_expired ( struct retry_timer *timer, int fail ) { /* Move to next DNS server if this is a retransmission */ if ( dns->buf.query.id ) - dns_index++; + dns->index++; /* Send DNS query */ dns_send_packet ( dns ); diff --git a/src/scripts/efi.lds b/src/scripts/efi.lds index dd7b3f01..218b1df6 100644 --- a/src/scripts/efi.lds +++ b/src/scripts/efi.lds @@ -75,6 +75,19 @@ SECTIONS { } /* + * The SBAT section + * + */ + + . = ALIGN ( _page_align ); + .sbat : { + _sbat = .; + KEEP(*(.sbat)) + KEEP(*(.sbat.*)) + _esbat = .; + } + + /* * Weak symbols that need zero values if not otherwise defined * */ diff --git a/src/tests/acpi_test.c b/src/tests/acpi_test.c new file mode 100644 index 00000000..1ca5befa --- /dev/null +++ b/src/tests/acpi_test.c @@ -0,0 +1,257 @@ +/* + * 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 + * + * ACPI tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <ipxe/acpi.h> +#include <ipxe/acpimac.h> +#include <ipxe/if_ether.h> +#include <ipxe/test.h> + +/** An ACPI test table signature */ +union acpi_test_signature { + /** String */ + char str[4]; + /** Raw value */ + uint32_t raw; +}; + +/** An ACPI test table */ +struct acpi_test_table { + /** Signature */ + union acpi_test_signature signature; + /** Table content */ + const void *data; +}; + +/** An ACPI test table set */ +struct acpi_test_tables { + /** Tables */ + struct acpi_test_table **table; + /** Number of tables */ + unsigned int count; +}; + +/** An ACPI MAC extraction test */ +struct acpi_mac_test { + /** ACPI test table set */ + struct acpi_test_tables *tables; + /** Expected MAC address */ + uint8_t expected[ETH_ALEN]; +}; + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define an ACPI test table */ +#define ACPI_TABLE( name, SIGNATURE, DATA ) \ + static const uint8_t name ## _data[] = DATA; \ + static struct acpi_test_table name = { \ + .signature = { \ + .str = SIGNATURE, \ + }, \ + .data = name ## _data, \ + } + +/** Define an ACPI test table set */ +#define ACPI_TABLES( name, ... ) \ + static struct acpi_test_table * name ## _table[] = \ + { __VA_ARGS__ }; \ + static struct acpi_test_tables name = { \ + .table = name ## _table, \ + .count = ( sizeof ( name ## _table ) / \ + sizeof ( name ## _table[0] ) ), \ + } + +/** Define an ACPI MAC extraction test */ +#define ACPI_MAC( name, TABLES, EXPECTED ) \ + static struct acpi_mac_test name = { \ + .tables = TABLES, \ + .expected = EXPECTED, \ + } + +/** "AMAC" SSDT + * + * DefinitionBlock ("", "SSDT", 2, "", "", 0x0) { + * Scope (\_SB) { + * Method (HW00, 0, Serialized) { Return(0) } + * Method (AMAC, 0, Serialized) { ToString("_AUXMAC_#525400aabbcc#") } + * Method (HW42, 0, Serialized) { Return(42) } + * } + * } + */ +ACPI_TABLE ( amac_ssdt, "SSDT", + DATA ( 0x53, 0x53, 0x44, 0x54, 0x5d, 0x00, 0x00, 0x00, 0x02, + 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x4e, 0x54, 0x4c, 0x04, 0x06, 0x21, 0x20, + 0x10, 0x38, 0x5c, 0x5f, 0x53, 0x42, 0x5f, 0x14, 0x08, + 0x48, 0x57, 0x30, 0x30, 0x08, 0xa4, 0x00, 0x14, 0x1e, + 0x41, 0x4d, 0x41, 0x43, 0x08, 0x0d, 0x5f, 0x41, 0x55, + 0x58, 0x4d, 0x41, 0x43, 0x5f, 0x23, 0x35, 0x32, 0x35, + 0x34, 0x30, 0x30, 0x61, 0x61, 0x62, 0x62, 0x63, 0x63, + 0x23, 0x00, 0x14, 0x09, 0x48, 0x57, 0x34, 0x32, 0x08, + 0xa4, 0x0a, 0x2a ) ); + +/** "AMAC" test tables */ +ACPI_TABLES ( amac_tables, &amac_ssdt ); + +/** "AMAC" test */ +ACPI_MAC ( amac, &amac_tables, + DATA ( 0x52, 0x54, 0x00, 0xaa, 0xbb, 0xcc ) ); + +/** "MACA" SSDT1 (does not contain AUXMAC) */ +ACPI_TABLE ( maca_ssdt1, "SSDT", + DATA ( 0x53, 0x53, 0x44, 0x54, 0x3e, 0x00, 0x00, 0x00, 0x02, + 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x4e, 0x54, 0x4c, 0x04, 0x06, 0x21, 0x20, + 0x10, 0x19, 0x5c, 0x5f, 0x53, 0x42, 0x5f, 0x14, 0x08, + 0x48, 0x57, 0x30, 0x30, 0x08, 0xa4, 0x00, 0x14, 0x09, + 0x48, 0x57, 0x34, 0x32, 0x08, 0xa4, 0x0a, 0x2a ) ); + +/** "MACA" SSDT2 (contains AUXMAC) */ +ACPI_TABLE ( maca_ssdt2, "SSDT", + DATA ( 0x53, 0x53, 0x44, 0x54, 0x54, 0x00, 0x00, 0x00, 0x02, + 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x4e, 0x54, 0x4c, 0x04, 0x06, 0x21, 0x20, + 0x10, 0x2f, 0x5c, 0x5f, 0x53, 0x42, 0x5f, 0x14, 0x1e, + 0x4d, 0x41, 0x43, 0x41, 0x08, 0x0d, 0x5f, 0x41, 0x55, + 0x58, 0x4d, 0x41, 0x43, 0x5f, 0x23, 0x35, 0x32, 0x35, + 0x34, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, + 0x23, 0x00, 0x14, 0x09, 0x48, 0x57, 0x39, 0x39, 0x08, + 0xa4, 0x0a, 0x63 ) ); + +/** "MACA" test tables */ +ACPI_TABLES ( maca_tables, &maca_ssdt1, &maca_ssdt2 ); + +/** "MACA" test */ +ACPI_MAC ( maca, &maca_tables, + DATA ( 0x52, 0x54, 0x00, 0x11, 0x22, 0x33 ) ); + +/** "RTMA" SSDT */ +ACPI_TABLE ( rtma_ssdt, "SSDT", + DATA ( 0x53, 0x53, 0x44, 0x54, 0x44, 0x00, 0x00, 0x00, 0x02, + 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x4e, 0x54, 0x4c, 0x04, 0x06, 0x21, 0x20, + 0x10, 0x1f, 0x5c, 0x5f, 0x53, 0x42, 0x5f, 0x14, 0x18, + 0x52, 0x54, 0x4d, 0x41, 0x08, 0x0d, 0x5f, 0x52, 0x54, + 0x58, 0x4d, 0x41, 0x43, 0x5f, 0x23, 0x52, 0x54, 0x30, + 0x30, 0x30, 0x31, 0x23, 0x00 ) ); + +/** "RTMA" test tables */ +ACPI_TABLES ( rtma_tables, &rtma_ssdt ); + +/** "RTMA" test */ +ACPI_MAC ( rtma, &rtma_tables, + DATA ( 0x52, 0x54, 0x30, 0x30, 0x30, 0x31 ) ); + +/** Current ACPI test table set */ +static struct acpi_test_tables *acpi_test_tables; + +/** + * Locate ACPI test table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +static userptr_t acpi_test_find ( uint32_t signature, unsigned int index ) { + struct acpi_test_table *table; + unsigned int i; + + /* Fail if no test tables are installed */ + if ( ! acpi_test_tables ) + return UNULL; + + /* Scan through test tables */ + for ( i = 0 ; i < acpi_test_tables->count ; i++ ) { + table = acpi_test_tables->table[i]; + if ( ( signature == le32_to_cpu ( table->signature.raw ) ) && + ( index-- == 0 ) ) { + return virt_to_user ( table->data ); + } + } + + return UNULL; +} + +/** Override ACPI table finder */ +typeof ( acpi_find ) *acpi_finder = acpi_test_find; + +/** + * Report ACPI MAC extraction test result + * + * @v test ACPI MAC extraction test + * @v file Test code file + * @v line Test code line + */ +static void acpi_mac_okx ( struct acpi_mac_test *test, + const char *file, unsigned int line ) { + uint8_t mac[ETH_ALEN]; + int rc; + + /* Set test table set */ + acpi_test_tables = test->tables; + + /* Extract MAC address */ + rc = acpi_mac ( mac ); + okx ( rc == 0, file, line ); + + /* Check extracted MAC address */ + okx ( memcmp ( mac, test->expected, ETH_ALEN ) == 0, file, line ); + + /* Clear test table set */ + acpi_test_tables = NULL; +} +#define acpi_mac_ok( test ) \ + acpi_mac_okx ( test, __FILE__, __LINE__ ) + +/** + * Perform ACPI self-test + * + */ +static void acpi_test_exec ( void ) { + + /* MAC extraction tests */ + acpi_mac_ok ( &amac ); + acpi_mac_ok ( &maca ); + acpi_mac_ok ( &rtma ); +} + +/** ACPI self-test */ +struct self_test acpi_test __self_test = { + .name = "acpi", + .exec = acpi_test_exec, +}; diff --git a/src/tests/settings_test.c b/src/tests/settings_test.c index 828901b0..5da7eb00 100644 --- a/src/tests/settings_test.c +++ b/src/tests/settings_test.c @@ -250,6 +250,12 @@ static struct setting test_uuid_setting = { .type = &setting_type_uuid, }; +/** Test GUID setting type */ +static struct setting test_guid_setting = { + .name = "test_guid", + .type = &setting_type_guid, +}; + /** Test PCI bus:dev.fn setting type */ static struct setting test_busdevfn_setting = { .name = "test_busdevfn", @@ -419,6 +425,10 @@ static void settings_test_exec ( void ) { RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8, 0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ), "1a6a749d-0eda-461a-a87a-7cfe4fca4a57" ); + fetchf_ok ( &test_settings, &test_guid_setting, + RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8, + 0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ), + "9d746a1a-da0e-1a46-a87a-7cfe4fca4a57" ); /* "busdevfn" setting type (no store capability) */ fetchf_ok ( &test_settings, &test_busdevfn_setting, diff --git a/src/tests/tests.c b/src/tests/tests.c index 1cc4c81e..5dbbac1b 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -75,3 +75,5 @@ REQUIRE_OBJECT ( pem_test ); REQUIRE_OBJECT ( ntlm_test ); REQUIRE_OBJECT ( zlib_test ); REQUIRE_OBJECT ( gzip_test ); +REQUIRE_OBJECT ( utf8_test ); +REQUIRE_OBJECT ( acpi_test ); diff --git a/src/tests/uri_test.c b/src/tests/uri_test.c index 92c2f903..338f479c 100644 --- a/src/tests/uri_test.c +++ b/src/tests/uri_test.c @@ -149,8 +149,10 @@ static void uri_okx ( struct uri *uri, struct uri *expected, const char *file, okx ( uristrcmp ( uri->host, expected->host ) == 0, file, line ); okx ( uristrcmp ( uri->port, expected->port ) == 0, file, line ); okx ( uristrcmp ( uri->path, expected->path ) == 0, file, line ); - okx ( uristrcmp ( uri->query, expected->query ) == 0, file, line ); - okx ( uristrcmp ( uri->fragment, expected->fragment ) == 0, file, line); + okx ( uristrcmp ( uri->epath, expected->epath ) == 0, file, line ); + okx ( uristrcmp ( uri->equery, expected->equery ) == 0, file, line ); + okx ( uristrcmp ( uri->efragment, expected->efragment ) == 0, + file, line); okx ( uri->params == expected->params, file, line ); } #define uri_ok( uri, expected ) uri_okx ( uri, expected, __FILE__, __LINE__ ) @@ -490,25 +492,33 @@ static struct uri_test uri_empty = { /** Basic HTTP URI */ static struct uri_test uri_boot_ipxe_org = { "http://boot.ipxe.org/demo/boot.php", - { .scheme = "http", .host = "boot.ipxe.org", .path = "/demo/boot.php" } + { .scheme = "http", .host = "boot.ipxe.org", + .path = "/demo/boot.php", .epath = "/demo/boot.php" }, }; /** Basic opaque URI */ static struct uri_test uri_mailto = { "mailto:ipxe-devel@lists.ipxe.org", - { .scheme = "mailto", .opaque = "ipxe-devel@lists.ipxe.org" } + { .scheme = "mailto", .opaque = "ipxe-devel@lists.ipxe.org" }, +}; + +/** Basic host-only URI */ +static struct uri_test uri_host = { + "http://boot.ipxe.org", + { .scheme = "http", .host = "boot.ipxe.org" }, }; /** Basic path-only URI */ static struct uri_test uri_path = { "/var/lib/tftpboot/pxelinux.0", - { .path = "/var/lib/tftpboot/pxelinux.0" }, + { .path = "/var/lib/tftpboot/pxelinux.0", + .epath ="/var/lib/tftpboot/pxelinux.0" }, }; /** Path-only URI with escaped characters */ static struct uri_test uri_path_escaped = { "/hello%20world%3F", - { .path = "/hello world?" }, + { .path = "/hello world?", .epath = "/hello%20world%3F" }, }; /** HTTP URI with all the trimmings */ @@ -521,8 +531,9 @@ static struct uri_test uri_http_all = { .host = "example.com", .port = "3001", .path = "/~foo/cgi-bin/foo.pl", - .query = "a=b&c=d", - .fragment = "bit", + .epath = "/~foo/cgi-bin/foo.pl", + .equery = "a=b&c=d", + .efragment = "bit", }, }; @@ -533,8 +544,9 @@ static struct uri_test uri_http_escaped = { .scheme = "https", .host = "test.ipxe.org", .path = "/wtf?\n", - .query = "kind#of/uri is", - .fragment = "this?", + .epath = "/wtf%3F%0A", + .equery = "kind%23of/uri%20is", + .efragment = "this%3F", }, }; @@ -550,8 +562,9 @@ static struct uri_test uri_http_escaped_improper = { .scheme = "https", .host = "test.ipxe.org", .path = "/wtf?\n", - .query = "kind#of/uri is", - .fragment = "this?", + .epath = "/wt%66%3f\n", + .equery = "kind%23of/uri is", + .efragment = "this?", }, }; @@ -562,6 +575,7 @@ static struct uri_test uri_ipv6 = { .scheme = "http", .host = "[2001:ba8:0:1d4::6950:5845]", .path = "/", + .epath = "/", }, }; @@ -573,6 +587,7 @@ static struct uri_test uri_ipv6_port = { .host = "[2001:ba8:0:1d4::6950:5845]", .port = "8001", .path = "/boot", + .epath = "/boot", }, }; @@ -583,6 +598,7 @@ static struct uri_test uri_ipv6_local = { .scheme = "http", .host = "[fe80::69ff:fe50:5845%net0]", .path = "/ipxe", + .epath = "/ipxe", }, }; @@ -598,6 +614,7 @@ static struct uri_test uri_ipv6_local_non_conforming = { .scheme = "http", .host = "[fe80::69ff:fe50:5845%net0]", .path = "/ipxe", + .epath = "/ipxe", }, }; @@ -625,6 +642,7 @@ static struct uri_test uri_file_absolute = { { .scheme = "file", .path = "/boot/script.ipxe", + .epath = "/boot/script.ipxe", }, }; @@ -635,6 +653,16 @@ static struct uri_test uri_file_volume = { .scheme = "file", .host = "hpilo", .path = "/boot/script.ipxe", + .epath = "/boot/script.ipxe", + }, +}; + +/** Relative URI with colons in path */ +static struct uri_test uri_colons = { + "/boot/52:54:00:12:34:56/boot.ipxe", + { + .path = "/boot/52:54:00:12:34:56/boot.ipxe", + .epath = "/boot/52:54:00:12:34:56/boot.ipxe", }, }; @@ -736,6 +764,7 @@ static struct uri_pxe_test uri_pxe_absolute = { .scheme = "http", .host = "not.a.tftp", .path = "/uri", + .epath = "/uri", }, "http://not.a.tftp/uri", }; @@ -754,6 +783,7 @@ static struct uri_pxe_test uri_pxe_absolute_path = { .scheme = "tftp", .host = "192.168.0.2", .path = "//absolute/path", + .epath = "//absolute/path", }, "tftp://192.168.0.2//absolute/path", }; @@ -772,6 +802,7 @@ static struct uri_pxe_test uri_pxe_relative_path = { .scheme = "tftp", .host = "192.168.0.3", .path = "/relative/path", + .epath = "/relative/path", }, "tftp://192.168.0.3/relative/path", }; @@ -790,8 +821,9 @@ static struct uri_pxe_test uri_pxe_icky = { .scheme = "tftp", .host = "10.0.0.6", .path = "/C:\\tftpboot\\icky#path", + .epath = "/C:\\tftpboot\\icky#path", }, - "tftp://10.0.0.6/C%3A\\tftpboot\\icky%23path", + "tftp://10.0.0.6/C:\\tftpboot\\icky#path", }; /** PXE URI with custom port */ @@ -810,6 +842,7 @@ static struct uri_pxe_test uri_pxe_port = { .host = "192.168.0.1", .port = "4069", .path = "//another/path", + .epath = "//another/path", }, "tftp://192.168.0.1:4069//another/path", }; @@ -873,6 +906,7 @@ static struct uri_params_test uri_params = { .scheme = "http", .host = "boot.ipxe.org", .path = "/demo/boot.php", + .epath = "/demo/boot.php", }, NULL, uri_params_list, @@ -902,6 +936,7 @@ static struct uri_params_test uri_named_params = { .host = "192.168.100.4", .port = "3001", .path = "/register", + .epath = "/register", }, "foo", uri_named_params_list, @@ -917,6 +952,7 @@ static void uri_test_exec ( void ) { uri_parse_format_dup_ok ( &uri_empty ); uri_parse_format_dup_ok ( &uri_boot_ipxe_org ); uri_parse_format_dup_ok ( &uri_mailto ); + uri_parse_format_dup_ok ( &uri_host ); uri_parse_format_dup_ok ( &uri_path ); uri_parse_format_dup_ok ( &uri_path_escaped ); uri_parse_format_dup_ok ( &uri_http_all ); @@ -930,6 +966,7 @@ static void uri_test_exec ( void ) { uri_parse_format_dup_ok ( &uri_file_relative ); uri_parse_format_dup_ok ( &uri_file_absolute ); uri_parse_format_dup_ok ( &uri_file_volume ); + uri_parse_format_dup_ok ( &uri_colons ); /** URI port number tests */ uri_port_ok ( &uri_explicit_port ); diff --git a/src/tests/utf8_test.c b/src/tests/utf8_test.c new file mode 100644 index 00000000..1996915c --- /dev/null +++ b/src/tests/utf8_test.c @@ -0,0 +1,164 @@ +/* + * 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 + * + * UTF-8 Unicode encoding tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <string.h> +#include <ipxe/utf8.h> +#include <ipxe/test.h> + +/** A UTF-8 accumulation test */ +struct utf8_accumulate_test { + /** UTF-8 byte string */ + const char *bytes; + /** Expected character sequence */ + const unsigned int *expected; + /** Length */ + size_t len; +}; + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define a UTF-8 accumulation test */ +#define UTF8_ACCUMULATE( name, BYTES, EXPECTED ) \ + static const char name ## _bytes[] = BYTES; \ + static const unsigned int name ## _expected[] = EXPECTED; \ + static struct utf8_accumulate_test name = { \ + .bytes = name ## _bytes, \ + .expected = name ## _expected, \ + .len = ( sizeof ( name ## _expected ) / \ + sizeof ( name ## _expected[0] ) ), \ + }; + +/** Basic ASCII test */ +UTF8_ACCUMULATE ( ascii, "Hello world!", + DATA ( 'H', 'e', 'l', 'l', 'o', ' ', + 'w', 'o', 'r', 'l', 'd', '!' ) ); + +/** Multi-byte character test */ +UTF8_ACCUMULATE ( multibyte, "Héllô wörld 🥳", + DATA ( 'H', 0, L'é', 'l', 'l', 0, L'ô', ' ', + 'w', 0, L'ö', 'r', 'l', 'd', ' ', + 0, 0, 0, 0x1f973 ) ); + +/** Stray continuation byte test */ +UTF8_ACCUMULATE ( stray_continuation, + DATA ( 'a', 0x81, 'b', 0xc3, 0x82, 0x83, 'c' ), + DATA ( 'a', 0xfffd, 'b', 0, 0xc2, 0xfffd, 'c' ) ); + +/** Missing continuation byte test */ +UTF8_ACCUMULATE ( missing_continuation, + DATA ( 'a', 0xc3, 'b', 0xe1, 0x86, 0xc3, 0x89, 'c' ), + DATA ( 'a', 0, 'b', 0, 0, 0, 0xc9, 'c' ) ); + +/** Illegal two-byte sequence test */ +UTF8_ACCUMULATE ( illegal_two, + DATA ( 'a', 0xc2, 0x80, 'b', 0xc1, 0xbf, 'c', 0xc0, 0x80, + 'd' ), + DATA ( 'a', 0, 0x80, 'b', 0, 0xfffd, 'c', 0, 0xfffd, 'd' ) ); + +/** Illegal three-byte sequence test */ +UTF8_ACCUMULATE ( illegal_three, + DATA ( 'a', 0xe0, 0xa0, 0x80, 'b', 0xe0, 0x9f, 0xbf, 'c', + 0xe0, 0x80, 0x80, 'd' ), + DATA ( 'a', 0, 0, 0x800, 'b', 0, 0, 0xfffd, 'c', + 0, 0, 0xfffd, 'd' ) ); + +/** Illegal four-byte sequence test */ +UTF8_ACCUMULATE ( illegal_four, + DATA ( 'a', 0xf0, 0x90, 0x80, 0x80, 'b', 0xf0, 0x8f, 0xbf, + 0xbf, 'c', 0xf0, 0x80, 0x80, 0x80, 'd' ), + DATA ( 'a', 0, 0, 0, 0x10000, 'b', 0, 0, 0, 0xfffd, 'c', + 0, 0, 0, 0xfffd, 'd' ) ); + +/** Illegal overlength sequence test */ +UTF8_ACCUMULATE ( illegal_length, + DATA ( 'a', 0xf8, 0xbf, 0xbf, 0xbf, 0xbf, 'b', 0xfc, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 'c', 0xfe, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 'd', 0xff, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 'e' ), + DATA ( 'a', 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 'b', + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 'c', + 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 'd', 0xfffd, 0xfffd, 0xfffd, 0xfffd, 0xfffd, + 0xfffd, 0xfffd, 0xfffd, 'e' ) ); + +/** + * Report UTF-8 accumulation test result + * + * @v test UTF-8 accumulation test + * @v file Test code file + * @v line Test code line + */ +static void utf8_accumulate_okx ( struct utf8_accumulate_test *test, + const char *file, unsigned int line ) { + struct utf8_accumulator utf8; + unsigned int character; + unsigned int i; + + /* Initialise accumulator */ + memset ( &utf8, 0, sizeof ( utf8 ) ); + + /* Test each byte in turn */ + for ( i = 0 ; i < test->len ; i++ ) { + character = utf8_accumulate ( &utf8, test->bytes[i] ); + DBGC ( test, "UTF8 byte %02x character %02x\n", + test->bytes[i], character ); + okx ( character == test->expected[i], file, line ); + } +} +#define utf8_accumulate_ok( test ) \ + utf8_accumulate_okx ( test, __FILE__, __LINE__ ) + +/** + * Perform UTF-8 self-test + * + */ +static void utf8_test_exec ( void ) { + + /* Accumulation tests */ + utf8_accumulate_ok ( &ascii ); + utf8_accumulate_ok ( &multibyte ); + utf8_accumulate_ok ( &stray_continuation ); + utf8_accumulate_ok ( &missing_continuation ); + utf8_accumulate_ok ( &illegal_two ); + utf8_accumulate_ok ( &illegal_three ); + utf8_accumulate_ok ( &illegal_four ); + utf8_accumulate_ok ( &illegal_length ); +} + +/** UTF-8 self-test */ +struct self_test utf8_test __self_test = { + .name = "utf8", + .exec = utf8_test_exec, +}; diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index 62e90ecd..24043ae6 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -579,8 +579,8 @@ int ipxe ( struct net_device *netdev ) { * defining the string PRODUCT_NAME in config/branding.h. * * While nothing in the GPL prevents you from removing all - * references to iPXE or http://ipxe.org, we prefer you not to - * do so. + * references to iPXE or https://ipxe.org, we prefer you not + * to do so. * */ printf ( NORMAL "\n\n" PRODUCT_NAME "\n" BOLD PRODUCT_SHORT_NAME " %s" diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index f8d14915..b7fc8293 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -58,8 +58,8 @@ int imgdownload ( struct uri *uri, unsigned long timeout, memcpy ( &uri_redacted, uri, sizeof ( uri_redacted ) ); uri_redacted.user = NULL; uri_redacted.password = NULL; - uri_redacted.query = NULL; - uri_redacted.fragment = NULL; + uri_redacted.equery = NULL; + uri_redacted.efragment = NULL; uri_string_redacted = format_uri_alloc ( &uri_redacted ); if ( ! uri_string_redacted ) { rc = -ENOMEM; diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 8af53aeb..08d790f1 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -753,15 +753,13 @@ static struct pe_section * create_reloc_section ( struct pe_header *pe_header, struct pe_relocs *pe_reltab ) { struct pe_section *reloc; - size_t section_rawsz; size_t section_memsz; size_t section_filesz; EFI_IMAGE_DATA_DIRECTORY *relocdir; /* Allocate PE section */ - section_rawsz = output_pe_reltab ( pe_reltab, NULL ); - section_filesz = efi_file_align ( section_rawsz ); - section_memsz = efi_image_align ( section_rawsz ); + section_memsz = output_pe_reltab ( pe_reltab, NULL ); + section_filesz = efi_file_align ( section_memsz ); reloc = xmalloc ( sizeof ( *reloc ) + section_filesz ); memset ( reloc, 0, sizeof ( *reloc ) + section_filesz ); @@ -782,11 +780,12 @@ create_reloc_section ( struct pe_header *pe_header, /* Update file header details */ pe_header->nt.FileHeader.NumberOfSections++; pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( reloc->hdr ); - pe_header->nt.OptionalHeader.SizeOfImage += section_memsz; + pe_header->nt.OptionalHeader.SizeOfImage += + efi_image_align ( section_memsz ); relocdir = &(pe_header->nt.OptionalHeader.DataDirectory [EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]); relocdir->VirtualAddress = reloc->hdr.VirtualAddress; - relocdir->Size = section_rawsz; + relocdir->Size = section_memsz; return reloc; } @@ -824,8 +823,8 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) { } *contents; /* Allocate PE section */ - section_memsz = efi_image_align ( sizeof ( *contents ) ); - section_filesz = efi_file_align ( sizeof ( *contents ) ); + section_memsz = sizeof ( *contents ); + section_filesz = efi_file_align ( section_memsz ); debug = xmalloc ( sizeof ( *debug ) + section_filesz ); memset ( debug, 0, sizeof ( *debug ) + section_filesz ); contents = ( void * ) debug->contents; @@ -857,7 +856,8 @@ create_debug_section ( struct pe_header *pe_header, const char *filename ) { /* Update file header details */ pe_header->nt.FileHeader.NumberOfSections++; pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( debug->hdr ); - pe_header->nt.OptionalHeader.SizeOfImage += section_memsz; + pe_header->nt.OptionalHeader.SizeOfImage += + efi_image_align ( section_memsz ); debugdir = &(pe_header->nt.OptionalHeader.DataDirectory [EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); debugdir->VirtualAddress = debug->hdr.VirtualAddress; diff --git a/src/util/genfsimg b/src/util/genfsimg index c1315820..731fa6ce 100755 --- a/src/util/genfsimg +++ b/src/util/genfsimg @@ -308,6 +308,9 @@ if [ -n "${ISOIMG}" ] ; then ${ISOARGS} "${ISODIR}" if isohybrid --version >/dev/null 2>&1 ; then ISOHYBRIDARGS= + if [ -n "${EFI}" ] ; then + ISOHYBRIDARGS="${ISOHYBRIDARGS} --uefi" + fi if [ -n "${SOURCE_DATE_EPOCH:-}" ] ; then ISOHYBRIDARGS="${ISOHYBRIDARGS} --id ${SOURCE_DATE_EPOCH}" fi diff --git a/src/util/genkeymap.pl b/src/util/genkeymap.pl deleted file mode 100755 index 7a5024bf..00000000 --- a/src/util/genkeymap.pl +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/perl -w -# -# Copyright (C) 2011 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. - -=head1 NAME - -genkeymap.pl - -=head1 SYNOPSIS - -genkeymap.pl [options] <keymap name> - -Options: - - -f,--from=<name> Set BIOS keymap name (default "us") - -h,--help Display brief help message - -v,--verbose Increase verbosity - -q,--quiet Decrease verbosity - -=cut - -# With reference to: -# -# http://gunnarwrobel.de/wiki/Linux-and-the-keyboard.html - -use Getopt::Long; -use Pod::Usage; -use strict; -use warnings; - -use constant BIOS_KEYMAP => "us"; -use constant BKEYMAP_MAGIC => "bkeymap"; -use constant MAX_NR_KEYMAPS => 256; -use constant NR_KEYS => 128; -use constant KG_SHIFT => 0; -use constant KG_ALTGR => 1; -use constant KG_CTRL => 2; -use constant KG_ALT => 3; -use constant KG_SHIFTL => 4; -use constant KG_KANASHIFT => 4; -use constant KG_SHIFTR => 5; -use constant KG_CTRLL => 6; -use constant KG_CTRLR => 7; -use constant KG_CAPSSHIFT => 8; -use constant KT_LATIN => 0; -use constant KT_FN => 1; -use constant KT_SPEC => 2; -use constant KT_PAD => 3; -use constant KT_DEAD => 4; -use constant KT_CONS => 5; -use constant KT_CUR => 6; -use constant KT_SHIFT => 7; -use constant KT_META => 8; -use constant KT_ASCII => 9; -use constant KT_LOCK => 10; -use constant KT_LETTER => 11; -use constant KT_SLOCK => 12; -use constant KT_SPKUP => 14; - -my $verbosity = 1; -my $from_name = BIOS_KEYMAP; - -# Read named keymaps using "loadkeys -b" -# -sub read_keymaps { - my $name = shift; - my $keymaps = []; - - # Generate binary keymap - open my $pipe, "-|", "loadkeys", "-b", $name - or die "Could not load keymap \"".$name."\": $!\n"; - - # Check magic - read $pipe, my $magic, length BKEYMAP_MAGIC - or die "Could not read from \"".$name."\": $!\n"; - die "Bad magic value from \"".$name."\"\n" - unless $magic eq BKEYMAP_MAGIC; - - # Read list of included keymaps - read $pipe, my $included, MAX_NR_KEYMAPS - or die "Could not read from \"".$name."\": $!\n"; - my @included = unpack ( "C*", $included ); - die "Missing or truncated keymap list from \"".$name."\"\n" - unless @included == MAX_NR_KEYMAPS; - - # Read each keymap in turn - for ( my $keymap = 0 ; $keymap < MAX_NR_KEYMAPS ; $keymap++ ) { - if ( $included[$keymap] ) { - read $pipe, my $keysyms, ( NR_KEYS * 2 ) - or die "Could not read from \"".$name."\": $!\n"; - my @keysyms = unpack ( "S*", $keysyms ); - die "Missing or truncated keymap ".$keymap." from \"".$name."\"\n" - unless @keysyms == NR_KEYS; - push @$keymaps, \@keysyms; - } else { - push @$keymaps, undef; - } - } - - close $pipe; - return $keymaps; -} - -# Translate keysym value to ASCII -# -sub keysym_to_ascii { - my $keysym = shift; - - # Non-existent keysyms have no ASCII equivalent - return unless $keysym; - - # Sanity check - if ( $keysym & 0xf000 ) { - warn "Unexpected keysym ".sprintf ( "0x%04x", $keysym )."\n"; - return; - } - - # Extract type and value - my $type = ( $keysym >> 8 ); - my $value = ( $keysym & 0xff ); - - # Non-simple types have no ASCII equivalent - return unless ( ( $type == KT_LATIN ) || ( $type == KT_ASCII ) || - ( $type == KT_LETTER ) ); - - # High-bit-set characters cannot be generated on a US keyboard - return if $value & 0x80; - - return $value; -} - -# Translate ASCII to descriptive name -# -sub ascii_to_name { - my $ascii = shift; - - if ( $ascii == 0x5c ) { - return "'\\\\'"; - } elsif ( $ascii == 0x27 ) { - return "'\\\''"; - } elsif ( ( $ascii >= 0x20 ) && ( $ascii <= 0x7e ) ) { - return sprintf ( "'%c'", $ascii ); - } elsif ( $ascii <= 0x1a ) { - return sprintf ( "Ctrl-%c", ( 0x40 + $ascii ) ); - } else { - return sprintf ( "0x%02x", $ascii ); - } -} - -# Produce translation table between two keymaps -# -sub translate_keymaps { - my $from = shift; - my $to = shift; - my $map = {}; - - foreach my $keymap ( 0, 1 << KG_SHIFT, 1 << KG_CTRL ) { - for ( my $keycode = 0 ; $keycode < NR_KEYS ; $keycode++ ) { - my $from_ascii = keysym_to_ascii ( $from->[$keymap]->[$keycode] ) - or next; - my $to_ascii = keysym_to_ascii ( $to->[$keymap]->[$keycode] ) - or next; - my $new_map = ( ! exists $map->{$from_ascii} ); - my $update_map = - ( $new_map || ( $keycode < $map->{$from_ascii}->{keycode} ) ); - if ( ( $verbosity > 1 ) && - ( ( $from_ascii != $to_ascii ) || - ( $update_map && ! $new_map ) ) ) { - printf STDERR "In keymap %d: %s => %s%s\n", $keymap, - ascii_to_name ( $from_ascii ), ascii_to_name ( $to_ascii ), - ( $update_map ? ( $new_map ? "" : " (override)" ) - : " (ignored)" ); - } - if ( $update_map ) { - $map->{$from_ascii} = { - to_ascii => $to_ascii, - keycode => $keycode, - }; - } - } - } - return { map { $_ => $map->{$_}->{to_ascii} } keys %$map }; -} - -# Parse command-line options -Getopt::Long::Configure ( 'bundling', 'auto_abbrev' ); -GetOptions ( - 'verbose|v+' => sub { $verbosity++; }, - 'quiet|q+' => sub { $verbosity--; }, - 'from|f=s' => sub { shift; $from_name = shift; }, - 'help|h' => sub { pod2usage ( 1 ); }, -) or die "Could not parse command-line options\n"; -pod2usage ( 1 ) unless @ARGV == 1; -my $to_name = shift; - -# Read and translate keymaps -my $from = read_keymaps ( $from_name ); -my $to = read_keymaps ( $to_name ); -my $map = translate_keymaps ( $from, $to ); - -# Generate output -( my $to_name_c = $to_name ) =~ s/\W/_/g; -printf "/** \@file\n"; -printf " *\n"; -printf " * \"".$to_name."\" keyboard mapping\n"; -printf " *\n"; -printf " * This file is automatically generated; do not edit\n"; -printf " *\n"; -printf " */\n"; -printf "\n"; -printf "FILE_LICENCE ( PUBLIC_DOMAIN );\n"; -printf "\n"; -printf "#include <ipxe/keymap.h>\n"; -printf "\n"; -printf "/** \"".$to_name."\" keyboard mapping */\n"; -printf "struct key_mapping ".$to_name_c."_mapping[] __keymap = {\n"; -foreach my $from_sym ( sort { $a <=> $b } keys %$map ) { - my $to_sym = $map->{$from_sym}; - next if $from_sym == $to_sym; - printf "\t{ 0x%02x, 0x%02x },\t/* %s => %s */\n", $from_sym, $to_sym, - ascii_to_name ( $from_sym ), ascii_to_name ( $to_sym ); -} -printf "};\n"; diff --git a/src/util/genkeymap.py b/src/util/genkeymap.py new file mode 100755 index 00000000..b70ce5f7 --- /dev/null +++ b/src/util/genkeymap.py @@ -0,0 +1,451 @@ +#!/usr/bin/env python3 +# +# 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. + +"""Generate iPXE keymaps""" + +from __future__ import annotations + +import argparse +from collections import UserDict +from collections.abc import Sequence, Mapping, MutableMapping +from dataclasses import dataclass +from enum import Flag, IntEnum +import re +import subprocess +from struct import Struct +import textwrap +from typing import ClassVar, Optional + + +BACKSPACE = chr(0x7f) +"""Backspace character""" + + +class KeyType(IntEnum): + """Key types""" + + LATIN = 0 + FN = 1 + SPEC = 2 + PAD = 3 + DEAD = 4 + CONS = 5 + CUR = 6 + SHIFT = 7 + META = 8 + ASCII = 9 + LOCK = 10 + LETTER = 11 + SLOCK = 12 + DEAD2 = 13 + BRL = 14 + UNKNOWN = 0xf0 + + +class DeadKey(IntEnum): + """Dead keys""" + + GRAVE = 0 + CIRCUMFLEX = 2 + TILDE = 3 + + +class KeyModifiers(Flag): + """Key modifiers""" + + NONE = 0 + SHIFT = 1 + ALTGR = 2 + CTRL = 4 + ALT = 8 + SHIFTL = 16 + SHIFTR = 32 + CTRLL = 64 + CTRLR = 128 + + @property + def complexity(self) -> int: + """Get complexity value of applied modifiers""" + if self == self.NONE: + return 0 + if self == self.SHIFT: + return 1 + if self == self.CTRL: + return 2 + return 3 + bin(self.value).count('1') + + +@dataclass(frozen=True) +class Key: + """A single key definition""" + + keycode: int + """Opaque keycode""" + + keysym: int + """Key symbol""" + + modifiers: KeyModifiers + """Applied modifiers""" + + ASCII_TYPES: ClassVar[set[KeyType]] = {KeyType.LATIN, KeyType.ASCII, + KeyType.LETTER} + """Key types with direct ASCII values""" + + DEAD_KEYS: ClassVar[Mapping[int, str]] = { + DeadKey.GRAVE: '`', + DeadKey.CIRCUMFLEX: '^', + DeadKey.TILDE: '~', + } + """Dead key replacement ASCII values""" + + @property + def keytype(self) -> Optional[KeyType]: + """Key type""" + try: + return KeyType(self.keysym >> 8) + except ValueError: + return None + + @property + def value(self) -> int: + """Key value""" + return self.keysym & 0xff + + @property + def ascii(self) -> Optional[str]: + """ASCII character""" + keytype = self.keytype + value = self.value + if keytype in self.ASCII_TYPES: + char = chr(value) + if value and char.isascii(): + return char + if keytype == KeyType.DEAD: + return self.DEAD_KEYS.get(value) + return None + + +class KeyLayout(UserDict[KeyModifiers, Sequence[Key]]): + """A keyboard layout""" + + BKEYMAP_MAGIC: ClassVar[bytes] = b'bkeymap' + """Magic signature for output produced by 'loadkeys -b'""" + + MAX_NR_KEYMAPS: ClassVar[int] = 256 + """Maximum number of keymaps produced by 'loadkeys -b'""" + + NR_KEYS: ClassVar[int] = 128 + """Number of keys in each keymap produced by 'loadkeys -b'""" + + KEY_BACKSPACE: ClassVar[int] = 14 + """Key code for backspace + + Keyboard maps seem to somewhat arbitrarily pick an interpretation + for the backspace key and its various modifiers, according to the + personal preference of the keyboard map transcriber. + """ + + KEY_NON_US: ClassVar[int] = 86 + """Key code 86 + + Key code 86 is somewhat bizarre. It doesn't physically exist on + most US keyboards. The database used by "loadkeys" defines it as + "<>", while most other databases either define it as a duplicate + "\\|" or omit it entirely. + """ + + FIXUPS: ClassVar[Mapping[str, Mapping[KeyModifiers, + Sequence[tuple[int, int]]]]] = { + 'us': { + # Redefine erroneous key 86 as generating "\\|" + KeyModifiers.NONE: [(KEY_NON_US, ord('\\'))], + KeyModifiers.SHIFT: [(KEY_NON_US, ord('|'))], + # Treat Ctrl-Backspace as producing Backspace rather than Ctrl-H + KeyModifiers.CTRL: [(KEY_BACKSPACE, ord(BACKSPACE))], + }, + 'il': { + # Redefine some otherwise unreachable ASCII characters + # using the closest available approximation + KeyModifiers.ALTGR: [(0x28, ord('\'')), (0x2b, ord('`')), + (0x35, ord('/'))], + }, + 'mt': { + # Redefine erroneous key 86 as generating "\\|" + KeyModifiers.NONE: [(KEY_NON_US, ord('\\'))], + KeyModifiers.SHIFT: [(KEY_NON_US, ord('|'))], + }, + } + """Fixups for erroneous keymappings produced by 'loadkeys -b'""" + + @property + def unshifted(self): + """Basic unshifted keyboard layout""" + return self[KeyModifiers.NONE] + + @property + def shifted(self): + """Basic shifted keyboard layout""" + return self[KeyModifiers.SHIFT] + + @classmethod + def load(cls, name: str) -> KeyLayout: + """Load keymap using 'loadkeys -b'""" + bkeymap = subprocess.check_output(["loadkeys", "-u", "-b", name]) + if not bkeymap.startswith(cls.BKEYMAP_MAGIC): + raise ValueError("Invalid bkeymap magic signature") + bkeymap = bkeymap[len(cls.BKEYMAP_MAGIC):] + included = bkeymap[:cls.MAX_NR_KEYMAPS] + if len(included) != cls.MAX_NR_KEYMAPS: + raise ValueError("Invalid bkeymap inclusion list") + bkeymap = bkeymap[cls.MAX_NR_KEYMAPS:] + keys = {} + for modifiers in map(KeyModifiers, range(cls.MAX_NR_KEYMAPS)): + if included[modifiers.value]: + fmt = Struct('<%dH' % cls.NR_KEYS) + bkeylist = bkeymap[:fmt.size] + if len(bkeylist) != fmt.size: + raise ValueError("Invalid bkeymap map %#x" % + modifiers.value) + keys[modifiers] = [ + Key(modifiers=modifiers, keycode=keycode, keysym=keysym) + for keycode, keysym in enumerate(fmt.unpack(bkeylist)) + ] + bkeymap = bkeymap[len(bkeylist):] + if bkeymap: + raise ValueError("Trailing bkeymap data") + for modifiers, fixups in cls.FIXUPS.get(name, {}).items(): + for keycode, keysym in fixups: + keys[modifiers][keycode] = Key(modifiers=modifiers, + keycode=keycode, keysym=keysym) + return cls(keys) + + @property + def inverse(self) -> MutableMapping[str, Key]: + """Construct inverse mapping from ASCII value to key""" + return { + key.ascii: key + # Give priority to simplest modifier for a given ASCII code + for modifiers in sorted(self.keys(), reverse=True, + key=lambda x: (x.complexity, x.value)) + # Give priority to lowest keycode for a given ASCII code + for key in reversed(self[modifiers]) + # Ignore keys with no ASCII value + if key.ascii + } + + +class BiosKeyLayout(KeyLayout): + """Keyboard layout as used by the BIOS + + To allow for remappings of the somewhat interesting key 86, we + arrange for our keyboard drivers to generate this key as "\\|" + with the high bit set. + """ + + KEY_PSEUDO: ClassVar[int] = 0x80 + """Flag used to indicate a fake ASCII value""" + + KEY_NON_US_UNSHIFTED: ClassVar[str] = chr(KEY_PSEUDO | ord('\\')) + """Fake ASCII value generated for unshifted key code 86""" + + KEY_NON_US_SHIFTED: ClassVar[str] = chr(KEY_PSEUDO | ord('|')) + """Fake ASCII value generated for shifted key code 86""" + + @property + def inverse(self) -> MutableMapping[str, Key]: + inverse = super().inverse + assert len(inverse) == 0x7f + inverse[self.KEY_NON_US_UNSHIFTED] = self.unshifted[self.KEY_NON_US] + inverse[self.KEY_NON_US_SHIFTED] = self.shifted[self.KEY_NON_US] + assert all(x.modifiers in {KeyModifiers.NONE, KeyModifiers.SHIFT, + KeyModifiers.CTRL} + for x in inverse.values()) + return inverse + + +class KeymapKeys(UserDict[str, Optional[str]]): + """An ASCII character remapping""" + + @classmethod + def ascii_name(cls, char: str) -> str: + """ASCII character name""" + if char == '\\': + name = "'\\\\'" + elif char == '\'': + name = "'\\\''" + elif ord(char) & BiosKeyLayout.KEY_PSEUDO: + name = "Pseudo-%s" % cls.ascii_name( + chr(ord(char) & ~BiosKeyLayout.KEY_PSEUDO) + ) + elif char.isprintable(): + name = "'%s'" % char + elif ord(char) <= 0x1a: + name = "Ctrl-%c" % (ord(char) + 0x40) + else: + name = "0x%02x" % ord(char) + return name + + @property + def code(self): + """Generated source code for C array""" + return '{\n' + ''.join( + '\t{ 0x%02x, 0x%02x },\t/* %s => %s */\n' % ( + ord(source), ord(target), + self.ascii_name(source), self.ascii_name(target) + ) + for source, target in self.items() + if target + and ord(source) & ~BiosKeyLayout.KEY_PSEUDO != ord(target) + ) + '\t{ 0, 0 }\n}' + + +@dataclass +class Keymap: + """An iPXE keyboard mapping""" + + name: str + """Mapping name""" + + source: KeyLayout + """Source keyboard layout""" + + target: KeyLayout + """Target keyboard layout""" + + @property + def basic(self) -> KeymapKeys: + """Basic remapping table""" + # Construct raw mapping from source ASCII to target ASCII + raw = {source: self.target[key.modifiers][key.keycode].ascii + for source, key in self.source.inverse.items()} + # Eliminate any identity mappings, or mappings that attempt to + # remap the backspace key + table = {source: target for source, target in raw.items() + if source != target + and source != BACKSPACE + and target != BACKSPACE} + # Recursively delete any mappings that would produce + # unreachable alphanumerics (e.g. the "il" keymap, which maps + # away the whole lower-case alphabet) + while True: + unreachable = set(table.keys()) - set(table.values()) + delete = {x for x in unreachable if x.isascii() and x.isalnum()} + if not delete: + break + table = {k: v for k, v in table.items() if k not in delete} + # Sanity check: ensure that all numerics are reachable using + # the same shift state + digits = '1234567890' + unshifted = ''.join(table.get(x) or x for x in '1234567890') + shifted = ''.join(table.get(x) or x for x in '!@#$%^&*()') + if digits not in (shifted, unshifted): + raise ValueError("Inconsistent numeric remapping %s / %s" % + (unshifted, shifted)) + return KeymapKeys(dict(sorted(table.items()))) + + @property + def altgr(self) -> KeymapKeys: + """AltGr remapping table""" + # Construct raw mapping from source ASCII to target ASCII + raw = { + source: next((self.target[x][key.keycode].ascii + for x in (key.modifiers | KeyModifiers.ALTGR, + KeyModifiers.ALTGR, key.modifiers) + if x in self.target + and self.target[x][key.keycode].ascii), None) + for source, key in self.source.inverse.items() + } + # Identify printable keys that are unreachable via the basic map + basic = self.basic + unmapped = set(x for x in basic.keys() + if x.isascii() and x.isprintable()) + remapped = set(basic.values()) + unreachable = unmapped - remapped + # Eliminate any mappings for unprintable characters, or + # mappings for characters that are reachable via the basic map + table = {source: target for source, target in raw.items() + if source.isprintable() + and target in unreachable} + # Check that all characters are now reachable + unreachable -= set(table.values()) + if unreachable: + raise ValueError("Unreachable characters: %s" % ', '.join( + KeymapKeys.ascii_name(x) for x in sorted(unreachable) + )) + return KeymapKeys(dict(sorted(table.items()))) + + def cname(self, suffix: str) -> str: + """C variable name""" + return re.sub(r'\W', '_', (self.name + '_' + suffix)) + + @property + def code(self) -> str: + """Generated source code""" + keymap_name = self.cname("keymap") + basic_name = self.cname("basic") + altgr_name = self.cname("altgr") + attribute = "__keymap_default" if self.name == "us" else "__keymap" + code = textwrap.dedent(f""" + /** @file + * + * "{self.name}" keyboard mapping + * + * This file is automatically generated; do not edit + * + */ + + FILE_LICENCE ( PUBLIC_DOMAIN ); + + #include <ipxe/keymap.h> + + /** "{self.name}" basic remapping */ + static struct keymap_key {basic_name}[] = %s; + + /** "{self.name}" AltGr remapping */ + static struct keymap_key {altgr_name}[] = %s; + + /** "{self.name}" keyboard map */ + struct keymap {keymap_name} {attribute} = {{ + \t.name = "{self.name}", + \t.basic = {basic_name}, + \t.altgr = {altgr_name}, + }}; + """).strip() % (self.basic.code, self.altgr.code) + return code + + +if __name__ == '__main__': + + # Parse command-line arguments + parser = argparse.ArgumentParser(description="Generate iPXE keymaps") + parser.add_argument('--verbose', '-v', action='count', default=0, + help="Increase verbosity") + parser.add_argument('layout', help="Target keyboard layout") + args = parser.parse_args() + + # Load source and target keyboard layouts + source = BiosKeyLayout.load('us') + target = KeyLayout.load(args.layout) + + # Construct keyboard mapping + keymap = Keymap(name=args.layout, source=source, target=target) + + # Output generated code + print(keymap.code) diff --git a/src/util/niclist.pl b/src/util/niclist.pl index 2668a1c0..c35a3277 100755 --- a/src/util/niclist.pl +++ b/src/util/niclist.pl @@ -565,7 +565,7 @@ EOM return join("\n", @output); } -# Output NIC list in DokuWiki format (for http://ipxe.org) +# Output NIC list in DokuWiki format (for https://ipxe.org) sub format_nic_list_dokuwiki { my ($nic_list, $column_names) = @_; my @output; |