gummiboot/sd-boot/systemd-boot: rename galore
What used to be gummiboot, was renamed sd-boot when it was merged into systemd. Let's try to be a bit more consistent with the rest of systemd and rename it again as follows: The EFI bootloader is now called 'systemd-bootx64.efi', and its sources are in 'src/boot/efi/'. The drop-in directory where bootctl will find EFI loaders is now /usr/lib/systemd/boot/efi/.
This commit is contained in:
+17
-17
@@ -215,7 +215,7 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
/* search for "#### LoaderInfo: sd-boot 218 ####" string inside the binary */
|
||||
/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
|
||||
static int get_file_version(FILE *f, char **v) {
|
||||
struct stat st;
|
||||
char *buf;
|
||||
@@ -351,7 +351,7 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) {
|
||||
|
||||
r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
|
||||
if (r == 0)
|
||||
fprintf(stderr, "sd-boot not installed in ESP.\n");
|
||||
fprintf(stderr, "systemd-boot not installed in ESP.\n");
|
||||
else if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -710,7 +710,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
|
||||
_cleanup_free_ char *v = NULL;
|
||||
int r;
|
||||
|
||||
if (asprintf(&p, SD_BOOTLIBDIR "/%s", name) < 0) {
|
||||
if (asprintf(&p, BOOTLIBDIR "/%s", name) < 0) {
|
||||
fprintf(stderr, "Out of memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -722,11 +722,11 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
|
||||
|
||||
r = copy_file(p, q, force);
|
||||
|
||||
if (startswith(name, "sd-boot")) {
|
||||
if (startswith(name, "systemd-boot")) {
|
||||
int k;
|
||||
|
||||
/* Create the EFI default boot loader name (specified for removable devices) */
|
||||
if (asprintf(&v, "%s/EFI/Boot/BOOT%s", esp_path, name + strlen("sd-boot")) < 0) {
|
||||
if (asprintf(&v, "%s/EFI/Boot/BOOT%s", esp_path, name + strlen("systemd-boot")) < 0) {
|
||||
fprintf(stderr, "Out of memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -756,9 +756,9 @@ static int install_binaries(const char *esp_path, bool force) {
|
||||
return r;
|
||||
}
|
||||
|
||||
d = opendir(SD_BOOTLIBDIR);
|
||||
d = opendir(BOOTLIBDIR);
|
||||
if (!d) {
|
||||
fprintf(stderr, "Failed to open "SD_BOOTLIBDIR": %m\n");
|
||||
fprintf(stderr, "Failed to open "BOOTLIBDIR": %m\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
@@ -814,7 +814,7 @@ static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
|
||||
if (n_options < 0)
|
||||
return n_options;
|
||||
|
||||
/* find already existing sd-boot entry */
|
||||
/* find already existing systemd-boot entry */
|
||||
for (i = 0; i < n_options; i++)
|
||||
if (same_entry(options[i], uuid, path)) {
|
||||
new_id = options[i];
|
||||
@@ -1036,7 +1036,7 @@ static int remove_boot_efi(const char *esp_path) {
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (r > 0 && strncmp(v, "sd-boot ", 10) == 0) {
|
||||
if (r > 0 && strncmp(v, "systemd-boot ", 10) == 0) {
|
||||
|
||||
r = unlink(q);
|
||||
if (r < 0) {
|
||||
@@ -1089,7 +1089,7 @@ static int remove_binaries(const char *esp_path) {
|
||||
char *p;
|
||||
int r, q;
|
||||
|
||||
if (asprintf(&p, "%s/EFI/sd-boot", esp_path) < 0) {
|
||||
if (asprintf(&p, "%s/EFI/systemd-boot", esp_path) < 0) {
|
||||
fprintf(stderr, "Out of memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -1113,7 +1113,7 @@ static int remove_binaries(const char *esp_path) {
|
||||
if (q < 0 && r == 0)
|
||||
r = q;
|
||||
|
||||
q = rmdir_one(esp_path, "EFI/sd-boot");
|
||||
q = rmdir_one(esp_path, "EFI/systemd-boot");
|
||||
if (q < 0 && r == 0)
|
||||
r = q;
|
||||
|
||||
@@ -1196,10 +1196,10 @@ static int help(void) {
|
||||
" --no-variables Don't touch EFI variables\n"
|
||||
"\n"
|
||||
"Comands:\n"
|
||||
" status Show status of installed sd-boot and EFI variables\n"
|
||||
" install Install sd-boot to the ESP and EFI variables\n"
|
||||
" update Update sd-boot in the ESP and EFI variables\n"
|
||||
" remove Remove sd-boot from the ESP and EFI variables\n",
|
||||
" status Show status of installed systemd-boot and EFI variables\n"
|
||||
" install Install systemd-boot to the ESP and EFI variables\n"
|
||||
" update Update systemd-boot in the ESP and EFI variables\n"
|
||||
" remove Remove systemd-boot from the ESP and EFI variables\n",
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
@@ -1371,7 +1371,7 @@ static int bootctl_main(int argc, char*argv[]) {
|
||||
if (arg_touch_variables)
|
||||
r = install_variables(arg_path,
|
||||
part, pstart, psize, uuid,
|
||||
"/EFI/systemd/sd-boot" EFI_MACHINE_TYPE_NAME ".efi",
|
||||
"/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
|
||||
arg_action == ACTION_INSTALL);
|
||||
break;
|
||||
|
||||
@@ -1379,7 +1379,7 @@ static int bootctl_main(int argc, char*argv[]) {
|
||||
r = remove_binaries(arg_path);
|
||||
|
||||
if (arg_touch_variables) {
|
||||
q = remove_variables(uuid, "/EFI/systemd/sd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
|
||||
q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
|
||||
if (q < 0 && r == 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/sd_boot.so
|
||||
/stub.so
|
||||
+2023
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,141 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
|
||||
* Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "console.h"
|
||||
|
||||
#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
|
||||
{ 0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } }
|
||||
|
||||
struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET_EX)(
|
||||
struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
|
||||
BOOLEAN ExtendedVerification;
|
||||
);
|
||||
|
||||
typedef UINT8 EFI_KEY_TOGGLE_STATE;
|
||||
|
||||
typedef struct {
|
||||
UINT32 KeyShiftState;
|
||||
EFI_KEY_TOGGLE_STATE KeyToggleState;
|
||||
} EFI_KEY_STATE;
|
||||
|
||||
typedef struct {
|
||||
EFI_INPUT_KEY Key;
|
||||
EFI_KEY_STATE KeyState;
|
||||
} EFI_KEY_DATA;
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_INPUT_READ_KEY_EX)(
|
||||
struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
|
||||
EFI_KEY_DATA *KeyData;
|
||||
);
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_SET_STATE)(
|
||||
struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
|
||||
EFI_KEY_TOGGLE_STATE *KeyToggleState;
|
||||
);
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_KEY_NOTIFY_FUNCTION)(
|
||||
EFI_KEY_DATA *KeyData;
|
||||
);
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY)(
|
||||
struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
|
||||
EFI_KEY_DATA KeyData;
|
||||
EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction;
|
||||
VOID **NotifyHandle;
|
||||
);
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)(
|
||||
struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This;
|
||||
VOID *NotificationHandle;
|
||||
);
|
||||
|
||||
typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL {
|
||||
EFI_INPUT_RESET_EX Reset;
|
||||
EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx;
|
||||
EFI_EVENT WaitForKeyEx;
|
||||
EFI_SET_STATE SetState;
|
||||
EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify;
|
||||
EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify;
|
||||
} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL;
|
||||
|
||||
EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) {
|
||||
EFI_GUID EfiSimpleTextInputExProtocolGuid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
|
||||
static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx;
|
||||
static BOOLEAN checked;
|
||||
UINTN index;
|
||||
EFI_INPUT_KEY k;
|
||||
EFI_STATUS err;
|
||||
|
||||
if (!checked) {
|
||||
err = LibLocateProtocol(&EfiSimpleTextInputExProtocolGuid, (VOID **)&TextInputEx);
|
||||
if (EFI_ERROR(err))
|
||||
TextInputEx = NULL;
|
||||
|
||||
checked = TRUE;
|
||||
}
|
||||
|
||||
/* wait until key is pressed */
|
||||
if (wait) {
|
||||
if (TextInputEx)
|
||||
uefi_call_wrapper(BS->WaitForEvent, 3, 1, &TextInputEx->WaitForKeyEx, &index);
|
||||
else
|
||||
uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index);
|
||||
}
|
||||
|
||||
if (TextInputEx) {
|
||||
EFI_KEY_DATA keydata;
|
||||
UINT64 keypress;
|
||||
|
||||
err = uefi_call_wrapper(TextInputEx->ReadKeyStrokeEx, 2, TextInputEx, &keydata);
|
||||
if (!EFI_ERROR(err)) {
|
||||
UINT32 shift = 0;
|
||||
|
||||
/* do not distinguish between left and right keys */
|
||||
if (keydata.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) {
|
||||
if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED))
|
||||
shift |= EFI_CONTROL_PRESSED;
|
||||
if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED))
|
||||
shift |= EFI_ALT_PRESSED;
|
||||
};
|
||||
|
||||
/* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */
|
||||
keypress = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar);
|
||||
if (keypress > 0) {
|
||||
*key = keypress;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* fallback for firmware which does not support SimpleTextInputExProtocol
|
||||
*
|
||||
* This is also called in case ReadKeyStrokeEx did not return a key, because
|
||||
* some broken firmwares offer SimpleTextInputExProtocol, but never acually
|
||||
* handle any key. */
|
||||
err = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &k);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
*key = KEYPRESS(0, k.ScanCode, k.UnicodeChar);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
|
||||
* Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __SDBOOT_CONSOLE_H
|
||||
#define __SDBOOT_CONSOLE_H
|
||||
|
||||
#define EFI_SHIFT_STATE_VALID 0x80000000
|
||||
#define EFI_RIGHT_CONTROL_PRESSED 0x00000004
|
||||
#define EFI_LEFT_CONTROL_PRESSED 0x00000008
|
||||
#define EFI_RIGHT_ALT_PRESSED 0x00000010
|
||||
#define EFI_LEFT_ALT_PRESSED 0x00000020
|
||||
|
||||
#define EFI_CONTROL_PRESSED (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED)
|
||||
#define EFI_ALT_PRESSED (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED)
|
||||
#define KEYPRESS(keys, scan, uni) ((((UINT64)keys) << 32) | ((scan) << 16) | (uni))
|
||||
#define KEYCHAR(k) ((k) & 0xffff)
|
||||
#define CHAR_CTRL(c) ((c) - 'a' + 1)
|
||||
|
||||
EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait);
|
||||
#endif
|
||||
@@ -0,0 +1,389 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
|
||||
* Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
* Authored by Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "graphics.h"
|
||||
|
||||
EFI_STATUS graphics_mode(BOOLEAN on) {
|
||||
#define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \
|
||||
{ 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } };
|
||||
|
||||
struct _EFI_CONSOLE_CONTROL_PROTOCOL;
|
||||
|
||||
typedef enum {
|
||||
EfiConsoleControlScreenText,
|
||||
EfiConsoleControlScreenGraphics,
|
||||
EfiConsoleControlScreenMaxValue,
|
||||
} EFI_CONSOLE_CONTROL_SCREEN_MODE;
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE)(
|
||||
struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
|
||||
EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode,
|
||||
BOOLEAN *UgaExists,
|
||||
BOOLEAN *StdInLocked
|
||||
);
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE)(
|
||||
struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
|
||||
EFI_CONSOLE_CONTROL_SCREEN_MODE Mode
|
||||
);
|
||||
|
||||
typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN)(
|
||||
struct _EFI_CONSOLE_CONTROL_PROTOCOL *This,
|
||||
CHAR16 *Password
|
||||
);
|
||||
|
||||
typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL {
|
||||
EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode;
|
||||
EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode;
|
||||
EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn;
|
||||
} EFI_CONSOLE_CONTROL_PROTOCOL;
|
||||
|
||||
EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
|
||||
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
|
||||
EFI_CONSOLE_CONTROL_SCREEN_MODE new;
|
||||
EFI_CONSOLE_CONTROL_SCREEN_MODE current;
|
||||
BOOLEAN uga_exists;
|
||||
BOOLEAN stdin_locked;
|
||||
EFI_STATUS err;
|
||||
|
||||
err = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **)&ConsoleControl);
|
||||
if (EFI_ERROR(err)) {
|
||||
/* console control protocol is nonstandard and might not exist. */
|
||||
return err == EFI_NOT_FOUND ? EFI_SUCCESS : err;
|
||||
}
|
||||
|
||||
/* check current mode */
|
||||
err = uefi_call_wrapper(ConsoleControl->GetMode, 4, ConsoleControl, ¤t, &uga_exists, &stdin_locked);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
/* do not touch the mode */
|
||||
new = on ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText;
|
||||
if (new == current)
|
||||
return EFI_SUCCESS;
|
||||
|
||||
err = uefi_call_wrapper(ConsoleControl->SetMode, 2, ConsoleControl, new);
|
||||
|
||||
/* some firmware enables the cursor when switching modes */
|
||||
uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
struct bmp_file {
|
||||
CHAR8 signature[2];
|
||||
UINT32 size;
|
||||
UINT16 reserved[2];
|
||||
UINT32 offset;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* we require at least BITMAPINFOHEADER, later versions are
|
||||
accepted, but their features ignored */
|
||||
struct bmp_dib {
|
||||
UINT32 size;
|
||||
UINT32 x;
|
||||
UINT32 y;
|
||||
UINT16 planes;
|
||||
UINT16 depth;
|
||||
UINT32 compression;
|
||||
UINT32 image_size;
|
||||
INT32 x_pixel_meter;
|
||||
INT32 y_pixel_meter;
|
||||
UINT32 colors_used;
|
||||
UINT32 colors_important;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bmp_map {
|
||||
UINT8 blue;
|
||||
UINT8 green;
|
||||
UINT8 red;
|
||||
UINT8 reserved;
|
||||
} __attribute__((packed));
|
||||
|
||||
EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib,
|
||||
struct bmp_map **ret_map, UINT8 **pixmap) {
|
||||
struct bmp_file *file;
|
||||
struct bmp_dib *dib;
|
||||
struct bmp_map *map;
|
||||
UINTN row_size;
|
||||
|
||||
if (size < sizeof(struct bmp_file) + sizeof(struct bmp_dib))
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
/* check file header */
|
||||
file = (struct bmp_file *)bmp;
|
||||
if (file->signature[0] != 'B' || file->signature[1] != 'M')
|
||||
return EFI_INVALID_PARAMETER;
|
||||
if (file->size != size)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
if (file->size < file->offset)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
/* check device-independent bitmap */
|
||||
dib = (struct bmp_dib *)(bmp + sizeof(struct bmp_file));
|
||||
if (dib->size < sizeof(struct bmp_dib))
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
switch (dib->depth) {
|
||||
case 1:
|
||||
case 4:
|
||||
case 8:
|
||||
case 24:
|
||||
if (dib->compression != 0)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
break;
|
||||
|
||||
case 16:
|
||||
case 32:
|
||||
if (dib->compression != 0 && dib->compression != 3)
|
||||
return EFI_UNSUPPORTED;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
row_size = (((dib->depth * dib->x) + 31) / 32) * 4;
|
||||
if (file->size - file->offset < dib->y * row_size)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
if (row_size * dib->y > 64 * 1024 * 1024)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
/* check color table */
|
||||
map = (struct bmp_map *)(bmp + sizeof(struct bmp_file) + dib->size);
|
||||
if (file->offset < sizeof(struct bmp_file) + dib->size)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
|
||||
if (file->offset > sizeof(struct bmp_file) + dib->size) {
|
||||
UINT32 map_count;
|
||||
UINTN map_size;
|
||||
|
||||
if (dib->colors_used)
|
||||
map_count = dib->colors_used;
|
||||
else {
|
||||
switch (dib->depth) {
|
||||
case 1:
|
||||
case 4:
|
||||
case 8:
|
||||
map_count = 1 << dib->depth;
|
||||
break;
|
||||
|
||||
default:
|
||||
map_count = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
map_size = file->offset - (sizeof(struct bmp_file) + dib->size);
|
||||
if (map_size != sizeof(struct bmp_map) * map_count)
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*ret_map = map;
|
||||
*ret_dib = dib;
|
||||
*pixmap = bmp + file->offset;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static VOID pixel_blend(UINT32 *dst, const UINT32 source) {
|
||||
UINT32 alpha, src, src_rb, src_g, dst_rb, dst_g, rb, g;
|
||||
|
||||
alpha = (source & 0xff);
|
||||
|
||||
/* convert src from RGBA to XRGB */
|
||||
src = source >> 8;
|
||||
|
||||
/* decompose into RB and G components */
|
||||
src_rb = (src & 0xff00ff);
|
||||
src_g = (src & 0x00ff00);
|
||||
|
||||
dst_rb = (*dst & 0xff00ff);
|
||||
dst_g = (*dst & 0x00ff00);
|
||||
|
||||
/* blend */
|
||||
rb = ((((src_rb - dst_rb) * alpha + 0x800080) >> 8) + dst_rb) & 0xff00ff;
|
||||
g = ((((src_g - dst_g) * alpha + 0x008000) >> 8) + dst_g) & 0x00ff00;
|
||||
|
||||
*dst = (rb | g);
|
||||
}
|
||||
|
||||
EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
|
||||
struct bmp_dib *dib, struct bmp_map *map,
|
||||
UINT8 *pixmap) {
|
||||
UINT8 *in;
|
||||
UINTN y;
|
||||
|
||||
/* transform and copy pixels */
|
||||
in = pixmap;
|
||||
for (y = 0; y < dib->y; y++) {
|
||||
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *out;
|
||||
UINTN row_size;
|
||||
UINTN x;
|
||||
|
||||
out = &buf[(dib->y - y - 1) * dib->x];
|
||||
for (x = 0; x < dib->x; x++, in++, out++) {
|
||||
switch (dib->depth) {
|
||||
case 1: {
|
||||
UINTN i;
|
||||
|
||||
for (i = 0; i < 8 && x < dib->x; i++) {
|
||||
out->Red = map[((*in) >> (7 - i)) & 1].red;
|
||||
out->Green = map[((*in) >> (7 - i)) & 1].green;
|
||||
out->Blue = map[((*in) >> (7 - i)) & 1].blue;
|
||||
out++;
|
||||
x++;
|
||||
}
|
||||
out--;
|
||||
x--;
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: {
|
||||
UINTN i;
|
||||
|
||||
i = (*in) >> 4;
|
||||
out->Red = map[i].red;
|
||||
out->Green = map[i].green;
|
||||
out->Blue = map[i].blue;
|
||||
if (x < (dib->x - 1)) {
|
||||
out++;
|
||||
x++;
|
||||
i = (*in) & 0x0f;
|
||||
out->Red = map[i].red;
|
||||
out->Green = map[i].green;
|
||||
out->Blue = map[i].blue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 8:
|
||||
out->Red = map[*in].red;
|
||||
out->Green = map[*in].green;
|
||||
out->Blue = map[*in].blue;
|
||||
break;
|
||||
|
||||
case 16: {
|
||||
UINT16 i = *(UINT16 *) in;
|
||||
|
||||
out->Red = (i & 0x7c00) >> 7;
|
||||
out->Green = (i & 0x3e0) >> 2;
|
||||
out->Blue = (i & 0x1f) << 3;
|
||||
in += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case 24:
|
||||
out->Red = in[2];
|
||||
out->Green = in[1];
|
||||
out->Blue = in[0];
|
||||
in += 2;
|
||||
break;
|
||||
|
||||
case 32: {
|
||||
UINT32 i = *(UINT32 *) in;
|
||||
|
||||
pixel_blend((UINT32 *)out, i);
|
||||
|
||||
in += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add row padding; new lines always start at 32 bit boundary */
|
||||
row_size = in - pixmap;
|
||||
in += ((row_size + 3) & ~3) - row_size;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS graphics_splash(EFI_FILE *root_dir, CHAR16 *path,
|
||||
const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background) {
|
||||
EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
|
||||
UINT8 *content;
|
||||
INTN len;
|
||||
struct bmp_dib *dib;
|
||||
struct bmp_map *map;
|
||||
UINT8 *pixmap;
|
||||
UINT64 blt_size;
|
||||
VOID *blt = NULL;
|
||||
UINTN x_pos = 0;
|
||||
UINTN y_pos = 0;
|
||||
EFI_STATUS err;
|
||||
|
||||
err = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
len = file_read(root_dir, path, 0, 0, &content);
|
||||
if (len < 0)
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
err = bmp_parse_header(content, len, &dib, &map, &pixmap);
|
||||
if (EFI_ERROR(err))
|
||||
goto err;
|
||||
|
||||
if(dib->x < GraphicsOutput->Mode->Info->HorizontalResolution)
|
||||
x_pos = (GraphicsOutput->Mode->Info->HorizontalResolution - dib->x) / 2;
|
||||
if(dib->y < GraphicsOutput->Mode->Info->VerticalResolution)
|
||||
y_pos = (GraphicsOutput->Mode->Info->VerticalResolution - dib->y) / 2;
|
||||
|
||||
uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
|
||||
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)background,
|
||||
EfiBltVideoFill, 0, 0, 0, 0,
|
||||
GraphicsOutput->Mode->Info->HorizontalResolution,
|
||||
GraphicsOutput->Mode->Info->VerticalResolution, 0);
|
||||
|
||||
/* EFI buffer */
|
||||
blt_size = dib->x * dib->y * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
|
||||
blt = AllocatePool(blt_size);
|
||||
if (!blt)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
err = uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
|
||||
blt, EfiBltVideoToBltBuffer, x_pos, y_pos, 0, 0,
|
||||
dib->x, dib->y, 0);
|
||||
if (EFI_ERROR(err))
|
||||
goto err;
|
||||
|
||||
err = bmp_to_blt(blt, dib, map, pixmap);
|
||||
if (EFI_ERROR(err))
|
||||
goto err;
|
||||
|
||||
err = graphics_mode(TRUE);
|
||||
if (EFI_ERROR(err))
|
||||
goto err;
|
||||
|
||||
err = uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
|
||||
blt, EfiBltBufferToVideo, 0, 0, x_pos, y_pos,
|
||||
dib->x, dib->y, 0);
|
||||
err:
|
||||
FreePool(blt);
|
||||
FreePool(content);
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
|
||||
* Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
* Authored by Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifndef __SDBOOT_GRAPHICS_H
|
||||
#define __SDBOOT_GRAPHICS_H
|
||||
|
||||
EFI_STATUS graphics_mode(BOOLEAN on);
|
||||
EFI_STATUS graphics_splash(EFI_FILE *root_dir, CHAR16 *path,
|
||||
const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background);
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "linux.h"
|
||||
|
||||
#define SETUP_MAGIC 0x53726448 /* "HdrS" */
|
||||
struct SetupHeader {
|
||||
UINT8 boot_sector[0x01f1];
|
||||
UINT8 setup_secs;
|
||||
UINT16 root_flags;
|
||||
UINT32 sys_size;
|
||||
UINT16 ram_size;
|
||||
UINT16 video_mode;
|
||||
UINT16 root_dev;
|
||||
UINT16 signature;
|
||||
UINT16 jump;
|
||||
UINT32 header;
|
||||
UINT16 version;
|
||||
UINT16 su_switch;
|
||||
UINT16 setup_seg;
|
||||
UINT16 start_sys;
|
||||
UINT16 kernel_ver;
|
||||
UINT8 loader_id;
|
||||
UINT8 load_flags;
|
||||
UINT16 movesize;
|
||||
UINT32 code32_start;
|
||||
UINT32 ramdisk_start;
|
||||
UINT32 ramdisk_len;
|
||||
UINT32 bootsect_kludge;
|
||||
UINT16 heap_end;
|
||||
UINT8 ext_loader_ver;
|
||||
UINT8 ext_loader_type;
|
||||
UINT32 cmd_line_ptr;
|
||||
UINT32 ramdisk_max;
|
||||
UINT32 kernel_alignment;
|
||||
UINT8 relocatable_kernel;
|
||||
UINT8 min_alignment;
|
||||
UINT16 xloadflags;
|
||||
UINT32 cmdline_size;
|
||||
UINT32 hardware_subarch;
|
||||
UINT64 hardware_subarch_data;
|
||||
UINT32 payload_offset;
|
||||
UINT32 payload_length;
|
||||
UINT64 setup_data;
|
||||
UINT64 pref_address;
|
||||
UINT32 init_size;
|
||||
UINT32 handover_offset;
|
||||
} __attribute__((packed));
|
||||
|
||||
#ifdef __x86_64__
|
||||
typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup);
|
||||
static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) {
|
||||
handover_f handover;
|
||||
|
||||
asm volatile ("cli");
|
||||
handover = (handover_f)((UINTN)setup->code32_start + 512 + setup->handover_offset);
|
||||
handover(image, ST, setup);
|
||||
}
|
||||
#else
|
||||
typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup) __attribute__((regparm(0)));
|
||||
static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) {
|
||||
handover_f handover;
|
||||
|
||||
handover = (handover_f)((UINTN)setup->code32_start + setup->handover_offset);
|
||||
handover(image, ST, setup);
|
||||
}
|
||||
#endif
|
||||
|
||||
EFI_STATUS linux_exec(EFI_HANDLE *image,
|
||||
CHAR8 *cmdline, UINTN cmdline_len,
|
||||
UINTN linux_addr,
|
||||
UINTN initrd_addr, UINTN initrd_size) {
|
||||
struct SetupHeader *image_setup;
|
||||
struct SetupHeader *boot_setup;
|
||||
EFI_PHYSICAL_ADDRESS addr;
|
||||
EFI_STATUS err;
|
||||
|
||||
image_setup = (struct SetupHeader *)(linux_addr);
|
||||
if (image_setup->signature != 0xAA55 || image_setup->header != SETUP_MAGIC)
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
if (image_setup->version < 0x20b || !image_setup->relocatable_kernel)
|
||||
return EFI_LOAD_ERROR;
|
||||
|
||||
addr = 0x3fffffff;
|
||||
err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData,
|
||||
EFI_SIZE_TO_PAGES(0x4000), &addr);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
boot_setup = (struct SetupHeader *)(UINTN)addr;
|
||||
ZeroMem(boot_setup, 0x4000);
|
||||
CopyMem(boot_setup, image_setup, sizeof(struct SetupHeader));
|
||||
boot_setup->loader_id = 0xff;
|
||||
|
||||
boot_setup->code32_start = (UINT32)linux_addr + (image_setup->setup_secs+1) * 512;
|
||||
|
||||
if (cmdline) {
|
||||
addr = 0xA0000;
|
||||
err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData,
|
||||
EFI_SIZE_TO_PAGES(cmdline_len + 1), &addr);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len);
|
||||
((CHAR8 *)addr)[cmdline_len] = 0;
|
||||
boot_setup->cmd_line_ptr = (UINT32)addr;
|
||||
}
|
||||
|
||||
boot_setup->ramdisk_start = (UINT32)initrd_addr;
|
||||
boot_setup->ramdisk_len = (UINT32)initrd_size;
|
||||
|
||||
linux_efi_handover(image, boot_setup);
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
|
||||
*/
|
||||
|
||||
#ifndef __SDBOOT_kernel_H
|
||||
#define __SDBOOT_kernel_H
|
||||
|
||||
EFI_STATUS linux_exec(EFI_HANDLE *image,
|
||||
CHAR8 *cmdline, UINTN cmdline_size,
|
||||
UINTN linux_addr,
|
||||
UINTN initrd_addr, UINTN initrd_size);
|
||||
#endif
|
||||
@@ -0,0 +1,172 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "pefile.h"
|
||||
|
||||
struct DosFileHeader {
|
||||
UINT8 Magic[2];
|
||||
UINT16 LastSize;
|
||||
UINT16 nBlocks;
|
||||
UINT16 nReloc;
|
||||
UINT16 HdrSize;
|
||||
UINT16 MinAlloc;
|
||||
UINT16 MaxAlloc;
|
||||
UINT16 ss;
|
||||
UINT16 sp;
|
||||
UINT16 Checksum;
|
||||
UINT16 ip;
|
||||
UINT16 cs;
|
||||
UINT16 RelocPos;
|
||||
UINT16 nOverlay;
|
||||
UINT16 reserved[4];
|
||||
UINT16 OEMId;
|
||||
UINT16 OEMInfo;
|
||||
UINT16 reserved2[10];
|
||||
UINT32 ExeHeader;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define PE_HEADER_MACHINE_I386 0x014c
|
||||
#define PE_HEADER_MACHINE_X64 0x8664
|
||||
struct PeFileHeader {
|
||||
UINT16 Machine;
|
||||
UINT16 NumberOfSections;
|
||||
UINT32 TimeDateStamp;
|
||||
UINT32 PointerToSymbolTable;
|
||||
UINT32 NumberOfSymbols;
|
||||
UINT16 SizeOfOptionalHeader;
|
||||
UINT16 Characteristics;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct PeSectionHeader {
|
||||
UINT8 Name[8];
|
||||
UINT32 VirtualSize;
|
||||
UINT32 VirtualAddress;
|
||||
UINT32 SizeOfRawData;
|
||||
UINT32 PointerToRawData;
|
||||
UINT32 PointerToRelocations;
|
||||
UINT32 PointerToLinenumbers;
|
||||
UINT16 NumberOfRelocations;
|
||||
UINT16 NumberOfLinenumbers;
|
||||
UINT32 Characteristics;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
EFI_STATUS pefile_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
|
||||
EFI_FILE_HANDLE handle;
|
||||
struct DosFileHeader dos;
|
||||
uint8_t magic[4];
|
||||
struct PeFileHeader pe;
|
||||
UINTN len;
|
||||
UINTN i;
|
||||
EFI_STATUS err;
|
||||
|
||||
err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
/* MS-DOS stub */
|
||||
len = sizeof(dos);
|
||||
err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos);
|
||||
if (EFI_ERROR(err))
|
||||
goto out;
|
||||
if (len != sizeof(dos)) {
|
||||
err = EFI_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (CompareMem(dos.Magic, "MZ", 2) != 0) {
|
||||
err = EFI_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader);
|
||||
if (EFI_ERROR(err))
|
||||
goto out;
|
||||
|
||||
/* PE header */
|
||||
len = sizeof(magic);
|
||||
err = uefi_call_wrapper(handle->Read, 3, handle, &len, &magic);
|
||||
if (EFI_ERROR(err))
|
||||
goto out;
|
||||
if (len != sizeof(magic)) {
|
||||
err = EFI_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (CompareMem(magic, "PE\0\0", 2) != 0) {
|
||||
err = EFI_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = sizeof(pe);
|
||||
err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe);
|
||||
if (EFI_ERROR(err))
|
||||
goto out;
|
||||
if (len != sizeof(pe)) {
|
||||
err = EFI_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* PE32+ Subsystem type */
|
||||
if (pe.Machine != PE_HEADER_MACHINE_X64 &&
|
||||
pe.Machine != PE_HEADER_MACHINE_I386) {
|
||||
err = EFI_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pe.NumberOfSections > 96) {
|
||||
err = EFI_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* the sections start directly after the headers */
|
||||
err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader + sizeof(magic) + sizeof(pe) + pe.SizeOfOptionalHeader);
|
||||
if (EFI_ERROR(err))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < pe.NumberOfSections; i++) {
|
||||
struct PeSectionHeader sect;
|
||||
UINTN j;
|
||||
|
||||
len = sizeof(sect);
|
||||
err = uefi_call_wrapper(handle->Read, 3, handle, &len, §);
|
||||
if (EFI_ERROR(err))
|
||||
goto out;
|
||||
if (len != sizeof(sect)) {
|
||||
err = EFI_LOAD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
for (j = 0; sections[j]; j++) {
|
||||
if (CompareMem(sect.Name, sections[j], strlena(sections[j])) != 0)
|
||||
continue;
|
||||
|
||||
if (addrs)
|
||||
addrs[j] = (UINTN)sect.VirtualAddress;
|
||||
if (offsets)
|
||||
offsets[j] = (UINTN)sect.PointerToRawData;
|
||||
if (sizes)
|
||||
sizes[j] = (UINTN)sect.VirtualSize;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
uefi_call_wrapper(handle->Close, 1, handle);
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
|
||||
*/
|
||||
|
||||
#ifndef __SDBOOT_PEFILE_H
|
||||
#define __SDBOOT_PEFILE_H
|
||||
|
||||
EFI_STATUS pefile_locate_sections(EFI_FILE *dir, CHAR16 *path,
|
||||
CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes);
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "pefile.h"
|
||||
#include "linux.h"
|
||||
|
||||
/* magic string to find in the binary image */
|
||||
static const char __attribute__((used)) magic[] = "#### LoaderInfo: stub " VERSION " ####";
|
||||
|
||||
static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE;
|
||||
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
EFI_LOADED_IMAGE *loaded_image;
|
||||
EFI_FILE *root_dir;
|
||||
CHAR16 *loaded_image_path;
|
||||
CHAR8 *b;
|
||||
UINTN size;
|
||||
BOOLEAN secure = FALSE;
|
||||
CHAR8 *sections[] = {
|
||||
(UINT8 *)".cmdline",
|
||||
(UINT8 *)".linux",
|
||||
(UINT8 *)".initrd",
|
||||
NULL
|
||||
};
|
||||
UINTN addrs[ELEMENTSOF(sections)-1] = {};
|
||||
UINTN offs[ELEMENTSOF(sections)-1] = {};
|
||||
UINTN szs[ELEMENTSOF(sections)-1] = {};
|
||||
CHAR8 *cmdline = NULL;
|
||||
UINTN cmdline_len;
|
||||
EFI_STATUS err;
|
||||
|
||||
InitializeLib(image, sys_table);
|
||||
|
||||
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
|
||||
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (EFI_ERROR(err)) {
|
||||
Print(L"Error getting a LoadedImageProtocol handle: %r ", err);
|
||||
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
return err;
|
||||
}
|
||||
|
||||
root_dir = LibOpenRoot(loaded_image->DeviceHandle);
|
||||
if (!root_dir) {
|
||||
Print(L"Unable to open root directory: %r ", err);
|
||||
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
loaded_image_path = DevicePathToStr(loaded_image->FilePath);
|
||||
|
||||
if (efivar_get_raw(&global_guid, L"SecureBoot", &b, &size) == EFI_SUCCESS) {
|
||||
if (*b > 0)
|
||||
secure = TRUE;
|
||||
FreePool(b);
|
||||
}
|
||||
|
||||
err = pefile_locate_sections(root_dir, loaded_image_path, sections, addrs, offs, szs);
|
||||
if (EFI_ERROR(err)) {
|
||||
Print(L"Unable to locate embedded .linux section: %r ", err);
|
||||
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (szs[0] > 0)
|
||||
cmdline = (CHAR8 *)(loaded_image->ImageBase + addrs[0]);
|
||||
|
||||
cmdline_len = szs[0];
|
||||
|
||||
/* if we are not in secure boot mode, accept a custom command line and replace the built-in one */
|
||||
if (!secure && loaded_image->LoadOptionsSize > 0) {
|
||||
CHAR16 *options;
|
||||
CHAR8 *line;
|
||||
UINTN i;
|
||||
|
||||
options = (CHAR16 *)loaded_image->LoadOptions;
|
||||
cmdline_len = (loaded_image->LoadOptionsSize / sizeof(CHAR16)) * sizeof(CHAR8);
|
||||
line = AllocatePool(cmdline_len);
|
||||
for (i = 0; i < cmdline_len; i++)
|
||||
line[i] = options[i];
|
||||
cmdline = line;
|
||||
}
|
||||
|
||||
err = linux_exec(image, cmdline, cmdline_len,
|
||||
(UINTN)loaded_image->ImageBase + addrs[1],
|
||||
(UINTN)loaded_image->ImageBase + addrs[2], szs[2]);
|
||||
|
||||
Print(L"Execution of embedded linux image failed: %r\n", err);
|
||||
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
|
||||
* Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
|
||||
*/
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* Allocated random UUID, intended to be shared across tools that implement
|
||||
* the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the
|
||||
* associated EFI variables.
|
||||
*/
|
||||
static const EFI_GUID loader_guid = { 0x4a67b082, 0x0a4c, 0x41cf, {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f} };
|
||||
|
||||
#ifdef __x86_64__
|
||||
UINT64 ticks_read(VOID) {
|
||||
UINT64 a, d;
|
||||
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
|
||||
return (d << 32) | a;
|
||||
}
|
||||
#else
|
||||
UINT64 ticks_read(VOID) {
|
||||
UINT64 val;
|
||||
__asm__ volatile ("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* count TSC ticks during a millisecond delay */
|
||||
UINT64 ticks_freq(VOID) {
|
||||
UINT64 ticks_start, ticks_end;
|
||||
|
||||
ticks_start = ticks_read();
|
||||
uefi_call_wrapper(BS->Stall, 1, 1000);
|
||||
ticks_end = ticks_read();
|
||||
|
||||
return (ticks_end - ticks_start) * 1000;
|
||||
}
|
||||
|
||||
UINT64 time_usec(VOID) {
|
||||
UINT64 ticks;
|
||||
static UINT64 freq;
|
||||
|
||||
ticks = ticks_read();
|
||||
if (ticks == 0)
|
||||
return 0;
|
||||
|
||||
if (freq == 0) {
|
||||
freq = ticks_freq();
|
||||
if (freq == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1000 * 1000 * ticks / freq;
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) {
|
||||
UINT32 flags;
|
||||
|
||||
flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
|
||||
if (persistent)
|
||||
flags |= EFI_VARIABLE_NON_VOLATILE;
|
||||
|
||||
return uefi_call_wrapper(RT->SetVariable, 5, name, (EFI_GUID *)vendor, flags, size, buf);
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent) {
|
||||
return efivar_set_raw(&loader_guid, name, (CHAR8 *)value, value ? (StrLen(value)+1) * sizeof(CHAR16) : 0, persistent);
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent) {
|
||||
CHAR16 str[32];
|
||||
|
||||
SPrint(str, 32, L"%d", i);
|
||||
return efivar_set(name, str, persistent);
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value) {
|
||||
CHAR8 *buf;
|
||||
CHAR16 *val;
|
||||
UINTN size;
|
||||
EFI_STATUS err;
|
||||
|
||||
err = efivar_get_raw(&loader_guid, name, &buf, &size);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
val = StrDuplicate((CHAR16 *)buf);
|
||||
if (!val) {
|
||||
FreePool(buf);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
*value = val;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i) {
|
||||
CHAR16 *val;
|
||||
EFI_STATUS err;
|
||||
|
||||
err = efivar_get(name, &val);
|
||||
if (!EFI_ERROR(err)) {
|
||||
*i = Atoi(val);
|
||||
FreePool(val);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) {
|
||||
CHAR8 *buf;
|
||||
UINTN l;
|
||||
EFI_STATUS err;
|
||||
|
||||
l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE;
|
||||
buf = AllocatePool(l);
|
||||
if (!buf)
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
|
||||
err = uefi_call_wrapper(RT->GetVariable, 5, name, (EFI_GUID *)vendor, NULL, &l, buf);
|
||||
if (!EFI_ERROR(err)) {
|
||||
*buffer = buf;
|
||||
if (size)
|
||||
*size = l;
|
||||
} else
|
||||
FreePool(buf);
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec) {
|
||||
CHAR16 str[32];
|
||||
|
||||
if (usec == 0)
|
||||
usec = time_usec();
|
||||
if (usec == 0)
|
||||
return;
|
||||
|
||||
SPrint(str, 32, L"%ld", usec);
|
||||
efivar_set(name, str, FALSE);
|
||||
}
|
||||
|
||||
static INTN utf8_to_16(CHAR8 *stra, CHAR16 *c) {
|
||||
CHAR16 unichar;
|
||||
UINTN len;
|
||||
UINTN i;
|
||||
|
||||
if (stra[0] < 0x80)
|
||||
len = 1;
|
||||
else if ((stra[0] & 0xe0) == 0xc0)
|
||||
len = 2;
|
||||
else if ((stra[0] & 0xf0) == 0xe0)
|
||||
len = 3;
|
||||
else if ((stra[0] & 0xf8) == 0xf0)
|
||||
len = 4;
|
||||
else if ((stra[0] & 0xfc) == 0xf8)
|
||||
len = 5;
|
||||
else if ((stra[0] & 0xfe) == 0xfc)
|
||||
len = 6;
|
||||
else
|
||||
return -1;
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
unichar = stra[0];
|
||||
break;
|
||||
case 2:
|
||||
unichar = stra[0] & 0x1f;
|
||||
break;
|
||||
case 3:
|
||||
unichar = stra[0] & 0x0f;
|
||||
break;
|
||||
case 4:
|
||||
unichar = stra[0] & 0x07;
|
||||
break;
|
||||
case 5:
|
||||
unichar = stra[0] & 0x03;
|
||||
break;
|
||||
case 6:
|
||||
unichar = stra[0] & 0x01;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 1; i < len; i++) {
|
||||
if ((stra[i] & 0xc0) != 0x80)
|
||||
return -1;
|
||||
unichar <<= 6;
|
||||
unichar |= stra[i] & 0x3f;
|
||||
}
|
||||
|
||||
*c = unichar;
|
||||
return len;
|
||||
}
|
||||
|
||||
CHAR16 *stra_to_str(CHAR8 *stra) {
|
||||
UINTN strlen;
|
||||
UINTN len;
|
||||
UINTN i;
|
||||
CHAR16 *str;
|
||||
|
||||
len = strlena(stra);
|
||||
str = AllocatePool((len + 1) * sizeof(CHAR16));
|
||||
|
||||
strlen = 0;
|
||||
i = 0;
|
||||
while (i < len) {
|
||||
INTN utf8len;
|
||||
|
||||
utf8len = utf8_to_16(stra + i, str + strlen);
|
||||
if (utf8len <= 0) {
|
||||
/* invalid utf8 sequence, skip the garbage */
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
strlen++;
|
||||
i += utf8len;
|
||||
}
|
||||
str[strlen] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
CHAR16 *stra_to_path(CHAR8 *stra) {
|
||||
CHAR16 *str;
|
||||
UINTN strlen;
|
||||
UINTN len;
|
||||
UINTN i;
|
||||
|
||||
len = strlena(stra);
|
||||
str = AllocatePool((len + 2) * sizeof(CHAR16));
|
||||
|
||||
str[0] = '\\';
|
||||
strlen = 1;
|
||||
i = 0;
|
||||
while (i < len) {
|
||||
INTN utf8len;
|
||||
|
||||
utf8len = utf8_to_16(stra + i, str + strlen);
|
||||
if (utf8len <= 0) {
|
||||
/* invalid utf8 sequence, skip the garbage */
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str[strlen] == '/')
|
||||
str[strlen] = '\\';
|
||||
if (str[strlen] == '\\' && str[strlen-1] == '\\') {
|
||||
/* skip double slashes */
|
||||
i += utf8len;
|
||||
continue;
|
||||
}
|
||||
|
||||
strlen++;
|
||||
i += utf8len;
|
||||
}
|
||||
str[strlen] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
CHAR8 *strchra(CHAR8 *s, CHAR8 c) {
|
||||
do {
|
||||
if (*s == c)
|
||||
return s;
|
||||
} while (*s++);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content) {
|
||||
EFI_FILE_HANDLE handle;
|
||||
CHAR8 *buf;
|
||||
UINTN buflen;
|
||||
EFI_STATUS err;
|
||||
UINTN len;
|
||||
|
||||
err = uefi_call_wrapper(dir->Open, 5, dir, &handle, name, EFI_FILE_MODE_READ, 0ULL);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
|
||||
if (size == 0) {
|
||||
EFI_FILE_INFO *info;
|
||||
|
||||
info = LibFileInfo(handle);
|
||||
buflen = info->FileSize+1;
|
||||
FreePool(info);
|
||||
} else
|
||||
buflen = size;
|
||||
|
||||
if (off > 0) {
|
||||
err = uefi_call_wrapper(handle->SetPosition, 2, handle, off);
|
||||
if (EFI_ERROR(err))
|
||||
return err;
|
||||
}
|
||||
|
||||
buf = AllocatePool(buflen);
|
||||
err = uefi_call_wrapper(handle->Read, 3, handle, &buflen, buf);
|
||||
if (!EFI_ERROR(err)) {
|
||||
buf[buflen] = '\0';
|
||||
*content = buf;
|
||||
len = buflen;
|
||||
} else {
|
||||
len = err;
|
||||
FreePool(buf);
|
||||
}
|
||||
|
||||
uefi_call_wrapper(handle->Close, 1, handle);
|
||||
return len;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org>
|
||||
* Copyright (C) 2012 Harald Hoyer <harald@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __SDBOOT_UTIL_H
|
||||
#define __SDBOOT_UTIL_H
|
||||
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
UINT64 ticks_read(void);
|
||||
UINT64 ticks_freq(void);
|
||||
UINT64 time_usec(void);
|
||||
|
||||
EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent);
|
||||
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent);
|
||||
EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent);
|
||||
VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec);
|
||||
|
||||
EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value);
|
||||
EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size);
|
||||
EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i);
|
||||
|
||||
CHAR8 *strchra(CHAR8 *s, CHAR8 c);
|
||||
CHAR16 *stra_to_path(CHAR8 *stra);
|
||||
CHAR16 *stra_to_str(CHAR8 *stra);
|
||||
|
||||
INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content);
|
||||
#endif
|
||||
Reference in New Issue
Block a user