Skip to content

Commit 04b2440

Browse files
nivedita76ardbiesheuvel
authored andcommitted
efi/libstub: Use snprintf with %ls to convert the command line
Now we can use snprintf to do the UTF-16 to UTF-8 translation for the command line. Drop the special "zero" trick to handle an empty command line. This was unnecessary even before this since with options_chars == 0, efi_utf16_to_utf8 would not have accessed options at all. snprintf won't access it either with a precision of 0. Signed-off-by: Arvind Sankar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent 15c316b commit 04b2440

File tree

1 file changed

+6
-60
lines changed

1 file changed

+6
-60
lines changed

drivers/firmware/efi/libstub/efi-stub-helper.c

Lines changed: 6 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -205,46 +205,6 @@ efi_status_t efi_parse_options(char const *cmdline)
205205
return EFI_SUCCESS;
206206
}
207207

208-
/*
209-
* Convert an UTF-16 string, not necessarily null terminated, to UTF-8.
210-
*/
211-
static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
212-
{
213-
unsigned int c;
214-
215-
while (n--) {
216-
c = *src++;
217-
if (n && c >= 0xd800 && c <= 0xdbff &&
218-
*src >= 0xdc00 && *src <= 0xdfff) {
219-
c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff);
220-
src++;
221-
n--;
222-
}
223-
if (c >= 0xd800 && c <= 0xdfff)
224-
c = 0xfffd; /* Unmatched surrogate */
225-
if (c < 0x80) {
226-
*dst++ = c;
227-
continue;
228-
}
229-
if (c < 0x800) {
230-
*dst++ = 0xc0 + (c >> 6);
231-
goto t1;
232-
}
233-
if (c < 0x10000) {
234-
*dst++ = 0xe0 + (c >> 12);
235-
goto t2;
236-
}
237-
*dst++ = 0xf0 + (c >> 18);
238-
*dst++ = 0x80 + ((c >> 12) & 0x3f);
239-
t2:
240-
*dst++ = 0x80 + ((c >> 6) & 0x3f);
241-
t1:
242-
*dst++ = 0x80 + (c & 0x3f);
243-
}
244-
245-
return dst;
246-
}
247-
248208
/*
249209
* Convert the unicode UEFI command line to ASCII to pass to kernel.
250210
* Size of memory allocated return in *cmd_line_len.
@@ -254,18 +214,15 @@ char *efi_convert_cmdline(efi_loaded_image_t *image,
254214
int *cmd_line_len, unsigned long max_addr)
255215
{
256216
const u16 *s2;
257-
u8 *s1 = NULL;
258217
unsigned long cmdline_addr = 0;
259-
int load_options_chars = efi_table_attr(image, load_options_size) / 2;
218+
int options_chars = efi_table_attr(image, load_options_size) / 2;
260219
const u16 *options = efi_table_attr(image, load_options);
261220
int options_bytes = 0; /* UTF-8 bytes */
262-
int options_chars = 0; /* UTF-16 chars */
263221
efi_status_t status;
264-
u16 zero = 0;
265222

266223
if (options) {
267224
s2 = options;
268-
while (options_chars < load_options_chars) {
225+
while (options_chars--) {
269226
u16 c = *s2++;
270227

271228
if (c == L'\0' || c == L'\n')
@@ -276,7 +233,6 @@ char *efi_convert_cmdline(efi_loaded_image_t *image,
276233
* The first part handles everything in the BMP.
277234
*/
278235
options_bytes += 1 + (c >= 0x80) + (c >= 0x800);
279-
options_chars++;
280236
/*
281237
* Add one more byte for valid surrogate pairs. Invalid
282238
* surrogates will be replaced with 0xfffd and take up
@@ -288,35 +244,25 @@ char *efi_convert_cmdline(efi_loaded_image_t *image,
288244
* we must ignore it since we can't access the
289245
* low surrogate.
290246
*/
291-
if (options_chars == load_options_chars) {
247+
if (!options_chars) {
292248
options_bytes -= 3;
293-
options_chars--;
294-
break;
295249
} else if ((*s2 & 0xfc00) == 0xdc00) {
296250
options_bytes++;
297-
options_chars++;
251+
options_chars--;
298252
s2++;
299253
}
300254
}
301255
}
302256
}
303257

304-
if (!options_chars) {
305-
/* No command line options, so return empty string*/
306-
options = &zero;
307-
}
308-
309258
options_bytes++; /* NUL termination */
310259

311260
status = efi_allocate_pages(options_bytes, &cmdline_addr, max_addr);
312261
if (status != EFI_SUCCESS)
313262
return NULL;
314263

315-
s1 = (u8 *)cmdline_addr;
316-
s2 = (const u16 *)options;
317-
318-
s1 = efi_utf16_to_utf8(s1, s2, options_chars);
319-
*s1 = '\0';
264+
snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
265+
options_bytes - 1, options);
320266

321267
*cmd_line_len = options_bytes;
322268
return (char *)cmdline_addr;

0 commit comments

Comments
 (0)