summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2022-05-11 10:41:01 +0200
committerSimon Rettberg2022-05-11 10:41:01 +0200
commita12e3c379cf2e5946c7316259ef46736cdd5f222 (patch)
tree49638dad528a4490e293ea4a0f87e39ce862a75b
parentLocal UEFI disk boot support (diff)
parent[cloud] Allow aws-import script to run on Python 3.6 (diff)
downloadipxe-a12e3c379cf2e5946c7316259ef46736cdd5f222.tar.gz
ipxe-a12e3c379cf2e5946c7316259ef46736cdd5f222.tar.xz
ipxe-a12e3c379cf2e5946c7316259ef46736cdd5f222.zip
Merge branch 'master' into openslx
-rwxr-xr-xcontrib/cloud/aws-import2
-rw-r--r--src/Makefile5
-rw-r--r--src/Makefile.housekeeping6
-rw-r--r--src/arch/i386/scripts/i386-kir.lds2
-rw-r--r--src/arch/i386/scripts/linux.lds2
-rw-r--r--src/arch/x86/include/bios.h7
-rw-r--r--src/arch/x86/interface/pcbios/acpi_timer.c2
-rw-r--r--src/arch/x86/interface/pcbios/acpipwr.c2
-rw-r--r--src/arch/x86/interface/pcbios/bios_console.c71
-rw-r--r--src/arch/x86/interface/pcbios/vesafb.c25
-rw-r--r--src/arch/x86/interface/syslinux/comboot_call.c2
-rw-r--r--src/arch/x86/prefix/libprefix.S14
-rw-r--r--src/arch/x86/prefix/romprefix.S4
-rw-r--r--src/arch/x86/scripts/pcbios.lds2
-rw-r--r--src/arch/x86/scripts/prefixonly.lds2
-rw-r--r--src/arch/x86_64/scripts/linux.lds2
-rw-r--r--src/config/branding.h42
-rw-r--r--src/config/defaults/efi.h4
-rw-r--r--src/core/acpi.c22
-rw-r--r--src/core/acpi_settings.c2
-rw-r--r--src/core/acpimac.c153
-rw-r--r--src/core/dynkeymap.c131
-rw-r--r--src/core/fbcon.c5
-rw-r--r--src/core/image.c7
-rw-r--r--src/core/keymap.c131
-rw-r--r--src/core/settings.c33
-rw-r--r--src/core/uri.c144
-rw-r--r--src/core/utf8.c137
-rw-r--r--src/core/version.c30
-rw-r--r--src/drivers/bus/pci.c5
-rw-r--r--src/drivers/bus/virtio-pci.c45
-rw-r--r--src/drivers/bus/virtio-ring.c4
-rw-r--r--src/drivers/net/efi/nii.c2
-rw-r--r--src/drivers/net/efi/snpnet.c18
-rw-r--r--src/drivers/net/intelx.c1
-rw-r--r--src/drivers/net/virtio-net.c36
-rw-r--r--src/drivers/usb/usbkbd.c27
-rw-r--r--src/drivers/usb/usbkbd.h1
-rw-r--r--src/drivers/usb/xhci.c73
-rw-r--r--src/drivers/usb/xhci.h2
-rw-r--r--src/hci/keymap/keymap_al.c30
-rw-r--r--src/hci/keymap/keymap_az.c24
-rw-r--r--src/hci/keymap/keymap_bg.c15
-rw-r--r--src/hci/keymap/keymap_by.c19
-rw-r--r--src/hci/keymap/keymap_cf.c32
-rw-r--r--src/hci/keymap/keymap_cz.c87
-rw-r--r--src/hci/keymap/keymap_de.c48
-rw-r--r--src/hci/keymap/keymap_dk.c40
-rw-r--r--src/hci/keymap/keymap_es.c52
-rw-r--r--src/hci/keymap/keymap_et.c35
-rw-r--r--src/hci/keymap/keymap_fi.c40
-rw-r--r--src/hci/keymap/keymap_fr.c54
-rw-r--r--src/hci/keymap/keymap_gr.c19
-rw-r--r--src/hci/keymap/keymap_hu.c61
-rw-r--r--src/hci/keymap/keymap_il.c37
-rw-r--r--src/hci/keymap/keymap_it.c41
-rw-r--r--src/hci/keymap/keymap_lt.c22
-rw-r--r--src/hci/keymap/keymap_mk.c19
-rw-r--r--src/hci/keymap/keymap_mt.c29
-rw-r--r--src/hci/keymap/keymap_nl.c28
-rw-r--r--src/hci/keymap/keymap_no-latin1.c33
-rw-r--r--src/hci/keymap/keymap_no.c121
-rw-r--r--src/hci/keymap/keymap_pl.c19
-rw-r--r--src/hci/keymap/keymap_pt.c65
-rw-r--r--src/hci/keymap/keymap_ro.c17
-rw-r--r--src/hci/keymap/keymap_ru.c20
-rw-r--r--src/hci/keymap/keymap_se.c64
-rw-r--r--src/hci/keymap/keymap_sg.c32
-rw-r--r--src/hci/keymap/keymap_sr-latin.c30
-rw-r--r--src/hci/keymap/keymap_sr.c35
-rw-r--r--src/hci/keymap/keymap_th.c15
-rw-r--r--src/hci/keymap/keymap_ua.c19
-rw-r--r--src/hci/keymap/keymap_uk.c17
-rw-r--r--src/hci/keymap/keymap_us.c17
-rw-r--r--src/hci/keymap/keymap_wo.c55
-rw-r--r--src/include/ipxe/acpi.h3
-rw-r--r--src/include/ipxe/efi/efi.h1
-rw-r--r--src/include/ipxe/efi/efi_wrap.h2
-rw-r--r--src/include/ipxe/errfile.h1
-rw-r--r--src/include/ipxe/fbcon.h7
-rw-r--r--src/include/ipxe/keymap.h57
-rw-r--r--src/include/ipxe/linux/linux_uaccess.h15
-rw-r--r--src/include/ipxe/sbat.h68
-rw-r--r--src/include/ipxe/settings.h1
-rw-r--r--src/include/ipxe/srp.h2
-rw-r--r--src/include/ipxe/tables.h27
-rw-r--r--src/include/ipxe/uri.h31
-rw-r--r--src/include/ipxe/utf8.h69
-rw-r--r--src/include/ipxe/virtio-pci.h8
-rw-r--r--src/include/ipxe/virtio-ring.h7
-rw-r--r--src/interface/efi/efi_autoexec.c238
-rw-r--r--src/interface/efi/efi_console.c63
-rw-r--r--src/interface/efi/efi_entropy.c4
-rw-r--r--src/interface/efi/efi_fbcon.c243
-rw-r--r--src/interface/efi/efi_init.c27
-rw-r--r--src/interface/efi/efi_timer.c2
-rw-r--r--src/interface/efi/efi_watchdog.c34
-rw-r--r--src/interface/efi/efi_wrap.c108
-rw-r--r--src/interface/smbios/smbios_settings.c3
-rw-r--r--src/net/infiniband/xsigo.c1
-rw-r--r--src/net/tcp/httpcore.c4
-rw-r--r--src/net/udp/dns.c9
-rw-r--r--src/scripts/efi.lds13
-rw-r--r--src/tests/acpi_test.c257
-rw-r--r--src/tests/settings_test.c10
-rw-r--r--src/tests/tests.c2
-rw-r--r--src/tests/uri_test.c63
-rw-r--r--src/tests/utf8_test.c164
-rw-r--r--src/usr/autoboot.c4
-rw-r--r--src/usr/imgmgmt.c4
-rw-r--r--src/util/elf2efi.c18
-rwxr-xr-xsrc/util/genfsimg3
-rwxr-xr-xsrc/util/genkeymap.pl238
-rwxr-xr-xsrc/util/genkeymap.py451
-rwxr-xr-xsrc/util/niclist.pl2
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;