From c598862958ca8733cc47e6a8f582ce69f1a7414b Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 27 Feb 2012 12:02:57 +0100 Subject: [PATCH] * grub-core/kern/efi/efi.c (grub_efi_get_variable): Add new function. * include/grub/efi/efi.h: Likewise. * include/grub/efi/api.h: Add guid for EFI-specified variables. * include/grub/charset.h (GRUB_MAX_UTF16_PER_UTF8): New definition. * grub-core/normal/charset.c (grub_utf8_process): Move from here ... * include/grub/charset.h (grub_utf8_process): ... to here. Inline. * grub-core/normal/charset.c (grub_utf8_to_utf16): Move from here ... * include/grub/charset.h (grub_utf8_to_utf16): ... to here. Inline. --- ChangeLog | 12 ++++ grub-core/kern/efi/efi.c | 39 +++++++++++++ grub-core/normal/charset.c | 101 -------------------------------- include/grub/charset.h | 114 ++++++++++++++++++++++++++++++++++--- include/grub/efi/api.h | 4 ++ include/grub/efi/efi.h | 3 +- 6 files changed, 163 insertions(+), 110 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9d11a93fc..2f083dfc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2012-02-27 Matthew Garrett +2012-02-27 Vladimir Serbinenko + + * grub-core/kern/efi/efi.c (grub_efi_get_variable): Add new function. + * include/grub/efi/efi.h: Likewise. + * include/grub/efi/api.h: Add guid for EFI-specified variables. + * include/grub/charset.h (GRUB_MAX_UTF16_PER_UTF8): New definition. + * grub-core/normal/charset.c (grub_utf8_process): Move from here ... + * include/grub/charset.h (grub_utf8_process): ... to here. Inline. + * grub-core/normal/charset.c (grub_utf8_to_utf16): Move from here ... + * include/grub/charset.h (grub_utf8_to_utf16): ... to here. Inline. + 2012-02-27 Matthew Garrett * include/grub/efi/pci.h: New file to define EFI PCI protocols. diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c index 6600f8b97..2b0a8b489 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -182,6 +182,45 @@ grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size, return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed"); } +void * +grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid) +{ + grub_efi_status_t status; + grub_efi_uintn_t datasize = 0; + grub_efi_runtime_services_t *r; + grub_efi_char16_t *var16; + void *data; + grub_size_t len, len16; + + len = grub_strlen (var); + len16 = len * GRUB_MAX_UTF16_PER_UTF8; + var16 = grub_malloc ((len16 + 1) * sizeof (var16[0])); + if (!var16) + return NULL; + len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL); + var16[len16] = 0; + + r = grub_efi_system_table->runtime_services; + + status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, NULL); + + data = grub_malloc (datasize); + if (!data) + { + grub_free (var16); + return NULL; + } + + status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data); + grub_free (var16); + + if (status == GRUB_EFI_SUCCESS) + return data; + + grub_free (data); + return NULL; +} + grub_uint64_t grub_rtc_get_time_ms (void) { diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c index d5aa0f6a7..5e5e5eaeb 100644 --- a/grub-core/normal/charset.c +++ b/grub-core/normal/charset.c @@ -53,107 +53,6 @@ #include "widthspec.h" #endif -int -grub_utf8_process (grub_uint8_t c, grub_uint32_t *code, int *count) -{ - if (*count) - { - if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT) - { - *count = 0; - /* invalid */ - return 0; - } - else - { - *code <<= 6; - *code |= (c & GRUB_UINT8_6_TRAILINGBITS); - (*count)--; - return 1; - } - } - - if ((c & GRUB_UINT8_1_LEADINGBIT) == 0) - { - *code = c; - return 1; - } - if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS) - { - *count = 1; - *code = c & GRUB_UINT8_5_TRAILINGBITS; - return 1; - } - if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS) - { - *count = 2; - *code = c & GRUB_UINT8_4_TRAILINGBITS; - return 1; - } - if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS) - { - *count = 3; - *code = c & GRUB_UINT8_3_TRAILINGBITS; - return 1; - } - return 0; -} - -/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE - bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string. - Return the number of characters converted. DEST must be able to hold - at least DESTSIZE characters. If an invalid sequence is found, return -1. - If SRCEND is not NULL, then *SRCEND is set to the next byte after the - last byte used in SRC. */ -grub_size_t -grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, - const grub_uint8_t *src, grub_size_t srcsize, - const grub_uint8_t **srcend) -{ - grub_uint16_t *p = dest; - int count = 0; - grub_uint32_t code = 0; - - if (srcend) - *srcend = src; - - while (srcsize && destsize) - { - int was_count = count; - if (srcsize != (grub_size_t)-1) - srcsize--; - if (!grub_utf8_process (*src++, &code, &count)) - { - code = '?'; - count = 0; - /* Character c may be valid, don't eat it. */ - if (was_count) - src--; - } - if (count != 0) - continue; - if (code == 0) - break; - if (destsize < 2 && code >= GRUB_UCS2_LIMIT) - break; - if (code >= GRUB_UCS2_LIMIT) - { - *p++ = GRUB_UTF16_UPPER_SURROGATE (code); - *p++ = GRUB_UTF16_LOWER_SURROGATE (code); - destsize -= 2; - } - else - { - *p++ = code; - destsize--; - } - } - - if (srcend) - *srcend = src; - return p - dest; -} - /* Returns -2 if not enough space, -1 on invalid character. */ grub_ssize_t grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend, diff --git a/include/grub/charset.h b/include/grub/charset.h index 41da01f1c..0e14e64cf 100644 --- a/include/grub/charset.h +++ b/include/grub/charset.h @@ -37,6 +37,10 @@ #define GRUB_UINT8_6_TRAILINGBITS 0x3f #define GRUB_MAX_UTF8_PER_UTF16 4 +/* You need at least one UTF-8 byte to have one UTF-16 word. + You need at least three UTF-8 bytes to have 2 UTF-16 words (surrogate pairs). + */ +#define GRUB_MAX_UTF16_PER_UTF8 1 #define GRUB_UCS2_LIMIT 0x10000 #define GRUB_UTF16_UPPER_SURROGATE(code) \ @@ -44,10 +48,110 @@ #define GRUB_UTF16_LOWER_SURROGATE(code) \ (0xDC00 + (((code) - GRUB_UCS2_LIMIT) & 0xfff)) -grub_size_t +/* Process one character from UTF8 sequence. + At beginning set *code = 0, *count = 0. Returns 0 on failure and + 1 on success. *count holds the number of trailing bytes. */ +static inline int +grub_utf8_process (grub_uint8_t c, grub_uint32_t *code, int *count) +{ + if (*count) + { + if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT) + { + *count = 0; + /* invalid */ + return 0; + } + else + { + *code <<= 6; + *code |= (c & GRUB_UINT8_6_TRAILINGBITS); + (*count)--; + return 1; + } + } + + if ((c & GRUB_UINT8_1_LEADINGBIT) == 0) + { + *code = c; + return 1; + } + if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS) + { + *count = 1; + *code = c & GRUB_UINT8_5_TRAILINGBITS; + return 1; + } + if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS) + { + *count = 2; + *code = c & GRUB_UINT8_4_TRAILINGBITS; + return 1; + } + if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS) + { + *count = 3; + *code = c & GRUB_UINT8_3_TRAILINGBITS; + return 1; + } + return 0; +} + + +/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE + bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string. + Return the number of characters converted. DEST must be able to hold + at least DESTSIZE characters. If an invalid sequence is found, return -1. + If SRCEND is not NULL, then *SRCEND is set to the next byte after the + last byte used in SRC. */ +static inline grub_size_t grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, const grub_uint8_t *src, grub_size_t srcsize, - const grub_uint8_t **srcend); + const grub_uint8_t **srcend) +{ + grub_uint16_t *p = dest; + int count = 0; + grub_uint32_t code = 0; + + if (srcend) + *srcend = src; + + while (srcsize && destsize) + { + int was_count = count; + if (srcsize != (grub_size_t)-1) + srcsize--; + if (!grub_utf8_process (*src++, &code, &count)) + { + code = '?'; + count = 0; + /* Character c may be valid, don't eat it. */ + if (was_count) + src--; + } + if (count != 0) + continue; + if (code == 0) + break; + if (destsize < 2 && code >= GRUB_UCS2_LIMIT) + break; + if (code >= GRUB_UCS2_LIMIT) + { + *p++ = GRUB_UTF16_UPPER_SURROGATE (code); + *p++ = GRUB_UTF16_LOWER_SURROGATE (code); + destsize -= 2; + } + else + { + *p++ = code; + destsize--; + } + } + + if (srcend) + *srcend = src; + return p - dest; +} /* Determine the last position where the UTF-8 string [beg, end) can be safely cut. */ @@ -178,12 +282,6 @@ grub_ssize_t grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, grub_uint32_t **last_position); -/* Process one character from UTF8 sequence. - At beginning set *code = 0, *count = 0. Returns 0 on failure and - 1 on success. *count holds the number of trailing bytes. */ -int -grub_utf8_process (grub_uint8_t c, grub_uint32_t *code, int *count); - void grub_ucs4_to_utf8 (const grub_uint32_t *src, grub_size_t size, grub_uint8_t *dest, grub_size_t destsize); diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index 184b3182e..6f857835b 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -1048,6 +1048,10 @@ struct grub_efi_runtime_services grub_efi_status_t (*convert_pointer) (grub_efi_uintn_t debug_disposition, void **address); +#define GRUB_EFI_GLOBAL_VARIABLE_GUID \ + { 0x8BE4DF61, 0x93CA, 0x11d2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B,0x8C }} + + grub_efi_status_t (*get_variable) (grub_efi_char16_t *variable_name, grub_efi_guid_t *vendor_guid, diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 7ecda58ab..067e3bdac 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -61,7 +61,8 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo grub_efi_uintn_t descriptor_size, grub_efi_uint32_t descriptor_version, grub_efi_memory_descriptor_t *virtual_map); - +void *EXPORT_FUNC (grub_efi_get_variable) (const char *variable, + const grub_efi_guid_t *guid); int EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1, const grub_efi_device_path_t *dp2);