From f24a2794e1b527e45efbbcad1c272f176f3d9df0 Mon Sep 17 00:00:00 2001 From: Aaron Young Date: Wed, 27 Oct 2021 16:05:43 -0700 Subject: [virtio] Update driver to use DMA API Signed-off-by: Aaron Young --- src/include/ipxe/virtio-pci.h | 8 ++++++-- src/include/ipxe/virtio-ring.h | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/virtio-pci.h b/src/include/ipxe/virtio-pci.h index f3074f14d..7abae26ff 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 + /* 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 852769f29..d082139e9 100644 --- a/src/include/ipxe/virtio-ring.h +++ b/src/include/ipxe/virtio-ring.h @@ -2,6 +2,7 @@ # define _VIRTIO_RING_H_ #include +#include /* 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; }; -- cgit v1.2.3-55-g7522 From 1844aacc837bf81cb1959fa65f2e52dcc70a0cae Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 11 Nov 2021 23:31:23 +0000 Subject: [uri] Retain original encodings for path, query, and fragment fields iPXE decodes any percent-encoded characters during the URI parsing stage, thereby allowing protocol implementations to consume the raw field values directly without further decoding. When reconstructing a URI string for use in an HTTP request line, the percent-encoding is currently reapplied in a reversible way: we guarantee that our reconstructed URI string could be decoded to give the same raw field values. This technically violates RFC3986, which states that "URIs that differ in the replacement of a reserved character with its corresponding percent-encoded octet are not equivalent". Experiments show that several HTTP server applications will attach meaning to the choice of whether or not a particular character was percent-encoded, even when the percent-encoding is unnecessary from the perspective of parsing the URI into its component fields. Fix by storing the originally encoded substrings for the path, query, and fragment fields and using these original encoded versions when reconstructing a URI string. The path field is also stored as a decoded string, for use by protocols such as TFTP that communicate using raw strings rather than URI-encoded strings. All other fields (such as the username and password) continue to be stored only in their decoded versions since nothing ever needs to know the originally encoded versions of these fields. Signed-off-by: Michael Brown --- src/core/uri.c | 131 ++++++++++++++++++++++++++++++------------------- src/include/ipxe/uri.h | 31 +++++++++--- src/net/tcp/httpcore.c | 4 +- src/tests/uri_test.c | 53 +++++++++++++++----- src/usr/imgmgmt.c | 4 +- 5 files changed, 148 insertions(+), 75 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/core/uri.c b/src/core/uri.c index e9e512ab4..a0f79e9ec 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,7 +331,7 @@ 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 */ @@ -338,47 +341,47 @@ struct uri * parse_uri ( const char *uri_string ) { *(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; + epath = raw; } /* If we don't have a path (i.e. we have an absolute URI with * an opaque portion, we're already finished processing */ - if ( ! 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 +389,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 +430,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 +467,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 +489,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 +689,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 +699,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 +728,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 +774,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/include/ipxe/uri.h b/src/include/ipxe/uri.h index 3879a0e73..e5b7c8616 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/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index 01bb496b2..fd94b5f08 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/tests/uri_test.c b/src/tests/uri_test.c index 92c2f9037..929ab3632 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,7 @@ static struct uri_test uri_file_volume = { .scheme = "file", .host = "hpilo", .path = "/boot/script.ipxe", + .epath = "/boot/script.ipxe", }, }; @@ -736,6 +755,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 +774,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 +793,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 +812,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 +833,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 +897,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 +927,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 +943,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 ); diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index f8d149153..b7fc8293d 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; -- cgit v1.2.3-55-g7522 From b6045a8cbb3843f185e8b1ab6488ee6799d0c2b7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 21 Nov 2021 13:27:14 +0000 Subject: [efi] Modify global system table when wrapping a loaded image The EFI loaded image protocol allows an image to be provided with a custom system table, and we currently use this mechanism to wrap any boot services calls made by the loaded image in order to provide strace-like debugging via DEBUG=efi_wrap. The ExitBootServices() call will modify the global system table, leaving the loaded image using a system table that is no longer current. When DEBUG=efi_wrap is used, this generally results in the machine locking up at the point that the loaded operating system calls ExitBootServices(). Fix by modifying the global EFI system table to point to our wrapper functions, instead of providing a custom system table via the loaded image protocol. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_wrap.h | 2 +- src/interface/efi/efi_wrap.c | 99 +++++++++++++++++++++++------------------ 2 files changed, 57 insertions(+), 44 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_wrap.h b/src/include/ipxe/efi/efi_wrap.h index 6c7ccf2e4..2747a9e33 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 -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/interface/efi/efi_wrap.c b/src/interface/efi/efi_wrap.c index 65c70ea28..5d5d2caee 100644 --- a/src/interface/efi/efi_wrap.c +++ b/src/interface/efi/efi_wrap.c @@ -195,6 +195,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; } @@ -1132,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; @@ -1197,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; } /** @@ -1211,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 ); } -- cgit v1.2.3-55-g7522 From 562c74e1ea52a399f7a6c416e35d98f4b37888cf Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 22 Nov 2021 14:53:33 +0000 Subject: [efi] Run ExitBootServices shutdown hook at TPL_NOTIFY On some systems (observed with the Thunderbolt ports on a ThinkPad X1 Extreme Gen3 and a ThinkPad P53), if the IOMMU is enabled then the system firmware will install an ExitBootServices notification event that disables bus mastering on the Thunderbolt xHCI controller and all PCI bridges, and destroys any extant IOMMU mappings. This leaves the xHCI controller unable to perform any DMA operations. As described in commit 236299b ("[xhci] Avoid DMA during shutdown if firmware has disabled bus mastering"), any subsequent DMA operation attempted by the xHCI controller will end up completing after the operating system kernel has reenabled bus mastering, resulting in a DMA operation to an area of memory that the hardware is no longer permitted to access and, on Windows with the Driver Verifier enabled, a STOP 0xE6 (DRIVER_VERIFIER_DMA_VIOLATION). That commit avoids triggering any DMA attempts during the shutdown of the xHCI controller itself. However, this is not a complete solution since any attached and opened USB device (e.g. a USB NIC) may asynchronously trigger DMA attempts that happen to occur after bus mastering has been disabled but before we reset the xHCI controller. Avoid this problem by installing our own ExitBootServices notification event at TPL_NOTIFY, thereby causing it to be invoked before the firmware's own ExitBootServices notification event that disables bus mastering. This unsurprisingly causes the shutdown hook itself to be invoked at TPL_NOTIFY, which causes a fatal error when later code attempts to raise the TPL to TPL_CALLBACK (which is a lower TPL). Work around this problem by redefining the "internal" iPXE TPL to be variable, and set this internal TPL to TPL_NOTIFY when the shutdown hook is invoked. Avoid calling into an underlying SNP protocol instance from within our shutdown hook at TPL_NOTIFY, since the underlying SNP driver may attempt to raise the TPL to TPL_CALLBACK (which would cause a fatal error). Failing to shut down the underlying SNP device is safe to do since the underlying device must, in any case, have installed its own ExitBootServices hook if any shutdown actions are required. Reported-by: Andreas Hammarskjöld Tested-by: Andreas Hammarskjöld Signed-off-by: Michael Brown --- src/drivers/net/efi/nii.c | 2 +- src/drivers/net/efi/snpnet.c | 18 ++++++++++++++---- src/include/ipxe/efi/efi.h | 1 + src/interface/efi/efi_entropy.c | 4 ++-- src/interface/efi/efi_init.c | 20 +++++++++++++++++--- src/interface/efi/efi_timer.c | 2 +- 6 files changed, 36 insertions(+), 11 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index b9f34650e..833462e77 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 fb5240277..69ec6f5e5 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/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index a83fa0f27..1dd0d4453 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/interface/efi/efi_entropy.c b/src/interface/efi/efi_entropy.c index 70cd06293..1e8ddfb68 100644 --- a/src/interface/efi/efi_entropy.c +++ b/src/interface/efi/efi_entropy.c @@ -104,8 +104,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_init.c b/src/interface/efi/efi_init.c index 1c6e9d440..5d98f9ff7 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: " @@ -373,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 */ @@ -384,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 405cd3454..6427eb1d8 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 ) ); -- cgit v1.2.3-55-g7522 From f43c2fd69749bb9a44f2a3ab61b6735938432b52 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 4 Jan 2022 13:31:15 +0000 Subject: [settings] Support formatting UUIDs as little-endian GUIDs The RFC4122 specification defines UUIDs as being in network byte order, but an unfortunately significant amount of (mostly Microsoft) software treats them as having the first three fields in little-endian byte order. In an ideal world, any server-side software that compares UUIDs for equality would perform an endian-insensitive comparison (analogous to comparing strings for equality using a case-insensitive comparison), and would therefore not care about byte order differences. Define a setting type name ":guid" to allow a UUID setting to be formatted in little-endian order, to simplify interoperability with server-side software that expects such a formatting. Signed-off-by: Michael Brown --- src/core/settings.c | 23 ++++++++++++++++++----- src/include/ipxe/settings.h | 1 + src/interface/smbios/smbios_settings.c | 3 ++- src/tests/settings_test.c | 10 ++++++++++ 4 files changed, 31 insertions(+), 6 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/core/settings.c b/src/core/settings.c index 430cdc84b..fcdf98d2b 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -2199,7 +2199,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 @@ -2208,17 +2208,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 */ @@ -2227,6 +2234,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/include/ipxe/settings.h b/src/include/ipxe/settings.h index f463e6674..e042b9758 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -426,6 +426,7 @@ extern const struct setting_type setting_type_hexhyp __setting_type; extern const struct setting_type setting_type_hexraw __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/interface/smbios/smbios_settings.c b/src/interface/smbios/smbios_settings.c index 2d571f2e4..ec31b43f2 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/tests/settings_test.c b/src/tests/settings_test.c index 828901b06..5da7eb008 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, -- cgit v1.2.3-55-g7522 From 53a5de3641ccd0836aac7378cdd37c9757e2db3a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 13 Jan 2022 12:48:38 +0000 Subject: [doc] Update user-visible ipxe.org URIs to use HTTPS Signed-off-by: Michael Brown --- src/Makefile | 2 +- src/arch/x86/interface/syslinux/comboot_call.c | 2 +- src/arch/x86/prefix/romprefix.S | 4 ++-- src/config/branding.h | 24 ++++++++++++------------ src/include/ipxe/srp.h | 2 +- src/usr/autoboot.c | 4 ++-- src/util/niclist.pl | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/Makefile b/src/Makefile index 69139dc11..4c4abf1aa 100644 --- a/src/Makefile +++ b/src/Makefile @@ -190,7 +190,7 @@ vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom @$(ECHO) ' bin/10222000.rom -- vlance/pcnet32' @$(ECHO) ' bin/15ad07b0.rom -- vmxnet3' @$(ECHO) - @$(ECHO) 'For more information, see http://ipxe.org/howto/vmware' + @$(ECHO) 'For more information, see https://ipxe.org/howto/vmware' @$(ECHO) @$(ECHO) '===========================================================' diff --git a/src/arch/x86/interface/syslinux/comboot_call.c b/src/arch/x86/interface/syslinux/comboot_call.c index dc308dafe..b75e8ef7c 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/romprefix.S b/src/arch/x86/prefix/romprefix.S index a9934a725..4e8793c21 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/config/branding.h b/src/config/branding.h index 73f00af95..e503dff9a 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,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * iPXE project and prohibit the alteration or removal of any * references to "iPXE". ] */ -#define PRODUCT_SETTING_URI "http://ipxe.org/cfg/%s" +#define PRODUCT_SETTING_URI "https://ipxe.org/cfg/%s" #include diff --git a/src/include/ipxe/srp.h b/src/include/ipxe/srp.h index 3abb0995f..1f66a22b2 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/usr/autoboot.c b/src/usr/autoboot.c index 62e90ecd0..24043ae69 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/util/niclist.pl b/src/util/niclist.pl index 2668a1c03..c35a3277e 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; -- cgit v1.2.3-55-g7522 From f4f9adf618cd85d330a896e1f721f3aa78d2409d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 13 Jan 2022 14:10:03 +0000 Subject: [efi] Include Secure Boot Advanced Targeting (SBAT) metadata 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). Add SBAT metadata to iPXE EFI binaries to support this mechanism. Signed-off-by: Michael Brown --- src/arch/i386/scripts/i386-kir.lds | 2 ++ src/arch/i386/scripts/linux.lds | 2 ++ src/arch/x86/scripts/pcbios.lds | 2 ++ src/arch/x86/scripts/prefixonly.lds | 2 ++ src/arch/x86_64/scripts/linux.lds | 2 ++ src/config/branding.h | 18 ++++++++++ src/core/version.c | 30 ++++++++++++++++ src/include/ipxe/sbat.h | 68 +++++++++++++++++++++++++++++++++++++ src/scripts/efi.lds | 13 +++++++ 9 files changed, 139 insertions(+) create mode 100644 src/include/ipxe/sbat.h (limited to 'src/include/ipxe') diff --git a/src/arch/i386/scripts/i386-kir.lds b/src/arch/i386/scripts/i386-kir.lds index 66bf804e6..13c36f2bf 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 9f2eeaf3c..8c3a7b0ba 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/scripts/pcbios.lds b/src/arch/x86/scripts/pcbios.lds index de59adca9..e208b174b 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 dce0930b5..2fe5b03be 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 47db21745..a093787e5 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 e503dff9a..454bf0c03 100644 --- a/src/config/branding.h +++ b/src/config/branding.h @@ -169,6 +169,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #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 #endif /* CONFIG_BRANDING_H */ diff --git a/src/core/version.c b/src/core/version.c index c984335c2..22f444065 100644 --- a/src/core/version.c +++ b/src/core/version.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -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/include/ipxe/sbat.h b/src/include/ipxe/sbat.h new file mode 100644 index 000000000..4b74670ed --- /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/scripts/efi.lds b/src/scripts/efi.lds index dd7b3f019..218b1df66 100644 --- a/src/scripts/efi.lds +++ b/src/scripts/efi.lds @@ -74,6 +74,19 @@ SECTIONS { _ebss = .; } + /* + * The SBAT section + * + */ + + . = ALIGN ( _page_align ); + .sbat : { + _sbat = .; + KEEP(*(.sbat)) + KEEP(*(.sbat.*)) + _esbat = .; + } + /* * Weak symbols that need zero values if not otherwise defined * -- cgit v1.2.3-55-g7522 From f51a62bc3f7abb40e331c16df1f4d9314aefaf23 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 9 Feb 2022 15:54:39 +0000 Subject: [console] Generalise bios_keymap() as key_remap() Allow the keyboard remapping functionality to be exposed to consoles other than the BIOS console. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/bios_console.c | 18 +--------- src/core/keymap.c | 52 ++++++++++++++++++++++++++++ src/include/ipxe/keymap.h | 2 ++ 3 files changed, 55 insertions(+), 17 deletions(-) create mode 100644 src/core/keymap.c (limited to 'src/include/ipxe') diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 80ebf330e..0692e7a6c 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -339,22 +339,6 @@ static const char * bios_ansi_seq ( unsigned int scancode ) { return NULL; } -/** - * Map a key - * - * @v character Character read from console - * @ret character Mapped character - */ -static int bios_keymap ( unsigned int character ) { - struct key_mapping *mapping; - - for_each_table_entry ( mapping, KEYMAP ) { - if ( mapping->from == character ) - return mapping->to; - } - return character; -} - /** * Get character from BIOS console * @@ -387,7 +371,7 @@ static int bios_getchar ( void ) { /* If it's a normal character, just map and return it */ if ( character && ( character < 0x80 ) ) - return bios_keymap ( character ); + 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/core/keymap.c b/src/core/keymap.c new file mode 100644 index 000000000..a6707a2ce --- /dev/null +++ b/src/core/keymap.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or 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 + +/** @file + * + * Keyboard mappings + * + */ + +/** + * Remap a key + * + * @v character Character read from console + * @ret character Mapped character + */ +unsigned int key_remap ( unsigned int character ) { + struct key_mapping *mapping; + + /* Remap via table */ + for_each_table_entry ( mapping, KEYMAP ) { + if ( mapping->from == character ) { + character = mapping->to; + break; + } + } + + return character; +} diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index 0f1b0c656..62b3bb131 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -27,4 +27,6 @@ struct key_mapping { /** Define a keyboard mapping */ #define __keymap __table_entry ( KEYMAP, 01 ) +extern unsigned int key_remap ( unsigned int character ); + #endif /* _IPXE_KEYMAP_H */ -- cgit v1.2.3-55-g7522 From 0bbd8967830097b9141945ba960e90339c230ccb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 9 Feb 2022 15:43:42 +0000 Subject: [console] Handle remapping of scancode 86 The key with scancode 86 appears in the position between left shift and Z on a US keyboard, where it typically fails to exist entirely. Most US keyboard maps define this nonexistent key as generating "\|", with the notable exception of "loadkeys" which instead reports it as generating "<>". Both of these mapping choices duplicate keys that exist elsewhere in the map, which causes problems for our ASCII-based remapping mechanism. Work around these quirks by treating the key as generating "\|" with the high bit set, and making it subject to remapping. Where the BIOS generates "\|" as expected, this allows us to remap to the correct ASCII value. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/bios_console.c | 9 ++++++++ src/core/keymap.c | 3 +++ src/drivers/usb/usbkbd.c | 8 ++++++- src/drivers/usb/usbkbd.h | 1 + src/hci/keymap/keymap_al.c | 2 ++ src/hci/keymap/keymap_az.c | 2 ++ src/hci/keymap/keymap_by.c | 2 ++ src/hci/keymap/keymap_de.c | 2 ++ src/hci/keymap/keymap_dk.c | 2 ++ src/hci/keymap/keymap_es.c | 2 ++ src/hci/keymap/keymap_et.c | 2 ++ src/hci/keymap/keymap_fi.c | 2 ++ src/hci/keymap/keymap_fr.c | 2 ++ src/hci/keymap/keymap_gr.c | 2 ++ src/hci/keymap/keymap_il.c | 2 ++ src/hci/keymap/keymap_it.c | 2 ++ src/hci/keymap/keymap_mk.c | 2 ++ src/hci/keymap/keymap_nl.c | 2 ++ src/hci/keymap/keymap_no-latin1.c | 2 ++ src/hci/keymap/keymap_no.c | 2 ++ src/hci/keymap/keymap_pl.c | 2 ++ src/hci/keymap/keymap_pt.c | 2 ++ src/hci/keymap/keymap_ru.c | 2 ++ src/hci/keymap/keymap_sg.c | 2 ++ src/hci/keymap/keymap_sr-latin.c | 2 ++ src/hci/keymap/keymap_ua.c | 2 ++ src/include/ipxe/keymap.h | 3 +++ src/util/genkeymap.py | 31 +++++++++++++++++++++++----- 28 files changed, 93 insertions(+), 6 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 443513e9e..438a01d07 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -68,6 +68,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #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 @@ -383,6 +390,8 @@ static int bios_getchar ( void ) { if ( character && ( character < 0x80 ) ) { if ( scancode < SCANCODE_RSHIFT ) { return key_remap ( character ); + } else if ( scancode == SCANCODE_NON_US ) { + return key_remap ( character | KEYMAP_PSEUDO ); } else { return character; } diff --git a/src/core/keymap.c b/src/core/keymap.c index a6707a2ce..5054e4769 100644 --- a/src/core/keymap.c +++ b/src/core/keymap.c @@ -48,5 +48,8 @@ unsigned int key_remap ( unsigned int character ) { } } + /* Clear pseudo key flag */ + character &= ~KEYMAP_PSEUDO; + return character; } diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index ba4b2d4d7..6954cd69b 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -114,13 +114,19 @@ 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 ) + if ( ( keycode < USBKBD_KEY_CAPS_LOCK ) || + ( keycode == USBKBD_KEY_NON_US ) ) { key = key_remap ( key ); + } /* Handle upper/lower case and Ctrl- */ if ( islower ( key ) ) { diff --git a/src/drivers/usb/usbkbd.h b/src/drivers/usb/usbkbd.h index cedebfe71..1a3fea1ba 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/hci/keymap/keymap_al.c b/src/hci/keymap/keymap_al.c index e4418361b..6b4663489 100644 --- a/src/hci/keymap/keymap_al.c +++ b/src/hci/keymap/keymap_al.c @@ -30,4 +30,6 @@ struct key_mapping al_mapping[] __keymap = { { 0x7c, 0x7d }, /* '|' => '}' */ { 0x7d, 0x27 }, /* '}' => '\'' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_az.c b/src/hci/keymap/keymap_az.c index 525ab2336..91a243460 100644 --- a/src/hci/keymap/keymap_az.c +++ b/src/hci/keymap/keymap_az.c @@ -21,4 +21,6 @@ struct key_mapping az_mapping[] __keymap = { { 0x40, 0x22 }, /* '@' => '"' */ { 0x5e, 0x3a }, /* '^' => ':' */ { 0x7c, 0x2f }, /* '|' => '/' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_by.c b/src/hci/keymap/keymap_by.c index 514d0b532..43fb746bf 100644 --- a/src/hci/keymap/keymap_by.c +++ b/src/hci/keymap/keymap_by.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "by" keyboard mapping */ struct key_mapping by_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_de.c b/src/hci/keymap/keymap_de.c index 2559e1538..85574d487 100644 --- a/src/hci/keymap/keymap_de.c +++ b/src/hci/keymap/keymap_de.c @@ -36,4 +36,6 @@ struct key_mapping de_mapping[] __keymap = { { 0x7a, 0x79 }, /* 'z' => 'y' */ { 0x7c, 0x27 }, /* '|' => '\'' */ { 0x7d, 0x2a }, /* '}' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_dk.c b/src/hci/keymap/keymap_dk.c index 05110dc89..4e1d5a739 100644 --- a/src/hci/keymap/keymap_dk.c +++ b/src/hci/keymap/keymap_dk.c @@ -28,4 +28,6 @@ struct key_mapping dk_mapping[] __keymap = { { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x7c, 0x2a }, /* '|' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_es.c b/src/hci/keymap/keymap_es.c index 51dedfff7..91327ea51 100644 --- a/src/hci/keymap/keymap_es.c +++ b/src/hci/keymap/keymap_es.c @@ -28,4 +28,6 @@ struct key_mapping es_mapping[] __keymap = { { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x7d, 0x2a }, /* '}' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_et.c b/src/hci/keymap/keymap_et.c index dd0f879b1..493ec93d4 100644 --- a/src/hci/keymap/keymap_et.c +++ b/src/hci/keymap/keymap_et.c @@ -26,4 +26,6 @@ struct key_mapping et_mapping[] __keymap = { { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x7c, 0x2a }, /* '|' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_fi.c b/src/hci/keymap/keymap_fi.c index c489bf0e5..18f48d47e 100644 --- a/src/hci/keymap/keymap_fi.c +++ b/src/hci/keymap/keymap_fi.c @@ -26,4 +26,6 @@ struct key_mapping fi_mapping[] __keymap = { { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x7c, 0x2a }, /* '|' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_fr.c b/src/hci/keymap/keymap_fr.c index 8f3b4999d..808cd7945 100644 --- a/src/hci/keymap/keymap_fr.c +++ b/src/hci/keymap/keymap_fr.c @@ -57,4 +57,6 @@ struct key_mapping fr_mapping[] __keymap = { { 0x71, 0x61 }, /* 'q' => 'a' */ { 0x77, 0x7a }, /* 'w' => 'z' */ { 0x7a, 0x77 }, /* 'z' => 'w' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_gr.c b/src/hci/keymap/keymap_gr.c index 42b6418e8..b48142e5e 100644 --- a/src/hci/keymap/keymap_gr.c +++ b/src/hci/keymap/keymap_gr.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "gr" keyboard mapping */ struct key_mapping gr_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_il.c b/src/hci/keymap/keymap_il.c index f631f7ac9..78e7fa970 100644 --- a/src/hci/keymap/keymap_il.c +++ b/src/hci/keymap/keymap_il.c @@ -24,4 +24,6 @@ struct key_mapping il_mapping[] __keymap = { { 0x60, 0x3b }, /* '`' => ';' */ { 0x7b, 0x7d }, /* '{' => '}' */ { 0x7d, 0x7b }, /* '}' => '{' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_it.c b/src/hci/keymap/keymap_it.c index d96102c9e..5a8e2b38d 100644 --- a/src/hci/keymap/keymap_it.c +++ b/src/hci/keymap/keymap_it.c @@ -30,4 +30,6 @@ struct key_mapping it_mapping[] __keymap = { { 0x60, 0x5c }, /* '`' => '\\' */ { 0x7d, 0x2a }, /* '}' => '*' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_mk.c b/src/hci/keymap/keymap_mk.c index 8f5060778..9f2cff78b 100644 --- a/src/hci/keymap/keymap_mk.c +++ b/src/hci/keymap/keymap_mk.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "mk" keyboard mapping */ struct key_mapping mk_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_nl.c b/src/hci/keymap/keymap_nl.c index 2a0fbbcbd..d248fc8ae 100644 --- a/src/hci/keymap/keymap_nl.c +++ b/src/hci/keymap/keymap_nl.c @@ -33,4 +33,6 @@ struct key_mapping nl_mapping[] __keymap = { { 0x60, 0x40 }, /* '`' => '@' */ { 0x7c, 0x3e }, /* '|' => '>' */ { 0x7d, 0x7c }, /* '}' => '|' */ + { 0xdc, 0x5d }, /* Pseudo-'\\' => ']' */ + { 0xfc, 0x5b }, /* Pseudo-'|' => '[' */ }; diff --git a/src/hci/keymap/keymap_no-latin1.c b/src/hci/keymap/keymap_no-latin1.c index 655e4cef7..d5a721a90 100644 --- a/src/hci/keymap/keymap_no-latin1.c +++ b/src/hci/keymap/keymap_no-latin1.c @@ -32,4 +32,6 @@ struct key_mapping no_latin1_mapping[] __keymap = { { 0x60, 0x7c }, /* '`' => '|' */ { 0x7c, 0x2a }, /* '|' => '*' */ { 0x7d, 0x5e }, /* '}' => '^' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_no.c b/src/hci/keymap/keymap_no.c index 7a2df7c5a..b6190da4a 100644 --- a/src/hci/keymap/keymap_no.c +++ b/src/hci/keymap/keymap_no.c @@ -30,4 +30,6 @@ struct key_mapping no_mapping[] __keymap = { { 0x5f, 0x3f }, /* '_' => '?' */ { 0x60, 0x7c }, /* '`' => '|' */ { 0x7c, 0x2a }, /* '|' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_pl.c b/src/hci/keymap/keymap_pl.c index 51822e072..224fbde28 100644 --- a/src/hci/keymap/keymap_pl.c +++ b/src/hci/keymap/keymap_pl.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "pl" keyboard mapping */ struct key_mapping pl_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_pt.c b/src/hci/keymap/keymap_pt.c index b993902af..6d850fee8 100644 --- a/src/hci/keymap/keymap_pt.c +++ b/src/hci/keymap/keymap_pt.c @@ -29,4 +29,6 @@ struct key_mapping pt_mapping[] __keymap = { { 0x60, 0x5c }, /* '`' => '\\' */ { 0x7b, 0x2a }, /* '{' => '*' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_ru.c b/src/hci/keymap/keymap_ru.c index c120ffd82..f7611c30a 100644 --- a/src/hci/keymap/keymap_ru.c +++ b/src/hci/keymap/keymap_ru.c @@ -13,4 +13,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "ru" keyboard mapping */ struct key_mapping ru_mapping[] __keymap = { { 0x0d, 0x0a }, /* Ctrl-M => Ctrl-J */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_sg.c b/src/hci/keymap/keymap_sg.c index 0b0820929..9a515c745 100644 --- a/src/hci/keymap/keymap_sg.c +++ b/src/hci/keymap/keymap_sg.c @@ -38,4 +38,6 @@ struct key_mapping sg_mapping[] __keymap = { { 0x7a, 0x79 }, /* 'z' => 'y' */ { 0x7c, 0x24 }, /* '|' => '$' */ { 0x7d, 0x21 }, /* '}' => '!' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_sr-latin.c b/src/hci/keymap/keymap_sr-latin.c index 9d76e8a6c..1d4588733 100644 --- a/src/hci/keymap/keymap_sr-latin.c +++ b/src/hci/keymap/keymap_sr-latin.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "sr-latin" keyboard mapping */ struct key_mapping sr_latin_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_ua.c b/src/hci/keymap/keymap_ua.c index 1106a8b28..50f2e184d 100644 --- a/src/hci/keymap/keymap_ua.c +++ b/src/hci/keymap/keymap_ua.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "ua" keyboard mapping */ struct key_mapping ua_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index 62b3bb131..93c9e7314 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -27,6 +27,9 @@ struct key_mapping { /** Define a keyboard mapping */ #define __keymap __table_entry ( KEYMAP, 01 ) +/** Pseudo key flag */ +#define KEYMAP_PSEUDO 0x80 + extern unsigned int key_remap ( unsigned int character ); #endif /* _IPXE_KEYMAP_H */ diff --git a/src/util/genkeymap.py b/src/util/genkeymap.py index 1bb494f83..081e314cc 100755 --- a/src/util/genkeymap.py +++ b/src/util/genkeymap.py @@ -219,12 +219,28 @@ class KeyMapping(UserDict[KeyModifiers, Sequence[Key]]): class BiosKeyMapping(KeyMapping): - """Keyboard mapping as used by the BIOS""" + """Keyboard mapping 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()) @@ -251,12 +267,13 @@ class KeyRemapping: raw = {source: self.target[key.modifiers][key.keycode].ascii for source, key in self.source.inverse.items()} # Eliminate any null mappings, mappings that attempt to remap - # the backspace key, or identity mappings + # the backspace key, or mappings that would become identity + # mappings after clearing the high bit table = {source: target for source, target in raw.items() if target and ord(source) != 0x7f and ord(target) != 0x7f - and ord(source) != ord(target)} + and ord(source) & ~BiosKeyMapping.KEY_PSEUDO != ord(target)} # Recursively delete any mappings that would produce # unreachable alphanumerics (e.g. the "il" keymap, which maps # away the whole lower-case alphabet) @@ -281,13 +298,17 @@ class KeyRemapping: """C variable name""" return re.sub(r'\W', '_', self.name) + "_mapping" - @staticmethod - def ascii_name(char: str) -> str: + @classmethod + def ascii_name(cls, char: str) -> str: """ASCII character name""" if char == '\\': name = "'\\\\'" elif char == '\'': name = "'\\\''" + elif ord(char) & BiosKeyMapping.KEY_PSEUDO: + name = "Pseudo-%s" % cls.ascii_name( + chr(ord(char) & ~BiosKeyMapping.KEY_PSEUDO) + ) elif char.isprintable(): name = "'%s'" % char elif ord(char) <= 0x1a: -- cgit v1.2.3-55-g7522 From 1150321595c44acfac2b2c56590d4d7f1d2ad70c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Feb 2022 13:13:37 +0000 Subject: [tables] Add ability to declare static table start and end markers The compound statement expression within __table_entries() prevents the use of top-level declarations such as static struct thing *things = table_start ( THINGS ); Define TABLE_START() and TABLE_END() macros that can be used as: static TABLE_START ( things_start, THINGS ); static struct thing *things = things_start; Signed-off-by: Michael Brown --- src/include/ipxe/tables.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/tables.h b/src/include/ipxe/tables.h index 28a87da96..de5b1f297 100644 --- a/src/include/ipxe/tables.h +++ b/src/include/ipxe/tables.h @@ -252,6 +252,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); __attribute__ (( unused )); \ __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 * @@ -270,6 +281,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 * @@ -288,6 +307,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 * -- cgit v1.2.3-55-g7522 From 871dd236d4aff66e871c25addcf522fe75a4ccd7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Feb 2022 13:22:48 +0000 Subject: [console] Allow for named keyboard mappings Separate the concept of a keyboard mapping from a list of remapped keys, to allow for the possibility of supporting multiple keyboard mappings at runtime. Signed-off-by: Michael Brown --- src/core/keymap.c | 14 ++-- src/hci/keymap/keymap_al.c | 11 ++- src/hci/keymap/keymap_az.c | 11 ++- src/hci/keymap/keymap_by.c | 11 ++- src/hci/keymap/keymap_cf.c | 11 ++- src/hci/keymap/keymap_cz.c | 11 ++- src/hci/keymap/keymap_de.c | 11 ++- src/hci/keymap/keymap_dk.c | 11 ++- src/hci/keymap/keymap_es.c | 11 ++- src/hci/keymap/keymap_et.c | 11 ++- src/hci/keymap/keymap_fi.c | 11 ++- src/hci/keymap/keymap_fr.c | 11 ++- src/hci/keymap/keymap_gr.c | 11 ++- src/hci/keymap/keymap_hu.c | 11 ++- src/hci/keymap/keymap_il.c | 11 ++- src/hci/keymap/keymap_it.c | 11 ++- src/hci/keymap/keymap_lt.c | 11 ++- src/hci/keymap/keymap_mk.c | 11 ++- src/hci/keymap/keymap_mt.c | 11 ++- src/hci/keymap/keymap_nl.c | 11 ++- src/hci/keymap/keymap_no-latin1.c | 11 ++- src/hci/keymap/keymap_no.c | 11 ++- src/hci/keymap/keymap_pl.c | 11 ++- src/hci/keymap/keymap_pt.c | 11 ++- src/hci/keymap/keymap_ro.c | 11 ++- src/hci/keymap/keymap_ru.c | 11 ++- src/hci/keymap/keymap_sg.c | 11 ++- src/hci/keymap/keymap_sr-latin.c | 11 ++- src/hci/keymap/keymap_ua.c | 11 ++- src/hci/keymap/keymap_uk.c | 11 ++- src/hci/keymap/keymap_us.c | 11 ++- src/include/ipxe/keymap.h | 19 +++++- src/util/genkeymap.py | 140 +++++++++++++++++++++----------------- 33 files changed, 373 insertions(+), 130 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/core/keymap.c b/src/core/keymap.c index 5054e4769..c0953967a 100644 --- a/src/core/keymap.c +++ b/src/core/keymap.c @@ -31,6 +31,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +/** Default keyboard mapping */ +static TABLE_START ( keymap_start, KEYMAP ); + +/** Current keyboard mapping */ +static struct keymap *keymap = keymap_start; + /** * Remap a key * @@ -38,12 +44,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @ret character Mapped character */ unsigned int key_remap ( unsigned int character ) { - struct key_mapping *mapping; + struct keymap_key *key; /* Remap via table */ - for_each_table_entry ( mapping, KEYMAP ) { - if ( mapping->from == character ) { - character = mapping->to; + for ( key = keymap->basic ; key->from ; key++ ) { + if ( key->from == character ) { + character = key->to; break; } } diff --git a/src/hci/keymap/keymap_al.c b/src/hci/keymap/keymap_al.c index 6b4663489..a3df385a9 100644 --- a/src/hci/keymap/keymap_al.c +++ b/src/hci/keymap/keymap_al.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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 */ @@ -32,4 +32,11 @@ struct key_mapping al_mapping[] __keymap = { { 0x7e, 0x7c }, /* '~' => '|' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "al" keyboard map */ +struct keymap al_keymap __keymap = { + .name = "al", + .basic = al_basic, }; diff --git a/src/hci/keymap/keymap_az.c b/src/hci/keymap/keymap_az.c index 91a243460..7b382ca8b 100644 --- a/src/hci/keymap/keymap_az.c +++ b/src/hci/keymap/keymap_az.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "az" keyboard mapping */ -struct key_mapping az_mapping[] __keymap = { +/** "az" basic remapping */ +static struct keymap_key az_basic[] = { { 0x1e, 0x36 }, /* 0x1e => '6' */ { 0x24, 0x3b }, /* '$' => ';' */ { 0x26, 0x3f }, /* '&' => '?' */ @@ -23,4 +23,11 @@ struct key_mapping az_mapping[] __keymap = { { 0x7c, 0x2f }, /* '|' => '/' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "az" keyboard map */ +struct keymap az_keymap __keymap = { + .name = "az", + .basic = az_basic, }; diff --git a/src/hci/keymap/keymap_by.c b/src/hci/keymap/keymap_by.c index 43fb746bf..4127609e3 100644 --- a/src/hci/keymap/keymap_by.c +++ b/src/hci/keymap/keymap_by.c @@ -10,8 +10,15 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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" keyboard map */ +struct keymap by_keymap __keymap = { + .name = "by", + .basic = by_basic, }; diff --git a/src/hci/keymap/keymap_cf.c b/src/hci/keymap/keymap_cf.c index d7e63b9b1..0bbe89659 100644 --- a/src/hci/keymap/keymap_cf.c +++ b/src/hci/keymap/keymap_cf.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "cf" keyboard mapping */ -struct key_mapping cf_mapping[] __keymap = { +/** "cf" basic remapping */ +static struct keymap_key cf_basic[] = { { 0x23, 0x2f }, /* '#' => '/' */ { 0x3c, 0x27 }, /* '<' => '\'' */ { 0x3e, 0x2e }, /* '>' => '.' */ @@ -21,4 +21,11 @@ struct key_mapping cf_mapping[] __keymap = { { 0x60, 0x23 }, /* '`' => '#' */ { 0x7c, 0x3e }, /* '|' => '>' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0, 0 } +}; + +/** "cf" keyboard map */ +struct keymap cf_keymap __keymap = { + .name = "cf", + .basic = cf_basic, }; diff --git a/src/hci/keymap/keymap_cz.c b/src/hci/keymap/keymap_cz.c index 2b4a21592..8655d5b68 100644 --- a/src/hci/keymap/keymap_cz.c +++ b/src/hci/keymap/keymap_cz.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "cz" keyboard mapping */ -struct key_mapping cz_mapping[] __keymap = { +/** "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 */ @@ -43,4 +43,11 @@ struct key_mapping cz_mapping[] __keymap = { { 0x7b, 0x2f }, /* '{' => '/' */ { 0x7c, 0x27 }, /* '|' => '\'' */ { 0x7d, 0x28 }, /* '}' => '(' */ + { 0, 0 } +}; + +/** "cz" keyboard map */ +struct keymap cz_keymap __keymap = { + .name = "cz", + .basic = cz_basic, }; diff --git a/src/hci/keymap/keymap_de.c b/src/hci/keymap/keymap_de.c index 85574d487..4d23c2e60 100644 --- a/src/hci/keymap/keymap_de.c +++ b/src/hci/keymap/keymap_de.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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 */ { 0x1c, 0x23 }, /* 0x1c => '#' */ @@ -38,4 +38,11 @@ struct key_mapping de_mapping[] __keymap = { { 0x7d, 0x2a }, /* '}' => '*' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "de" keyboard map */ +struct keymap de_keymap __keymap = { + .name = "de", + .basic = de_basic, }; diff --git a/src/hci/keymap/keymap_dk.c b/src/hci/keymap/keymap_dk.c index 4e1d5a739..100246bf5 100644 --- a/src/hci/keymap/keymap_dk.c +++ b/src/hci/keymap/keymap_dk.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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 }, /* '&' => '/' */ @@ -30,4 +30,11 @@ struct key_mapping dk_mapping[] __keymap = { { 0x7c, 0x2a }, /* '|' => '*' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "dk" keyboard map */ +struct keymap dk_keymap __keymap = { + .name = "dk", + .basic = dk_basic, }; diff --git a/src/hci/keymap/keymap_es.c b/src/hci/keymap/keymap_es.c index 91327ea51..2f4b86c47 100644 --- a/src/hci/keymap/keymap_es.c +++ b/src/hci/keymap/keymap_es.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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 }, /* '&' => '/' */ @@ -30,4 +30,11 @@ struct key_mapping es_mapping[] __keymap = { { 0x7d, 0x2a }, /* '}' => '*' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "es" keyboard map */ +struct keymap es_keymap __keymap = { + .name = "es", + .basic = es_basic, }; diff --git a/src/hci/keymap/keymap_et.c b/src/hci/keymap/keymap_et.c index 493ec93d4..a8bf46ebc 100644 --- a/src/hci/keymap/keymap_et.c +++ b/src/hci/keymap/keymap_et.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "et" keyboard mapping */ -struct key_mapping et_mapping[] __keymap = { +/** "et" basic remapping */ +static struct keymap_key et_basic[] = { { 0x26, 0x2f }, /* '&' => '/' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ @@ -28,4 +28,11 @@ struct key_mapping et_mapping[] __keymap = { { 0x7c, 0x2a }, /* '|' => '*' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "et" keyboard map */ +struct keymap et_keymap __keymap = { + .name = "et", + .basic = et_basic, }; diff --git a/src/hci/keymap/keymap_fi.c b/src/hci/keymap/keymap_fi.c index 18f48d47e..eb75eb4dc 100644 --- a/src/hci/keymap/keymap_fi.c +++ b/src/hci/keymap/keymap_fi.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "fi" keyboard mapping */ -struct key_mapping fi_mapping[] __keymap = { +/** "fi" basic remapping */ +static struct keymap_key fi_basic[] = { { 0x26, 0x2f }, /* '&' => '/' */ { 0x28, 0x29 }, /* '(' => ')' */ { 0x29, 0x3d }, /* ')' => '=' */ @@ -28,4 +28,11 @@ struct key_mapping fi_mapping[] __keymap = { { 0x7c, 0x2a }, /* '|' => '*' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "fi" keyboard map */ +struct keymap fi_keymap __keymap = { + .name = "fi", + .basic = fi_basic, }; diff --git a/src/hci/keymap/keymap_fr.c b/src/hci/keymap/keymap_fr.c index 808cd7945..523254ee5 100644 --- a/src/hci/keymap/keymap_fr.c +++ b/src/hci/keymap/keymap_fr.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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 */ @@ -59,4 +59,11 @@ struct key_mapping fr_mapping[] __keymap = { { 0x7a, 0x77 }, /* 'z' => 'w' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "fr" keyboard map */ +struct keymap fr_keymap __keymap = { + .name = "fr", + .basic = fr_basic, }; diff --git a/src/hci/keymap/keymap_gr.c b/src/hci/keymap/keymap_gr.c index b48142e5e..16a2a7032 100644 --- a/src/hci/keymap/keymap_gr.c +++ b/src/hci/keymap/keymap_gr.c @@ -10,8 +10,15 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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" keyboard map */ +struct keymap gr_keymap __keymap = { + .name = "gr", + .basic = gr_basic, }; diff --git a/src/hci/keymap/keymap_hu.c b/src/hci/keymap/keymap_hu.c index a2eadbc62..5e407161f 100644 --- a/src/hci/keymap/keymap_hu.c +++ b/src/hci/keymap/keymap_hu.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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' */ @@ -32,4 +32,11 @@ struct key_mapping hu_mapping[] __keymap = { { 0x60, 0x30 }, /* '`' => '0' */ { 0x79, 0x7a }, /* 'y' => 'z' */ { 0x7a, 0x79 }, /* 'z' => 'y' */ + { 0, 0 } +}; + +/** "hu" keyboard map */ +struct keymap hu_keymap __keymap = { + .name = "hu", + .basic = hu_basic, }; diff --git a/src/hci/keymap/keymap_il.c b/src/hci/keymap/keymap_il.c index 78e7fa970..de5e639ca 100644 --- a/src/hci/keymap/keymap_il.c +++ b/src/hci/keymap/keymap_il.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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 }, /* '(' => ')' */ @@ -26,4 +26,11 @@ struct key_mapping il_mapping[] __keymap = { { 0x7d, 0x7b }, /* '}' => '{' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "il" keyboard map */ +struct keymap il_keymap __keymap = { + .name = "il", + .basic = il_basic, }; diff --git a/src/hci/keymap/keymap_it.c b/src/hci/keymap/keymap_it.c index 5a8e2b38d..a4921020a 100644 --- a/src/hci/keymap/keymap_it.c +++ b/src/hci/keymap/keymap_it.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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 }, /* '(' => ')' */ @@ -32,4 +32,11 @@ struct key_mapping it_mapping[] __keymap = { { 0x7e, 0x7c }, /* '~' => '|' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "it" keyboard map */ +struct keymap it_keymap __keymap = { + .name = "it", + .basic = it_basic, }; diff --git a/src/hci/keymap/keymap_lt.c b/src/hci/keymap/keymap_lt.c index 3e99d8c6c..333241d21 100644 --- a/src/hci/keymap/keymap_lt.c +++ b/src/hci/keymap/keymap_lt.c @@ -10,6 +10,13 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "lt" keyboard mapping */ -struct key_mapping lt_mapping[] __keymap = { +/** "lt" basic remapping */ +static struct keymap_key lt_basic[] = { + { 0, 0 } +}; + +/** "lt" keyboard map */ +struct keymap lt_keymap __keymap = { + .name = "lt", + .basic = lt_basic, }; diff --git a/src/hci/keymap/keymap_mk.c b/src/hci/keymap/keymap_mk.c index 9f2cff78b..1656fb99c 100644 --- a/src/hci/keymap/keymap_mk.c +++ b/src/hci/keymap/keymap_mk.c @@ -10,8 +10,15 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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" keyboard map */ +struct keymap mk_keymap __keymap = { + .name = "mk", + .basic = mk_basic, }; diff --git a/src/hci/keymap/keymap_mt.c b/src/hci/keymap/keymap_mt.c index dfca2ff66..ebff8506f 100644 --- a/src/hci/keymap/keymap_mt.c +++ b/src/hci/keymap/keymap_mt.c @@ -10,11 +10,18 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "mt" keyboard mapping */ -struct key_mapping mt_mapping[] __keymap = { +/** "mt" basic remapping */ +static struct keymap_key mt_basic[] = { { 0x1c, 0x1e }, /* 0x1c => 0x1e */ { 0x22, 0x40 }, /* '"' => '@' */ { 0x40, 0x22 }, /* '@' => '"' */ { 0x5c, 0x23 }, /* '\\' => '#' */ { 0x7c, 0x7e }, /* '|' => '~' */ + { 0, 0 } +}; + +/** "mt" keyboard map */ +struct keymap mt_keymap __keymap = { + .name = "mt", + .basic = mt_basic, }; diff --git a/src/hci/keymap/keymap_nl.c b/src/hci/keymap/keymap_nl.c index d248fc8ae..2172e045f 100644 --- a/src/hci/keymap/keymap_nl.c +++ b/src/hci/keymap/keymap_nl.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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' */ @@ -35,4 +35,11 @@ struct key_mapping nl_mapping[] __keymap = { { 0x7d, 0x7c }, /* '}' => '|' */ { 0xdc, 0x5d }, /* Pseudo-'\\' => ']' */ { 0xfc, 0x5b }, /* Pseudo-'|' => '[' */ + { 0, 0 } +}; + +/** "nl" keyboard map */ +struct keymap nl_keymap __keymap = { + .name = "nl", + .basic = nl_basic, }; diff --git a/src/hci/keymap/keymap_no-latin1.c b/src/hci/keymap/keymap_no-latin1.c index d5a721a90..65f30beae 100644 --- a/src/hci/keymap/keymap_no-latin1.c +++ b/src/hci/keymap/keymap_no-latin1.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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 }, /* '(' => ')' */ @@ -34,4 +34,11 @@ struct key_mapping no_latin1_mapping[] __keymap = { { 0x7d, 0x5e }, /* '}' => '^' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "no-latin1" keyboard map */ +struct keymap no_latin1_keymap __keymap = { + .name = "no-latin1", + .basic = no_latin1_basic, }; diff --git a/src/hci/keymap/keymap_no.c b/src/hci/keymap/keymap_no.c index b6190da4a..d3d06bce3 100644 --- a/src/hci/keymap/keymap_no.c +++ b/src/hci/keymap/keymap_no.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "no" keyboard mapping */ -struct key_mapping no_mapping[] __keymap = { +/** "no" basic remapping */ +static struct keymap_key no_basic[] = { { 0x1c, 0x27 }, /* 0x1c => '\'' */ { 0x1e, 0x36 }, /* 0x1e => '6' */ { 0x26, 0x2f }, /* '&' => '/' */ @@ -32,4 +32,11 @@ struct key_mapping no_mapping[] __keymap = { { 0x7c, 0x2a }, /* '|' => '*' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "no" keyboard map */ +struct keymap no_keymap __keymap = { + .name = "no", + .basic = no_basic, }; diff --git a/src/hci/keymap/keymap_pl.c b/src/hci/keymap/keymap_pl.c index 224fbde28..a23c01f2c 100644 --- a/src/hci/keymap/keymap_pl.c +++ b/src/hci/keymap/keymap_pl.c @@ -10,8 +10,15 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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" keyboard map */ +struct keymap pl_keymap __keymap = { + .name = "pl", + .basic = pl_basic, }; diff --git a/src/hci/keymap/keymap_pt.c b/src/hci/keymap/keymap_pt.c index 6d850fee8..c065fd76f 100644 --- a/src/hci/keymap/keymap_pt.c +++ b/src/hci/keymap/keymap_pt.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "pt" keyboard mapping */ -struct key_mapping pt_mapping[] __keymap = { +/** "pt" basic remapping */ +static struct keymap_key pt_basic[] = { { 0x1e, 0x36 }, /* 0x1e => '6' */ { 0x26, 0x2f }, /* '&' => '/' */ { 0x28, 0x29 }, /* '(' => ')' */ @@ -31,4 +31,11 @@ struct key_mapping pt_mapping[] __keymap = { { 0x7e, 0x7c }, /* '~' => '|' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "pt" keyboard map */ +struct keymap pt_keymap __keymap = { + .name = "pt", + .basic = pt_basic, }; diff --git a/src/hci/keymap/keymap_ro.c b/src/hci/keymap/keymap_ro.c index 0eef7d534..334cf6080 100644 --- a/src/hci/keymap/keymap_ro.c +++ b/src/hci/keymap/keymap_ro.c @@ -10,6 +10,13 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "ro" keyboard mapping */ -struct key_mapping ro_mapping[] __keymap = { +/** "ro" basic remapping */ +static struct keymap_key ro_basic[] = { + { 0, 0 } +}; + +/** "ro" keyboard map */ +struct keymap ro_keymap __keymap = { + .name = "ro", + .basic = ro_basic, }; diff --git a/src/hci/keymap/keymap_ru.c b/src/hci/keymap/keymap_ru.c index f7611c30a..a08b115ed 100644 --- a/src/hci/keymap/keymap_ru.c +++ b/src/hci/keymap/keymap_ru.c @@ -10,9 +10,16 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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" keyboard map */ +struct keymap ru_keymap __keymap = { + .name = "ru", + .basic = ru_basic, }; diff --git a/src/hci/keymap/keymap_sg.c b/src/hci/keymap/keymap_sg.c index 9a515c745..152c5d631 100644 --- a/src/hci/keymap/keymap_sg.c +++ b/src/hci/keymap/keymap_sg.c @@ -10,8 +10,8 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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 }, /* '!' => '+' */ @@ -40,4 +40,11 @@ struct key_mapping sg_mapping[] __keymap = { { 0x7d, 0x21 }, /* '}' => '!' */ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "sg" keyboard map */ +struct keymap sg_keymap __keymap = { + .name = "sg", + .basic = sg_basic, }; diff --git a/src/hci/keymap/keymap_sr-latin.c b/src/hci/keymap/keymap_sr-latin.c index 1d4588733..ec5efdc89 100644 --- a/src/hci/keymap/keymap_sr-latin.c +++ b/src/hci/keymap/keymap_sr-latin.c @@ -10,8 +10,15 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "sr-latin" keyboard mapping */ -struct key_mapping sr_latin_mapping[] __keymap = { +/** "sr-latin" basic remapping */ +static struct keymap_key sr_latin_basic[] = { { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ + { 0, 0 } +}; + +/** "sr-latin" keyboard map */ +struct keymap sr_latin_keymap __keymap = { + .name = "sr-latin", + .basic = sr_latin_basic, }; diff --git a/src/hci/keymap/keymap_ua.c b/src/hci/keymap/keymap_ua.c index 50f2e184d..b4199cdad 100644 --- a/src/hci/keymap/keymap_ua.c +++ b/src/hci/keymap/keymap_ua.c @@ -10,8 +10,15 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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" keyboard map */ +struct keymap ua_keymap __keymap = { + .name = "ua", + .basic = ua_basic, }; diff --git a/src/hci/keymap/keymap_uk.c b/src/hci/keymap/keymap_uk.c index 6550d8ee5..156b42dff 100644 --- a/src/hci/keymap/keymap_uk.c +++ b/src/hci/keymap/keymap_uk.c @@ -10,10 +10,17 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "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" keyboard map */ +struct keymap uk_keymap __keymap = { + .name = "uk", + .basic = uk_basic, }; diff --git a/src/hci/keymap/keymap_us.c b/src/hci/keymap/keymap_us.c index 73d01a30a..5d78f80a2 100644 --- a/src/hci/keymap/keymap_us.c +++ b/src/hci/keymap/keymap_us.c @@ -10,6 +10,13 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); #include -/** "us" keyboard mapping */ -struct key_mapping us_mapping[] __keymap = { +/** "us" basic remapping */ +static struct keymap_key us_basic[] = { + { 0, 0 } +}; + +/** "us" keyboard map */ +struct keymap us_keymap __keymap = { + .name = "us", + .basic = us_basic, }; diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index 93c9e7314..a64ab9cd4 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -13,16 +13,29 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** 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; +}; + /** Keyboard mapping table */ -#define KEYMAP __table ( struct key_mapping, "keymap" ) +#define KEYMAP __table ( struct keymap, "keymap" ) /** Define a keyboard mapping */ #define __keymap __table_entry ( KEYMAP, 01 ) diff --git a/src/util/genkeymap.py b/src/util/genkeymap.py index 081e314cc..d38552eb4 100755 --- a/src/util/genkeymap.py +++ b/src/util/genkeymap.py @@ -79,7 +79,7 @@ class KeyModifiers(Flag): return 3 + bin(self.value).count('1') -@dataclass +@dataclass(frozen=True) class Key: """A single key definition""" @@ -120,8 +120,8 @@ class Key: return None -class KeyMapping(UserDict[KeyModifiers, Sequence[Key]]): - """A keyboard mapping""" +class KeyLayout(UserDict[KeyModifiers, Sequence[Key]]): + """A keyboard layout""" BKEYMAP_MAGIC: ClassVar[bytes] = b'bkeymap' """Magic signature for output produced by 'loadkeys -b'""" @@ -163,16 +163,16 @@ class KeyMapping(UserDict[KeyModifiers, Sequence[Key]]): @property def unshifted(self): - """Basic unshifted key mapping""" + """Basic unshifted keyboard layout""" return self[KeyModifiers.NONE] @property def shifted(self): - """Basic shifted key mapping""" + """Basic shifted keyboard layout""" return self[KeyModifiers.SHIFT] @classmethod - def load(cls, name: str) -> KeyMapping: + 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): @@ -181,21 +181,21 @@ class KeyMapping(UserDict[KeyModifiers, Sequence[Key]]): included = bkeymap[:cls.MAX_NR_KEYMAPS] if len(included) != cls.MAX_NR_KEYMAPS: raise ValueError("Invalid bkeymap inclusion list") - keymaps = bkeymap[cls.MAX_NR_KEYMAPS:] + 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) - keymap = keymaps[:fmt.size] - if len(keymap) != fmt.size: + 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(keymap)) + for keycode, keysym in enumerate(fmt.unpack(bkeylist)) ] - keymaps = keymaps[len(keymap):] - if keymaps: + 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: @@ -218,8 +218,8 @@ class KeyMapping(UserDict[KeyModifiers, Sequence[Key]]): } -class BiosKeyMapping(KeyMapping): - """Keyboard mapping as used by the BIOS +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 "\\|" @@ -247,22 +247,56 @@ class BiosKeyMapping(KeyMapping): return inverse +class KeymapKeys(UserDict[str, 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() + ) + '\t{ 0, 0 }\n}' + + @dataclass -class KeyRemapping: - """A keyboard remapping""" +class Keymap: + """An iPXE keyboard mapping""" name: str """Mapping name""" - source: KeyMapping - """Source keyboard mapping""" + source: KeyLayout + """Source keyboard layout""" - target: KeyMapping - """Target keyboard mapping""" + target: KeyLayout + """Target keyboard layout""" @property - def ascii(self) -> MutableMapping[str, str]: - """Remapped ASCII key table""" + 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()} @@ -273,7 +307,7 @@ class KeyRemapping: if target and ord(source) != 0x7f and ord(target) != 0x7f - and ord(source) & ~BiosKeyMapping.KEY_PSEUDO != ord(target)} + and ord(source) & ~BiosKeyLayout.KEY_PSEUDO != ord(target)} # Recursively delete any mappings that would produce # unreachable alphanumerics (e.g. the "il" keymap, which maps # away the whole lower-case alphabet) @@ -291,35 +325,17 @@ class KeyRemapping: if digits not in (shifted, unshifted): raise ValueError("Inconsistent numeric remapping %s / %s" % (unshifted, shifted)) - return dict(sorted(table.items())) + return KeymapKeys(dict(sorted(table.items()))) - @property - def cname(self) -> str: + def cname(self, suffix: str) -> str: """C variable name""" - return re.sub(r'\W', '_', self.name) + "_mapping" - - @classmethod - def ascii_name(cls, char: str) -> str: - """ASCII character name""" - if char == '\\': - name = "'\\\\'" - elif char == '\'': - name = "'\\\''" - elif ord(char) & BiosKeyMapping.KEY_PSEUDO: - name = "Pseudo-%s" % cls.ascii_name( - chr(ord(char) & ~BiosKeyMapping.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 + 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") code = textwrap.dedent(f""" /** @file * @@ -333,17 +349,15 @@ class KeyRemapping: #include - /** "{self.name}" keyboard mapping */ - struct key_mapping {self.cname}[] __keymap = {{ - """).lstrip() + ''.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.ascii.items() - ) + textwrap.dedent(""" - }; - """).strip() + /** "{self.name}" basic remapping */ + static struct keymap_key {basic_name}[] = %s; + + /** "{self.name}" keyboard map */ + struct keymap {keymap_name} __keymap = {{ + \t.name = "{self.name}", + \t.basic = {basic_name}, + }}; + """).strip() % self.basic.code return code @@ -356,12 +370,12 @@ if __name__ == '__main__': parser.add_argument('layout', help="Target keyboard layout") args = parser.parse_args() - # Load source and target keymaps - source = BiosKeyMapping.load('us') - target = KeyMapping.load(args.layout) + # Load source and target keyboard layouts + source = BiosKeyLayout.load('us') + target = KeyLayout.load(args.layout) - # Construct remapping - remap = KeyRemapping(name=args.layout, source=source, target=target) + # Construct keyboard mapping + keymap = Keymap(name=args.layout, source=source, target=target) # Output generated code - print(remap.code) + print(keymap.code) -- cgit v1.2.3-55-g7522 From f2a59d5973da2041f93264609698b9b3f4ec101b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Feb 2022 16:31:08 +0000 Subject: [console] Centralise handling of key modifiers Handle Ctrl and CapsLock key modifiers within key_remap(), to provide consistent behaviour across different console types. Signed-off-by: Michael Brown --- src/arch/x86/include/bios.h | 3 ++ src/arch/x86/interface/pcbios/bios_console.c | 23 +++++++++++---- src/core/keymap.c | 41 ++++++++++++++++++++++---- src/drivers/usb/usbkbd.c | 21 ++++++------- src/include/ipxe/keymap.h | 21 +++++++++++++ src/interface/efi/efi_console.c | 44 ++++++++++++++++++---------- 6 files changed, 116 insertions(+), 37 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/include/bios.h b/src/arch/x86/include/bios.h index 14e7acbc7..3ba8264ec 100644 --- a/src/arch/x86/include/bios.h +++ b/src/arch/x86/include/bios.h @@ -6,6 +6,9 @@ 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_CTRL 0x04 +#define BDA_KB0_CAPSLOCK 0x040 #define BDA_FBMS 0x0013 #define BDA_TICKS 0x006c #define BDA_MIDNIGHT 0x0070 diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 438a01d07..2664ac8a5 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -361,6 +361,7 @@ static const char * bios_ansi_seq ( unsigned int scancode ) { */ static int bios_getchar ( void ) { uint16_t keypress; + uint8_t kb0; unsigned int scancode; unsigned int character; const char *ansi_seq; @@ -385,16 +386,28 @@ static int bios_getchar ( void ) { bios_inject_lock--; scancode = ( keypress >> 8 ); character = ( keypress & 0xff ); + get_real ( kb0, BDA_SEG, BDA_KB0 ); /* If it's a normal character, map (if applicable) and return it */ if ( character && ( character < 0x80 ) ) { - if ( scancode < SCANCODE_RSHIFT ) { - return key_remap ( character ); - } else if ( scancode == SCANCODE_NON_US ) { - return key_remap ( character | KEYMAP_PSEUDO ); - } else { + + /* 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; + + /* Map and return */ + return key_remap ( character ); } /* Otherwise, check for a special key that we know about */ diff --git a/src/core/keymap.c b/src/core/keymap.c index c0953967a..a5209bc20 100644 --- a/src/core/keymap.c +++ b/src/core/keymap.c @@ -23,6 +23,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include +#include #include /** @file @@ -31,6 +33,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +/** 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 ); @@ -41,21 +55,36 @@ static struct keymap *keymap = keymap_start; * Remap a key * * @v character Character read from console - * @ret character Mapped character + * @ret mapped Mapped character */ unsigned int key_remap ( unsigned int character ) { + 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; + /* Remap via table */ for ( key = keymap->basic ; key->from ; key++ ) { - if ( key->from == character ) { - character = key->to; + if ( mapped == key->from ) { + mapped = key->to; break; } } - /* Clear pseudo key flag */ - character &= ~KEYMAP_PSEUDO; + /* Handle Ctrl- 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; - return character; + DBGC2 ( &keymap, "KEYMAP mapped %04x => %02x\n", character, mapped ); + return mapped; } diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index 6954cd69b..516667b25 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -71,6 +71,9 @@ 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_SHIFT ) { + key -= ( 'a' - 'A' ); + } } else if ( keycode <= USBKBD_KEY_0 ) { /* Numeric key row */ if ( modifiers & USBKBD_SHIFT ) { @@ -125,17 +128,15 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, /* Remap key if applicable */ if ( ( keycode < USBKBD_KEY_CAPS_LOCK ) || ( keycode == USBKBD_KEY_NON_US ) ) { - key = key_remap ( key ); - } - /* Handle upper/lower case and Ctrl- */ - if ( islower ( key ) ) { - if ( modifiers & USBKBD_CTRL ) { - key -= ( 'a' - CTRL_A ); - } else if ( ( modifiers & USBKBD_SHIFT ) || - ( leds & USBKBD_LED_CAPS_LOCK ) ) { - key -= ( 'a' - 'A' ); - } + /* Apply modifiers */ + if ( modifiers & USBKBD_CTRL ) + key |= KEYMAP_CTRL; + if ( leds & USBKBD_LED_CAPS_LOCK ) + key |= KEYMAP_CAPSLOCK; + + /* Remap key */ + key = key_remap ( key ); } return key; diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index a64ab9cd4..3da25190b 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -40,9 +40,30 @@ struct keymap { /** Define a keyboard mapping */ #define __keymap __table_entry ( KEYMAP, 01 ) +/** 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 ) + extern unsigned int key_remap ( unsigned int character ); #endif /* _IPXE_KEYMAP_H */ diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c index 874f54b6c..9adce4a9b 100644 --- a/src/interface/efi/efi_console.c +++ b/src/interface/efi/efi_console.c @@ -55,8 +55,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 @@ -286,6 +284,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; @@ -318,23 +319,34 @@ static int efi_getchar ( void ) { key.KeyState.KeyToggleState, key.Key.UnicodeChar, key.Key.ScanCode ); - /* Remap key. 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 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. */ - key.Key.UnicodeChar = key_remap ( key.Key.UnicodeChar ); + 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; + } + } - /* Translate Ctrl- */ - if ( ( key.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID ) && - ( key.KeyState.KeyShiftState & ( EFI_LEFT_CONTROL_PRESSED | - EFI_RIGHT_CONTROL_PRESSED ) ) ) { - key.Key.UnicodeChar &= CTRL_MASK; - } + /* Apply toggle state */ + toggle = key.KeyState.KeyToggleState; + if ( toggle & EFI_TOGGLE_STATE_VALID ) { + if ( toggle & EFI_CAPS_LOCK_ACTIVE ) { + character |= KEYMAP_CAPSLOCK_REDO; + } + } - /* If key has a Unicode representation, return it */ - if ( key.Key.UnicodeChar ) - return key.Key.UnicodeChar; + /* 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 ) ) ) { -- cgit v1.2.3-55-g7522 From e1cedbc0d4fdb0e16818f6b722f4873a50780761 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Feb 2022 13:45:59 +0000 Subject: [console] Support AltGr to access ASCII characters via remapping Several keyboard layouts define ASCII characters as accessible only via the AltGr modifier. Add support for this modifier to ensure that all ASCII characters are accessible. Experiments suggest that the BIOS console is likely to fail to generate ASCII characters when the AltGr key is pressed. Work around this limitation by accepting LShift+RShift (which will definitely produce an ASCII character) as a synonym for AltGr. Signed-off-by: Michael Brown --- src/arch/x86/include/bios.h | 4 +++ src/arch/x86/interface/pcbios/bios_console.c | 12 +++++++++ src/core/keymap.c | 5 +++- src/drivers/usb/usbkbd.c | 2 ++ src/hci/keymap/keymap_al.c | 8 ++++++ src/hci/keymap/keymap_az.c | 7 +++++ src/hci/keymap/keymap_by.c | 6 +++++ src/hci/keymap/keymap_cf.c | 9 +++++++ src/hci/keymap/keymap_cz.c | 26 ++++++++++++++++++ src/hci/keymap/keymap_de.c | 11 ++++++++ src/hci/keymap/keymap_dk.c | 9 +++++++ src/hci/keymap/keymap_es.c | 11 ++++++++ src/hci/keymap/keymap_et.c | 10 +++++++ src/hci/keymap/keymap_fi.c | 9 +++++++ src/hci/keymap/keymap_fr.c | 12 +++++++++ src/hci/keymap/keymap_gr.c | 6 +++++ src/hci/keymap/keymap_hu.c | 17 ++++++++++++ src/hci/keymap/keymap_il.c | 6 +++++ src/hci/keymap/keymap_it.c | 12 +++++++++ src/hci/keymap/keymap_lt.c | 6 +++++ src/hci/keymap/keymap_mk.c | 6 +++++ src/hci/keymap/keymap_mt.c | 7 +++++ src/hci/keymap/keymap_nl.c | 8 ++++++ src/hci/keymap/keymap_no-latin1.c | 10 +++++++ src/hci/keymap/keymap_no.c | 8 ++++++ src/hci/keymap/keymap_pl.c | 6 +++++ src/hci/keymap/keymap_pt.c | 10 +++++++ src/hci/keymap/keymap_ro.c | 6 +++++ src/hci/keymap/keymap_ru.c | 6 +++++ src/hci/keymap/keymap_sg.c | 10 +++++++ src/hci/keymap/keymap_sr-latin.c | 6 +++++ src/hci/keymap/keymap_ua.c | 6 +++++ src/hci/keymap/keymap_uk.c | 6 +++++ src/hci/keymap/keymap_us.c | 6 +++++ src/include/ipxe/keymap.h | 5 ++++ src/interface/efi/efi_console.c | 3 +++ src/util/genkeymap.py | 40 +++++++++++++++++++++++++--- 37 files changed, 332 insertions(+), 5 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/include/bios.h b/src/arch/x86/include/bios.h index 3ba8264ec..6391a4958 100644 --- a/src/arch/x86/include/bios.h +++ b/src/arch/x86/include/bios.h @@ -7,6 +7,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #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 @@ -16,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/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 2664ac8a5..0220c8564 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -362,6 +362,7 @@ static const char * bios_ansi_seq ( unsigned int scancode ) { static int bios_getchar ( void ) { uint16_t keypress; uint8_t kb0; + uint8_t kb2; unsigned int scancode; unsigned int character; const char *ansi_seq; @@ -387,6 +388,7 @@ static int bios_getchar ( void ) { 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 ) ) { @@ -405,6 +407,16 @@ static int bios_getchar ( void ) { character |= KEYMAP_CTRL; if ( kb0 & BDA_KB0_CAPSLOCK ) character |= KEYMAP_CAPSLOCK_REDO; + if ( kb2 & BDA_KB2_RALT ) + character |= KEYMAP_ALTGR; + + /* Treat LShift+RShift as AltGr since many BIOSes will + * not return ASCII characters when AltGr is pressed. + */ + if ( ( kb0 & ( BDA_KB0_LSHIFT | BDA_KB0_RSHIFT ) ) == + ( BDA_KB0_LSHIFT | BDA_KB0_RSHIFT ) ) { + character |= KEYMAP_ALTGR; + } /* Map and return */ return key_remap ( character ); diff --git a/src/core/keymap.c b/src/core/keymap.c index a5209bc20..3fa85f74e 100644 --- a/src/core/keymap.c +++ b/src/core/keymap.c @@ -65,8 +65,11 @@ unsigned int key_remap ( unsigned int character ) { 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 = keymap->basic ; key->from ; key++ ) { + for ( ; key->from ; key++ ) { if ( mapped == key->from ) { mapped = key->to; break; diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index 516667b25..b284e584f 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -132,6 +132,8 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, /* 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; diff --git a/src/hci/keymap/keymap_al.c b/src/hci/keymap/keymap_al.c index a3df385a9..b68b98878 100644 --- a/src/hci/keymap/keymap_al.c +++ b/src/hci/keymap/keymap_al.c @@ -35,8 +35,16 @@ static struct keymap_key al_basic[] = { { 0, 0 } }; +/** "al" AltGr remapping */ +static struct keymap_key al_altgr[] = { + { 0x31, 0x7e }, /* '1' => '~' */ + { 0x37, 0x60 }, /* '7' => '`' */ + { 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 index 7b382ca8b..03087e01e 100644 --- a/src/hci/keymap/keymap_az.c +++ b/src/hci/keymap/keymap_az.c @@ -26,8 +26,15 @@ static struct keymap_key az_basic[] = { { 0, 0 } }; +/** "az" AltGr remapping */ +static struct keymap_key az_altgr[] = { + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + /** "az" keyboard map */ struct keymap az_keymap __keymap = { .name = "az", .basic = az_basic, + .altgr = az_altgr, }; diff --git a/src/hci/keymap/keymap_by.c b/src/hci/keymap/keymap_by.c index 4127609e3..9af6c966d 100644 --- a/src/hci/keymap/keymap_by.c +++ b/src/hci/keymap/keymap_by.c @@ -17,8 +17,14 @@ static struct keymap_key by_basic[] = { { 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 0bbe89659..09242ee6f 100644 --- a/src/hci/keymap/keymap_cf.c +++ b/src/hci/keymap/keymap_cf.c @@ -24,8 +24,17 @@ static struct keymap_key cf_basic[] = { { 0, 0 } }; +/** "cf" AltGr remapping */ +static struct keymap_key cf_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x3b, 0x7e }, /* ';' => '~' */ + { 0x60, 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 8655d5b68..cce686d9a 100644 --- a/src/hci/keymap/keymap_cz.c +++ b/src/hci/keymap/keymap_cz.c @@ -46,8 +46,34 @@ static struct keymap_key cz_basic[] = { { 0, 0 } }; +/** "cz" AltGr remapping */ +static struct keymap_key cz_altgr[] = { + { 0x2c, 0x3c }, /* ',' => '<' */ + { 0x2e, 0x3e }, /* '.' => '>' */ + { 0x2f, 0x2a }, /* '/' => '*' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x34, 0x24 }, /* '4' => '$' */ + { 0x36, 0x5e }, /* '6' => '^' */ + { 0x37, 0x26 }, /* '7' => '&' */ + { 0x38, 0x2a }, /* '8' => '*' */ + { 0x39, 0x7b }, /* '9' => '{' */ + { 0x3b, 0x24 }, /* ';' => '$' */ + { 0x62, 0x7b }, /* 'b' => '{' */ + { 0x63, 0x26 }, /* 'c' => '&' */ + { 0x67, 0x5d }, /* 'g' => ']' */ + { 0x68, 0x60 }, /* 'h' => '`' */ + { 0x6d, 0x5e }, /* 'm' => '^' */ + { 0x6e, 0x7d }, /* 'n' => '}' */ + { 0x76, 0x40 }, /* 'v' => '@' */ + { 0x78, 0x23 }, /* 'x' => '#' */ + { 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 4d23c2e60..4a889a242 100644 --- a/src/hci/keymap/keymap_de.c +++ b/src/hci/keymap/keymap_de.c @@ -41,8 +41,19 @@ static struct keymap_key de_basic[] = { { 0, 0 } }; +/** "de" AltGr remapping */ +static struct keymap_key de_altgr[] = { + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 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 100246bf5..4d40743b1 100644 --- a/src/hci/keymap/keymap_dk.c +++ b/src/hci/keymap/keymap_dk.c @@ -33,8 +33,17 @@ static struct keymap_key dk_basic[] = { { 0, 0 } }; +/** "dk" AltGr remapping */ +static struct keymap_key dk_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x3d, 0x7c }, /* '=' => '|' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 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 2f4b86c47..397e2cbaa 100644 --- a/src/hci/keymap/keymap_es.c +++ b/src/hci/keymap/keymap_es.c @@ -33,8 +33,19 @@ static struct keymap_key es_basic[] = { { 0, 0 } }; +/** "es" AltGr remapping */ +static struct keymap_key es_altgr[] = { + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x5c, 0x7d }, /* '\\' => '}' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 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 a8bf46ebc..4120dbed9 100644 --- a/src/hci/keymap/keymap_et.c +++ b/src/hci/keymap/keymap_et.c @@ -31,8 +31,18 @@ static struct keymap_key et_basic[] = { { 0, 0 } }; +/** "et" AltGr remapping */ +static struct keymap_key et_altgr[] = { + { 0x27, 0x5e }, /* '\'' => '^' */ + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 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 eb75eb4dc..978121a88 100644 --- a/src/hci/keymap/keymap_fi.c +++ b/src/hci/keymap/keymap_fi.c @@ -31,8 +31,17 @@ static struct keymap_key fi_basic[] = { { 0, 0 } }; +/** "fi" AltGr remapping */ +static struct keymap_key fi_altgr[] = { + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 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 523254ee5..c0a959f0d 100644 --- a/src/hci/keymap/keymap_fr.c +++ b/src/hci/keymap/keymap_fr.c @@ -62,8 +62,20 @@ static struct keymap_key fr_basic[] = { { 0, 0 } }; +/** "fr" AltGr remapping */ +static struct keymap_key fr_altgr[] = { + { 0x2d, 0x5d }, /* '-' => ']' */ + { 0x30, 0x40 }, /* '0' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x38, 0x5c }, /* '8' => '\\' */ + { 0x39, 0x5e }, /* '9' => '^' */ + { 0x61, 0x40 }, /* 'a' => '@' */ + { 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 16a2a7032..4826c26c2 100644 --- a/src/hci/keymap/keymap_gr.c +++ b/src/hci/keymap/keymap_gr.c @@ -17,8 +17,14 @@ static struct keymap_key gr_basic[] = { { 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 5e407161f..64e27dda6 100644 --- a/src/hci/keymap/keymap_hu.c +++ b/src/hci/keymap/keymap_hu.c @@ -35,8 +35,25 @@ static struct keymap_key hu_basic[] = { { 0, 0 } }; +/** "hu" AltGr remapping */ +static struct keymap_key hu_altgr[] = { + { 0x2e, 0x3e }, /* '.' => '>' */ + { 0x2f, 0x2a }, /* '/' => '*' */ + { 0x33, 0x5e }, /* '3' => '^' */ + { 0x37, 0x60 }, /* '7' => '`' */ + { 0x3b, 0x24 }, /* ';' => '$' */ + { 0x63, 0x26 }, /* 'c' => '&' */ + { 0x6d, 0x3c }, /* 'm' => '<' */ + { 0x76, 0x40 }, /* 'v' => '@' */ + { 0x78, 0x23 }, /* 'x' => '#' */ + { 0x7a, 0x3e }, /* 'z' => '>' */ + { 0xdc, 0x3c }, /* 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 de5e639ca..e3061fa54 100644 --- a/src/hci/keymap/keymap_il.c +++ b/src/hci/keymap/keymap_il.c @@ -29,8 +29,14 @@ static struct keymap_key il_basic[] = { { 0, 0 } }; +/** "il" AltGr remapping */ +static struct keymap_key il_altgr[] = { + { 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 a4921020a..f67bbadcb 100644 --- a/src/hci/keymap/keymap_it.c +++ b/src/hci/keymap/keymap_it.c @@ -35,8 +35,20 @@ static struct keymap_key it_basic[] = { { 0, 0 } }; +/** "it" AltGr remapping */ +static struct keymap_key it_altgr[] = { + { 0x2d, 0x60 }, /* '-' => '`' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x3b, 0x40 }, /* ';' => '@' */ + { 0x3d, 0x7e }, /* '=' => '~' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 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 333241d21..5d6ee5a8c 100644 --- a/src/hci/keymap/keymap_lt.c +++ b/src/hci/keymap/keymap_lt.c @@ -15,8 +15,14 @@ static struct keymap_key lt_basic[] = { { 0, 0 } }; +/** "lt" AltGr remapping */ +static struct keymap_key lt_altgr[] = { + { 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 1656fb99c..4b90ef799 100644 --- a/src/hci/keymap/keymap_mk.c +++ b/src/hci/keymap/keymap_mk.c @@ -17,8 +17,14 @@ static struct keymap_key mk_basic[] = { { 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 ebff8506f..f5baf6907 100644 --- a/src/hci/keymap/keymap_mt.c +++ b/src/hci/keymap/keymap_mt.c @@ -20,8 +20,15 @@ static struct keymap_key mt_basic[] = { { 0, 0 } }; +/** "mt" AltGr remapping */ +static struct keymap_key mt_altgr[] = { + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 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 2172e045f..bbee4cbdf 100644 --- a/src/hci/keymap/keymap_nl.c +++ b/src/hci/keymap/keymap_nl.c @@ -38,8 +38,16 @@ static struct keymap_key nl_basic[] = { { 0, 0 } }; +/** "nl" AltGr remapping */ +static struct keymap_key nl_altgr[] = { + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x39, 0x7d }, /* '9' => '}' */ + { 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 65f30beae..63fe85548 100644 --- a/src/hci/keymap/keymap_no-latin1.c +++ b/src/hci/keymap/keymap_no-latin1.c @@ -37,8 +37,18 @@ static struct keymap_key no_latin1_basic[] = { { 0, 0 } }; +/** "no-latin1" AltGr remapping */ +static struct keymap_key no_latin1_altgr[] = { + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x5b, 0x7d }, /* '[' => '}' */ + { 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 d3d06bce3..95a95428b 100644 --- a/src/hci/keymap/keymap_no.c +++ b/src/hci/keymap/keymap_no.c @@ -35,8 +35,16 @@ static struct keymap_key no_basic[] = { { 0, 0 } }; +/** "no" AltGr remapping */ +static struct keymap_key no_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 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 a23c01f2c..a76181fbc 100644 --- a/src/hci/keymap/keymap_pl.c +++ b/src/hci/keymap/keymap_pl.c @@ -17,8 +17,14 @@ static struct keymap_key pl_basic[] = { { 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 c065fd76f..99ba52e4b 100644 --- a/src/hci/keymap/keymap_pt.c +++ b/src/hci/keymap/keymap_pt.c @@ -34,8 +34,18 @@ static struct keymap_key pt_basic[] = { { 0, 0 } }; +/** "pt" AltGr remapping */ +static struct keymap_key pt_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 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 334cf6080..620450001 100644 --- a/src/hci/keymap/keymap_ro.c +++ b/src/hci/keymap/keymap_ro.c @@ -15,8 +15,14 @@ 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 a08b115ed..2aafcf9bd 100644 --- a/src/hci/keymap/keymap_ru.c +++ b/src/hci/keymap/keymap_ru.c @@ -18,8 +18,14 @@ static struct keymap_key ru_basic[] = { { 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_sg.c b/src/hci/keymap/keymap_sg.c index 152c5d631..9a6db9cb4 100644 --- a/src/hci/keymap/keymap_sg.c +++ b/src/hci/keymap/keymap_sg.c @@ -43,8 +43,18 @@ static struct keymap_key sg_basic[] = { { 0, 0 } }; +/** "sg" AltGr remapping */ +static struct keymap_key sg_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x37, 0x7c }, /* '7' => '|' */ + { 0x5c, 0x7d }, /* '\\' => '}' */ + { 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 index ec5efdc89..7e55714a2 100644 --- a/src/hci/keymap/keymap_sr-latin.c +++ b/src/hci/keymap/keymap_sr-latin.c @@ -17,8 +17,14 @@ static struct keymap_key sr_latin_basic[] = { { 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_ua.c b/src/hci/keymap/keymap_ua.c index b4199cdad..44e82cb2d 100644 --- a/src/hci/keymap/keymap_ua.c +++ b/src/hci/keymap/keymap_ua.c @@ -17,8 +17,14 @@ static struct keymap_key ua_basic[] = { { 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 156b42dff..28cf7aac4 100644 --- a/src/hci/keymap/keymap_uk.c +++ b/src/hci/keymap/keymap_uk.c @@ -19,8 +19,14 @@ static struct keymap_key uk_basic[] = { { 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 5d78f80a2..6432474e2 100644 --- a/src/hci/keymap/keymap_us.c +++ b/src/hci/keymap/keymap_us.c @@ -15,8 +15,14 @@ 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 = { .name = "us", .basic = us_basic, + .altgr = us_altgr, }; diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index 3da25190b..72b6961ef 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -32,6 +32,8 @@ struct keymap { const char *name; /** Basic remapping table (zero-terminated) */ struct keymap_key *basic; + /** AltGr remapping table (zero-terminated) */ + struct keymap_key *altgr; }; /** Keyboard mapping table */ @@ -64,6 +66,9 @@ struct keymap { /** 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 ); #endif /* _IPXE_KEYMAP_H */ diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c index 9adce4a9b..fc1500afb 100644 --- a/src/interface/efi/efi_console.c +++ b/src/interface/efi/efi_console.c @@ -334,6 +334,9 @@ static int efi_getchar ( void ) { EFI_RIGHT_CONTROL_PRESSED ) ) { character |= KEYMAP_CTRL; } + if ( shift & EFI_RIGHT_ALT_PRESSED ) { + character |= KEYMAP_ALTGR; + } } /* Apply toggle state */ diff --git a/src/util/genkeymap.py b/src/util/genkeymap.py index d38552eb4..ff5ff0a87 100755 --- a/src/util/genkeymap.py +++ b/src/util/genkeymap.py @@ -171,6 +171,11 @@ class KeyLayout(UserDict[KeyModifiers, Sequence[Key]]): """Basic shifted keyboard layout""" return self[KeyModifiers.SHIFT] + @property + def altgr(self): + """AltGr keyboard layout""" + return self.get(KeyModifiers.ALTGR, self.unshifted) + @classmethod def load(cls, name: str) -> KeyLayout: """Load keymap using 'loadkeys -b'""" @@ -278,6 +283,7 @@ class KeymapKeys(UserDict[str, str]): self.ascii_name(source), self.ascii_name(target) ) for source, target in self.items() + if ord(source) & ~BiosKeyLayout.KEY_PSEUDO != ord(target) ) + '\t{ 0, 0 }\n}' @@ -301,13 +307,12 @@ class Keymap: raw = {source: self.target[key.modifiers][key.keycode].ascii for source, key in self.source.inverse.items()} # Eliminate any null mappings, mappings that attempt to remap - # the backspace key, or mappings that would become identity - # mappings after clearing the high bit + # the backspace key, or identity mappings table = {source: target for source, target in raw.items() if target and ord(source) != 0x7f and ord(target) != 0x7f - and ord(source) & ~BiosKeyLayout.KEY_PSEUDO != ord(target)} + and source != target} # Recursively delete any mappings that would produce # unreachable alphanumerics (e.g. the "il" keymap, which maps # away the whole lower-case alphabet) @@ -327,6 +332,28 @@ class Keymap: (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: self.target.altgr[key.keycode].ascii + for source, key in self.source.inverse.items() + if key.modifiers == KeyModifiers.NONE} + # 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 null mappings, 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 + and target in unreachable} + return KeymapKeys(dict(sorted(table.items()))) + def cname(self, suffix: str) -> str: """C variable name""" return re.sub(r'\W', '_', (self.name + '_' + suffix)) @@ -336,6 +363,7 @@ class Keymap: """Generated source code""" keymap_name = self.cname("keymap") basic_name = self.cname("basic") + altgr_name = self.cname("altgr") code = textwrap.dedent(f""" /** @file * @@ -352,12 +380,16 @@ class Keymap: /** "{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} __keymap = {{ \t.name = "{self.name}", \t.basic = {basic_name}, + \t.altgr = {altgr_name}, }}; - """).strip() % self.basic.code + """).strip() % (self.basic.code, self.altgr.code) return code -- cgit v1.2.3-55-g7522 From 11e17991d0729fd17ab06d94ec67a8ca48032af4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 16 Feb 2022 00:11:33 +0000 Subject: [console] Ensure that US keyboard map appears at start of linker table Signed-off-by: Michael Brown --- src/hci/keymap/keymap_us.c | 2 +- src/include/ipxe/keymap.h | 5 ++++- src/util/genkeymap.py | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/hci/keymap/keymap_us.c b/src/hci/keymap/keymap_us.c index 6432474e2..b8e604a48 100644 --- a/src/hci/keymap/keymap_us.c +++ b/src/hci/keymap/keymap_us.c @@ -21,7 +21,7 @@ static struct keymap_key us_altgr[] = { }; /** "us" keyboard map */ -struct keymap us_keymap __keymap = { +struct keymap us_keymap __keymap_default = { .name = "us", .basic = us_basic, .altgr = us_altgr, diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index 72b6961ef..392d3ab8f 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -39,8 +39,11 @@ struct keymap { /** Keyboard mapping table */ #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 diff --git a/src/util/genkeymap.py b/src/util/genkeymap.py index 632f71eda..9fd987477 100755 --- a/src/util/genkeymap.py +++ b/src/util/genkeymap.py @@ -399,6 +399,7 @@ class Keymap: 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 * @@ -419,7 +420,7 @@ class Keymap: static struct keymap_key {altgr_name}[] = %s; /** "{self.name}" keyboard map */ - struct keymap {keymap_name} __keymap = {{ + struct keymap {keymap_name} {attribute} = {{ \t.name = "{self.name}", \t.basic = {basic_name}, \t.altgr = {altgr_name}, -- cgit v1.2.3-55-g7522 From 304333dace992ea4b876a074c42bb7fd752137ca Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 16 Feb 2022 00:14:38 +0000 Subject: [console] Support changing keyboard map at runtime Provide the special keyboard map named "dynamic" which allows the active keyboard map to be selected at runtime via the ${keymap} setting, e.g.: #define KEYBOARD_MAP dynamic iPXE> set keymap uk Signed-off-by: Michael Brown --- src/core/dynkeymap.c | 131 +++++++++++++++++++++++++++++++++++++++++++++ src/core/keymap.c | 42 ++++++++++++++- src/include/ipxe/errfile.h | 1 + src/include/ipxe/keymap.h | 2 + 4 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 src/core/dynkeymap.c (limited to 'src/include/ipxe') diff --git a/src/core/dynkeymap.c b/src/core/dynkeymap.c new file mode 100644 index 000000000..2f7c49937 --- /dev/null +++ b/src/core/dynkeymap.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2022 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or 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 +#include +#include +#include + +/** + * 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/keymap.c b/src/core/keymap.c index 3fa85f74e..36db7bd4c 100644 --- a/src/core/keymap.c +++ b/src/core/keymap.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include #include @@ -49,7 +50,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); static TABLE_START ( keymap_start, KEYMAP ); /** Current keyboard mapping */ -static struct keymap *keymap = keymap_start; +static struct keymap *keymap_current = keymap_start; /** * Remap a key @@ -58,6 +59,7 @@ static struct keymap *keymap = keymap_start; * @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; @@ -88,6 +90,42 @@ unsigned int key_remap ( unsigned int character ) { /* Clear flags */ mapped &= ASCII_MASK; - DBGC2 ( &keymap, "KEYMAP mapped %04x => %02x\n", character, mapped ); + 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/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 23e406b62..81f555725 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/keymap.h b/src/include/ipxe/keymap.h index 392d3ab8f..8bfbe07a5 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -73,5 +73,7 @@ struct keymap { #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 */ -- cgit v1.2.3-55-g7522 From 3cd3a7326178bd10fb38e09eb702b27bc463d3c6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 28 Feb 2022 13:37:40 +0000 Subject: [utf8] Add ability to accumulate Unicode characters from UTF-8 bytes Signed-off-by: Michael Brown --- src/core/utf8.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/utf8.h | 69 ++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 src/core/utf8.c create mode 100644 src/include/ipxe/utf8.h (limited to 'src/include/ipxe') diff --git a/src/core/utf8.c b/src/core/utf8.c new file mode 100644 index 000000000..4ee01baf9 --- /dev/null +++ b/src/core/utf8.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2022 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include + +/** @file + * + * 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/include/ipxe/utf8.h b/src/include/ipxe/utf8.h new file mode 100644 index 000000000..299c25511 --- /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 + +/** 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 */ -- cgit v1.2.3-55-g7522 From ba93c9134ce9d9edcba117b690fbbdd35b3e066b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Mar 2022 22:38:24 +0000 Subject: [fbcon] Support Unicode character output Accumulate UTF-8 characters in fbcon_putchar(), and require the frame buffer console's .glyph() method to accept Unicode character values. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/vesafb.c | 25 ++++- src/core/fbcon.c | 5 + src/include/ipxe/fbcon.h | 7 +- src/interface/efi/efi_fbcon.c | 198 +++++++++++++++++++++------------ 4 files changed, 161 insertions(+), 74 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/interface/pcbios/vesafb.c b/src/arch/x86/interface/pcbios/vesafb.c index 50e485852..86edbda42 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/core/fbcon.c b/src/core/fbcon.c index 44a56e105..ff3132ac7 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/include/ipxe/fbcon.h b/src/include/ipxe/fbcon.h index 42ffca3d7..a4c7a9ab3 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 #include +#include #include #include @@ -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/interface/efi/efi_fbcon.c b/src/interface/efi/efi_fbcon.c index abc5a9390..d9e3e69e6 100644 --- a/src/interface/efi/efi_fbcon.c +++ b/src/interface/efi/efi_fbcon.c @@ -62,6 +62,9 @@ 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 + /* Forward declaration */ struct console_driver efifb_console __console_driver; @@ -84,7 +87,7 @@ struct efifb { struct fbcon_colour_map map; /** Font definition */ struct fbcon_font font; - /** Character glyphs */ + /** Character glyph cache */ userptr_t glyphs; }; @@ -92,14 +95,112 @@ struct efifb { 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 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 an "unknown" glyph */ + index = 0; + } + + /* Copy cached glyph */ + offset = ( index * efifb.font.height ); copy_from_user ( glyph, efifb.glyphs, offset, efifb.font.height ); } @@ -109,16 +210,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 +223,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.font.height ); efifb.glyphs = umalloc ( len ); if ( ! efifb.glyphs ) { rc = -ENOMEM; @@ -168,60 +257,29 @@ 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 ); } efifb.font.glyph = efifb_glyph; return 0; + err_draw: ufree ( efifb.glyphs ); err_alloc: + err_height: return rc; } -- cgit v1.2.3-55-g7522 From 27825e555746c379ac045466f692ed77686af2b5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 23 Mar 2022 14:39:11 +0000 Subject: [acpi] Allow for the possibility of overriding ACPI tables at link time Allow for linked-in code to override the mechanism used to locate an ACPI table, thereby opening up the possibility of ACPI self-tests. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/acpi_timer.c | 2 +- src/arch/x86/interface/pcbios/acpipwr.c | 2 +- src/core/acpi.c | 22 ++++++++++++++++++++-- src/core/acpi_settings.c | 2 +- src/include/ipxe/acpi.h | 3 +++ 5 files changed, 26 insertions(+), 5 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/interface/pcbios/acpi_timer.c b/src/arch/x86/interface/pcbios/acpi_timer.c index 82e85a034..2e4047e38 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 3dac6b605..f08b4af25 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/core/acpi.c b/src/core/acpi.c index aa486da93..526bf8555 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 @@ -82,6 +88,18 @@ void acpi_fix_checksum ( struct acpi_header *acpi ) { acpi->checksum -= acpi_checksum ( virt_to_user ( acpi ) ); } +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +userptr_t acpi_table ( uint32_t signature, unsigned int index ) { + + return ( *acpi_finder ) ( signature, index ); +} + /** * Locate ACPI table via RSDT * @@ -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 7ba2e979f..b9e2b7f61 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/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index 7df3ec21c..c34681238 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 ) ); -- cgit v1.2.3-55-g7522 From 1e1b9593e6f7d6026f2d6a2109e06a9629ef0ce0 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 23 Mar 2022 14:41:36 +0000 Subject: [linux] Add stub phys_to_user() implementation For symmetry with the stub user_to_phys() implementation, provide phys_to_user() with the same underlying assumption that virtual addresses are physical (since there is no way to know the real physical address when running as a Linux userspace executable). Signed-off-by: Michael Brown --- src/include/ipxe/linux/linux_uaccess.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/linux/linux_uaccess.h b/src/include/ipxe/linux/linux_uaccess.h index acd919a85..a642b6163 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 ); -- cgit v1.2.3-55-g7522