summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2015-04-19 13:27:42 +0200
committerAndy Wingo <wingo@pobox.com>2015-04-19 13:27:42 +0200
commit9d2fd3600e0e3c313b6ca57665c2683fab9f9063 (patch)
tree1728c29b232256dc8008fd6086a1051900d8ff98
parent17366dcbe347c0a96df513268cb7acfed9b8f1f9 (diff)
Remove src/boot
l---------src/boot/Makefile1
-rw-r--r--src/boot/bootctl.c1404
-rw-r--r--src/boot/efi/.gitignore2
-rw-r--r--src/boot/efi/boot.c1834
-rw-r--r--src/boot/efi/console.c141
-rw-r--r--src/boot/efi/console.h34
-rw-r--r--src/boot/efi/graphics.c91
-rw-r--r--src/boot/efi/graphics.h24
-rw-r--r--src/boot/efi/linux.c130
-rw-r--r--src/boot/efi/linux.h24
-rw-r--r--src/boot/efi/pefile.c172
-rw-r--r--src/boot/efi/pefile.h22
-rw-r--r--src/boot/efi/splash.c323
-rw-r--r--src/boot/efi/splash.h22
-rw-r--r--src/boot/efi/stub.c113
-rw-r--r--src/boot/efi/util.c342
-rw-r--r--src/boot/efi/util.h50
17 files changed, 0 insertions, 4729 deletions
diff --git a/src/boot/Makefile b/src/boot/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/boot/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
deleted file mode 100644
index bc1405145e..0000000000
--- a/src/boot/bootctl.c
+++ /dev/null
@@ -1,1404 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2013-2015 Kay Sievers
- Copyright 2013 Lennart Poettering
-
- systemd 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.
-
- systemd 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.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdio.h>
-#include <getopt.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <sys/statfs.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <limits.h>
-#include <ftw.h>
-#include <stdbool.h>
-#include <blkid/blkid.h>
-
-#include "efivars.h"
-#include "build.h"
-#include "util.h"
-
-static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) {
- struct statfs sfs;
- struct stat st, st2;
- char *t;
- blkid_probe b = NULL;
- int r;
- const char *v;
-
- if (statfs(p, &sfs) < 0) {
- fprintf(stderr, "Failed to check file system type of %s: %m\n", p);
- return -errno;
- }
-
- if (sfs.f_type != 0x4d44) {
- fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system.\n", p);
- return -ENODEV;
- }
-
- if (stat(p, &st) < 0) {
- fprintf(stderr, "Failed to determine block device node of %s: %m\n", p);
- return -errno;
- }
-
- if (major(st.st_dev) == 0) {
- fprintf(stderr, "Block device node of %p is invalid.\n", p);
- return -ENODEV;
- }
-
- r = asprintf(&t, "%s/..", p);
- if (r < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- r = stat(t, &st2);
- free(t);
- if (r < 0) {
- fprintf(stderr, "Failed to determine block device node of parent of %s: %m\n", p);
- return -errno;
- }
-
- if (st.st_dev == st2.st_dev) {
- fprintf(stderr, "Directory %s is not the root of the EFI System Partition (ESP) file system.\n", p);
- return -ENODEV;
- }
-
- r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev));
- if (r < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- errno = 0;
- b = blkid_new_probe_from_filename(t);
- free(t);
- if (!b) {
- if (errno != 0) {
- fprintf(stderr, "Failed to open file system %s: %m\n", p);
- return -errno;
- }
-
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- blkid_probe_enable_superblocks(b, 1);
- blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
- blkid_probe_enable_partitions(b, 1);
- blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
-
- errno = 0;
- r = blkid_do_safeprobe(b);
- if (r == -2) {
- fprintf(stderr, "File system %s is ambigious.\n", p);
- r = -ENODEV;
- goto fail;
- } else if (r == 1) {
- fprintf(stderr, "File system %s does not contain a label.\n", p);
- r = -ENODEV;
- goto fail;
- } else if (r != 0) {
- r = errno ? -errno : -EIO;
- fprintf(stderr, "Failed to probe file system %s: %s\n", p, strerror(-r));
- goto fail;
- }
-
- errno = 0;
- r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
- if (r != 0) {
- r = errno ? -errno : -EIO;
- fprintf(stderr, "Failed to probe file system type %s: %s\n", p, strerror(-r));
- goto fail;
- }
-
- if (strcmp(v, "vfat") != 0) {
- fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system after all.\n", p);
- r = -ENODEV;
- goto fail;
- }
-
- errno = 0;
- r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
- if (r != 0) {
- r = errno ? -errno : -EIO;
- fprintf(stderr, "Failed to probe partition scheme %s: %s\n", p, strerror(-r));
- goto fail;
- }
-
- if (strcmp(v, "gpt") != 0) {
- fprintf(stderr, "File system %s is not on a GPT partition table.\n", p);
- r = -ENODEV;
- goto fail;
- }
-
- errno = 0;
- r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
- if (r != 0) {
- r = errno ? -errno : -EIO;
- fprintf(stderr, "Failed to probe partition type UUID %s: %s\n", p, strerror(-r));
- goto fail;
- }
-
- if (strcmp(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b") != 0) {
- r = -ENODEV;
- fprintf(stderr, "File system %s is not an EFI System Partition (ESP).\n", p);
- goto fail;
- }
-
- errno = 0;
- r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
- if (r != 0) {
- r = errno ? -errno : -EIO;
- fprintf(stderr, "Failed to probe partition entry UUID %s: %s\n", p, strerror(-r));
- goto fail;
- }
-
- r = sd_id128_from_string(v, uuid);
- if (r < 0) {
- fprintf(stderr, "Partition %s has invalid UUID: %s\n", p, v);
- r = -EIO;
- goto fail;
- }
-
- errno = 0;
- r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
- if (r != 0) {
- r = errno ? -errno : -EIO;
- fprintf(stderr, "Failed to probe partition number %s: %s\n", p, strerror(-r));
- goto fail;
- }
- *part = strtoul(v, NULL, 10);
-
- errno = 0;
- r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
- if (r != 0) {
- r = errno ? -errno : -EIO;
- fprintf(stderr, "Failed to probe partition offset %s: %s\n", p, strerror(-r));
- goto fail;
- }
- *pstart = strtoul(v, NULL, 10);
-
- errno = 0;
- r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
- if (r != 0) {
- r = errno ? -errno : -EIO;
- fprintf(stderr, "Failed to probe partition size %s: %s\n", p, strerror(-r));
- goto fail;
- }
- *psize = strtoul(v, NULL, 10);
-
- blkid_free_probe(b);
- return 0;
-fail:
- if (b)
- blkid_free_probe(b);
- return r;
-}
-
-/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
-static int get_file_version(FILE *f, char **v) {
- struct stat st;
- char *buf;
- const char *s, *e;
- char *x = NULL;
- int r = 0;
-
- assert(f);
- assert(v);
-
- if (fstat(fileno(f), &st) < 0)
- return -errno;
-
- if (st.st_size < 27)
- return 0;
-
- buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fileno(f), 0);
- if (buf == MAP_FAILED)
- return -errno;
-
- s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17);
- if (!s)
- goto finish;
- s += 17;
-
- e = memmem(s, st.st_size - (s - buf), " ####", 5);
- if (!e || e - s < 3) {
- fprintf(stderr, "Malformed version string.\n");
- r = -EINVAL;
- goto finish;
- }
-
- x = strndup(s, e - s);
- if (!x) {
- fprintf(stderr, "Out of memory.\n");
- r = -ENOMEM;
- goto finish;
- }
- r = 1;
-
-finish:
- munmap(buf, st.st_size);
- *v = x;
- return r;
-}
-
-static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
- struct dirent *de;
- char *p = NULL, *q = NULL;
- DIR *d = NULL;
- int r = 0, c = 0;
-
- if (asprintf(&p, "%s/%s", esp_path, path) < 0) {
- fprintf(stderr, "Out of memory.\n");
- r = -ENOMEM;
- goto finish;
- }
-
- d = opendir(p);
- if (!d) {
- if (errno == ENOENT) {
- r = 0;
- goto finish;
- }
-
- fprintf(stderr, "Failed to read %s: %m\n", p);
- r = -errno;
- goto finish;
- }
-
- while ((de = readdir(d))) {
- char *v;
- size_t n;
- FILE *f;
-
- if (de->d_name[0] == '.')
- continue;
-
- n = strlen(de->d_name);
- if (n < 4 || strcasecmp(de->d_name + n - 4, ".efi") != 0)
- continue;
-
- if (prefix && strncasecmp(de->d_name, prefix, strlen(prefix)) != 0)
- continue;
-
- free(q);
- q = NULL;
- if (asprintf(&q, "%s/%s/%s", esp_path, path, de->d_name) < 0) {
- fprintf(stderr, "Out of memory.\n");
- r = -ENOMEM;
- goto finish;
- }
-
- f = fopen(q, "re");
- if (!f) {
- fprintf(stderr, "Failed to open %s for reading: %m\n", q);
- r = -errno;
- goto finish;
- }
-
- r = get_file_version(f, &v);
- fclose(f);
-
- if (r < 0)
- goto finish;
-
- if (r > 0)
- printf(" File: └─/%s/%s (%s)\n", path, de->d_name, v);
- else
- printf(" File: └─/%s/%s\n", path, de->d_name);
-
- c++;
- free(v);
- }
-
- r = c;
-
-finish:
- if (d)
- closedir(d);
-
- free(p);
- free(q);
- return r;
-}
-
-static int status_binaries(const char *esp_path, sd_id128_t partition) {
- int r;
-
- printf("Boot Loader Binaries:\n");
-
- printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition));
-
- r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
- if (r == 0)
- fprintf(stderr, "systemd-boot not installed in ESP.\n");
- else if (r < 0)
- return r;
-
- r = enumerate_binaries(esp_path, "EFI/Boot", "boot");
- if (r == 0)
- fprintf(stderr, "No default/fallback boot loader installed in ESP.\n");
- else if (r < 0)
- return r;
-
- printf("\n");
- return 0;
-}
-
-static int print_efi_option(uint16_t id, bool in_order) {
- _cleanup_free_ char *title = NULL;
- _cleanup_free_ char *path = NULL;
- sd_id128_t partition;
- bool active;
- int r = 0;
-
- r = efi_get_boot_option(id, &title, &partition, &path, &active);
- if (r < 0)
- return r;
-
- /* print only configured entries with partition information */
- if (!path || sd_id128_equal(partition, SD_ID128_NULL))
- return 0;
-
- efi_tilt_backslashes(path);
-
- printf(" Title: %s\n", strna(title));
- printf(" ID: 0x%04X\n", id);
- printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
- printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition));
- printf(" File: └─%s\n", path);
- printf("\n");
-
- return 0;
-}
-
-static int status_variables(void) {
- int n_options, n_order;
- uint16_t *options = NULL, *order = NULL;
- int r, i;
-
- if (!is_efi_boot()) {
- fprintf(stderr, "Not booted with EFI, not showing EFI variables.\n");
- return 0;
- }
-
- n_options = efi_get_boot_options(&options);
- if (n_options < 0) {
- if (n_options == -ENOENT)
- fprintf(stderr, "Failed to access EFI variables, "
- "efivarfs needs to be available at /sys/firmware/efi/efivars/.\n");
- else
- fprintf(stderr, "Failed to read EFI boot entries: %s\n", strerror(-n_options));
- r = n_options;
- goto finish;
- }
-
- printf("Boot Loader Entries in EFI Variables:\n");
- n_order = efi_get_boot_order(&order);
- if (n_order == -ENOENT) {
- n_order = 0;
- } else if (n_order < 0) {
- fprintf(stderr, "Failed to read EFI boot order.\n");
- r = n_order;
- goto finish;
- }
-
- /* print entries in BootOrder first */
- for (i = 0; i < n_order; i++)
- print_efi_option(order[i], true);
-
- /* print remaining entries */
- for (i = 0; i < n_options; i++) {
- int j;
- bool found = false;
-
- for (j = 0; j < n_order; j++)
- if (options[i] == order[j]) {
- found = true;
- break;
- }
-
- if (found)
- continue;
-
- print_efi_option(options[i], false);
- }
-
- r = 0;
-finish:
- free(options);
- free(order);
-
- return r;
-}
-
-static int compare_product(const char *a, const char *b) {
- size_t x, y;
-
- assert(a);
- assert(b);
-
- x = strcspn(a, " ");
- y = strcspn(b, " ");
- if (x != y)
- return x < y ? -1 : x > y ? 1 : 0;
-
- return strncmp(a, b, x);
-}
-
-static int compare_version(const char *a, const char *b) {
- assert(a);
- assert(b);
-
- a += strcspn(a, " ");
- a += strspn(a, " ");
- b += strcspn(b, " ");
- b += strspn(b, " ");
-
- return strverscmp(a, b);
-}
-
-static int version_check(FILE *f, const char *from, const char *to) {
- FILE *g = NULL;
- char *a = NULL, *b = NULL;
- int r;
-
- assert(f);
- assert(from);
- assert(to);
-
- r = get_file_version(f, &a);
- if (r < 0)
- goto finish;
- if (r == 0) {
- r = -EINVAL;
- fprintf(stderr, "Source file %s does not carry version information!\n", from);
- goto finish;
- }
-
- g = fopen(to, "re");
- if (!g) {
- if (errno == ENOENT) {
- r = 0;
- goto finish;
- }
-
- r = -errno;
- fprintf(stderr, "Failed to open %s for reading: %m\n", to);
- goto finish;
- }
-
- r = get_file_version(g, &b);
- if (r < 0)
- goto finish;
- if (r == 0 || compare_product(a, b) != 0) {
- r = -EEXIST;
- fprintf(stderr, "Skipping %s, since it's owned by another boot loader.\n", to);
- goto finish;
- }
-
- if (compare_version(a, b) < 0) {
- r = -EEXIST;
- fprintf(stderr, "Skipping %s, since it's a newer boot loader version already.\n", to);
- goto finish;
- }
-
- r = 0;
-
-finish:
- free(a);
- free(b);
- if (g)
- fclose(g);
- return r;
-}
-
-static int copy_file(const char *from, const char *to, bool force) {
- FILE *f = NULL, *g = NULL;
- char *p = NULL;
- int r;
- struct timespec t[2];
- struct stat st;
-
- assert(from);
- assert(to);
-
- f = fopen(from, "re");
- if (!f) {
- fprintf(stderr, "Failed to open %s for reading: %m\n", from);
- return -errno;
- }
-
- if (!force) {
- /* If this is an update, then let's compare versions first */
- r = version_check(f, from, to);
- if (r < 0)
- goto finish;
- }
-
- if (asprintf(&p, "%s~", to) < 0) {
- fprintf(stderr, "Out of memory.\n");
- r = -ENOMEM;
- goto finish;
- }
-
- g = fopen(p, "wxe");
- if (!g) {
- /* Directory doesn't exist yet? Then let's skip this... */
- if (!force && errno == ENOENT) {
- r = 0;
- goto finish;
- }
-
- fprintf(stderr, "Failed to open %s for writing: %m\n", to);
- r = -errno;
- goto finish;
- }
-
- rewind(f);
- do {
- size_t k;
- uint8_t buf[32*1024];
-
- k = fread(buf, 1, sizeof(buf), f);
- if (ferror(f)) {
- fprintf(stderr, "Failed to read %s: %m\n", from);
- r = -errno;
- goto finish;
- }
- if (k == 0)
- break;
-
- fwrite(buf, 1, k, g);
- if (ferror(g)) {
- fprintf(stderr, "Failed to write %s: %m\n", to);
- r = -errno;
- goto finish;
- }
- } while (!feof(f));
-
- fflush(g);
- if (ferror(g)) {
- fprintf(stderr, "Failed to write %s: %m\n", to);
- r = -errno;
- goto finish;
- }
-
- r = fstat(fileno(f), &st);
- if (r < 0) {
- fprintf(stderr, "Failed to get file timestamps of %s: %m", from);
- r = -errno;
- goto finish;
- }
-
- t[0] = st.st_atim;
- t[1] = st.st_mtim;
-
- r = futimens(fileno(g), t);
- if (r < 0) {
- fprintf(stderr, "Failed to change file timestamps for %s: %m", p);
- r = -errno;
- goto finish;
- }
-
- if (rename(p, to) < 0) {
- fprintf(stderr, "Failed to rename %s to %s: %m\n", p, to);
- r = -errno;
- goto finish;
- }
-
- fprintf(stderr, "Copied %s to %s.\n", from, to);
-
- free(p);
- p = NULL;
- r = 0;
-
-finish:
- if (f)
- fclose(f);
- if (g)
- fclose(g);
- if (p) {
- unlink(p);
- free(p);
- }
- return r;
-}
-
-static char* strupper(char *s) {
- char *p;
-
- for (p = s; *p; p++)
- *p = toupper(*p);
-
- return s;
-}
-
-static int mkdir_one(const char *prefix, const char *suffix) {
- char *p;
-
- if (asprintf(&p, "%s/%s", prefix, suffix) < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- if (mkdir(p, 0700) < 0) {
- if (errno != EEXIST) {
- fprintf(stderr, "Failed to create %s: %m\n", p);
- free(p);
- return -errno;
- }
- } else
- fprintf(stderr, "Created %s.\n", p);
-
- free(p);
- return 0;
-}
-
-static int create_dirs(const char *esp_path) {
- int r;
-
- r = mkdir_one(esp_path, "EFI");
- if (r < 0)
- return r;
-
- r = mkdir_one(esp_path, "EFI/systemd");
- if (r < 0)
- return r;
-
- r = mkdir_one(esp_path, "EFI/Boot");
- if (r < 0)
- return r;
-
- r = mkdir_one(esp_path, "loader");
- if (r < 0)
- return r;
-
- r = mkdir_one(esp_path, "loader/entries");
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int copy_one_file(const char *esp_path, const char *name, bool force) {
- _cleanup_free_ char *p = NULL;
- _cleanup_free_ char *q = NULL;
- _cleanup_free_ char *v = NULL;
- int r;
-
- if (asprintf(&p, BOOTLIBDIR "/%s", name) < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- if (asprintf(&q, "%s/EFI/systemd/%s", esp_path, name) < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- r = copy_file(p, q, force);
-
- 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("systemd-boot")) < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
- strupper(strrchr(v, '/') + 1);
-
- k = copy_file(p, v, force);
- if (k < 0 && r == 0)
- return k;
- }
-
- return r;
-}
-
-static int install_binaries(const char *esp_path, bool force) {
- struct dirent *de;
- DIR *d;
- int r = 0;
-
- if (force) {
- /* Don't create any of these directories when we are
- * just updating. When we update we'll drop-in our
- * files (unless there are newer ones already), but we
- * won't create the directories for them in the first
- * place. */
- r = create_dirs(esp_path);
- if (r < 0)
- return r;
- }
-
- d = opendir(BOOTLIBDIR);
- if (!d) {
- fprintf(stderr, "Failed to open "BOOTLIBDIR": %m\n");
- return -errno;
- }
-
- while ((de = readdir(d))) {
- size_t n;
- int k;
-
- if (de->d_name[0] == '.')
- continue;
-
- n = strlen(de->d_name);
- if (n < 4 || strcmp(de->d_name + n - 4, ".efi") != 0)
- continue;
-
- k = copy_one_file(esp_path, de->d_name, force);
- if (k < 0 && r == 0)
- r = k;
- }
-
- closedir(d);
- return r;
-}
-
-static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
- char *opath = NULL;
- sd_id128_t ouuid;
- int err;
- bool same = false;
-
- err = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL);
- if (err < 0)
- return false;
- if (!sd_id128_equal(uuid, ouuid))
- goto finish;
-
- if (!streq_ptr(path, opath))
- goto finish;
-
- same = true;
-
-finish:
- return same;
-}
-
-static int find_slot(sd_id128_t uuid, const char *path, uint16_t *id) {
- uint16_t *options = NULL;
- int n_options;
- int i;
- uint16_t new_id = 0;
- bool existing = false;
-
- n_options = efi_get_boot_options(&options);
- if (n_options < 0)
- return n_options;
-
- /* find already existing systemd-boot entry */
- for (i = 0; i < n_options; i++)
- if (same_entry(options[i], uuid, path)) {
- new_id = options[i];
- existing = true;
- goto finish;
- }
-
- /* find free slot in the sorted BootXXXX variable list */
- for (i = 0; i < n_options; i++)
- if (i != options[i]) {
- new_id = i;
- goto finish;
- }
-
- /* use the next one */
- if (i == 0xffff)
- return -ENOSPC;
- new_id = i;
-
-finish:
- *id = new_id;
- free(options);
- return existing;
-}
-
-static int insert_into_order(uint16_t slot, bool first) {
- uint16_t *order = NULL;
- uint16_t *new_order;
- int n_order;
- int i;
- int err = 0;
-
- n_order = efi_get_boot_order(&order);
- if (n_order <= 0) {
- /* no entry, add us */
- err = efi_set_boot_order(&slot, 1);
- goto finish;
- }
-
- /* are we the first and only one? */
- if (n_order == 1 && order[0] == slot)
- goto finish;
-
- /* are we already in the boot order? */
- for (i = 0; i < n_order; i++) {
- if (order[i] != slot)
- continue;
-
- /* we do not require to be the first one, all is fine */
- if (!first)
- goto finish;
-
- /* move us to the first slot */
- memmove(&order[1], order, i * sizeof(uint16_t));
- order[0] = slot;
- efi_set_boot_order(order, n_order);
- goto finish;
- }
-
- /* extend array */
- new_order = realloc(order, (n_order+1) * sizeof(uint16_t));
- if (!new_order) {
- err = -ENOMEM;
- goto finish;
- }
- order = new_order;
-
- /* add us to the top or end of the list */
- if (first) {
- memmove(&order[1], order, n_order * sizeof(uint16_t));
- order[0] = slot;
- } else
- order[n_order] = slot;
-
- efi_set_boot_order(order, n_order+1);
-
-finish:
- free(order);
- return err;
-}
-
-static int remove_from_order(uint16_t slot) {
- _cleanup_free_ uint16_t *order = NULL;
- int n_order;
- int i;
- int err = 0;
-
- n_order = efi_get_boot_order(&order);
- if (n_order < 0)
- return n_order;
- if (n_order == 0)
- return 0;
-
- for (i = 0; i < n_order; i++) {
- if (order[i] != slot)
- continue;
-
- if (i+1 < n_order)
- memmove(&order[i], &order[i+1], (n_order - i) * sizeof(uint16_t));
- efi_set_boot_order(order, n_order-1);
- break;
- }
-
- return err;
-}
-
-static int install_variables(const char *esp_path,
- uint32_t part, uint64_t pstart, uint64_t psize,
- sd_id128_t uuid, const char *path,
- bool first) {
- char *p = NULL;
- uint16_t *options = NULL;
- uint16_t slot;
- int r;
-
- if (!is_efi_boot()) {
- fprintf(stderr, "Not booted with EFI, skipping EFI variable setup.\n");
- return 0;
- }
-
- if (asprintf(&p, "%s%s", esp_path, path) < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- if (access(p, F_OK) < 0) {
- if (errno == ENOENT)
- r = 0;
- else
- r = -errno;
- goto finish;
- }
-
- r = find_slot(uuid, path, &slot);
- if (r < 0) {
- if (r == -ENOENT)
- fprintf(stderr, "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?\n");
- else
- fprintf(stderr, "Failed to determine current boot order: %s\n", strerror(-r));
- goto finish;
- }
-
- if (first || r == false) {
- r = efi_add_boot_option(slot, "Linux Boot Manager",
- part, pstart, psize,
- uuid, path);
- if (r < 0) {
- fprintf(stderr, "Failed to create EFI Boot variable entry: %s\n", strerror(-r));
- goto finish;
- }
- fprintf(stderr, "Created EFI boot entry \"Linux Boot Manager\".\n");
- }
-
- insert_into_order(slot, first);
-
-finish:
- free(p);
- free(options);
- return r;
-}
-
-static int remove_boot_efi(const char *esp_path) {
- struct dirent *de;
- char *p = NULL, *q = NULL;
- DIR *d = NULL;
- int r = 0, c = 0;
-
- if (asprintf(&p, "%s/EFI/Boot", esp_path) < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- d = opendir(p);
- if (!d) {
- if (errno == ENOENT) {
- r = 0;
- goto finish;
- }
-
- fprintf(stderr, "Failed to read %s: %m\n", p);
- r = -errno;
- goto finish;
- }
-
- while ((de = readdir(d))) {
- char *v;
- size_t n;
- FILE *f;
-
- if (de->d_name[0] == '.')
- continue;
-
- n = strlen(de->d_name);
- if (n < 4 || strcasecmp(de->d_name + n - 4, ".EFI") != 0)
- continue;
-
- if (strncasecmp(de->d_name, "Boot", 4) != 0)
- continue;
-
- free(q);
- q = NULL;
- if (asprintf(&q, "%s/%s", p, de->d_name) < 0) {
- fprintf(stderr, "Out of memory.\n");
- r = -ENOMEM;
- goto finish;
- }
-
- f = fopen(q, "re");
- if (!f) {
- fprintf(stderr, "Failed to open %s for reading: %m\n", q);
- r = -errno;
- goto finish;
- }
-
- r = get_file_version(f, &v);
- fclose(f);
-
- if (r < 0)
- goto finish;
-
- if (r > 0 && strncmp(v, "systemd-boot ", 10) == 0) {
-
- r = unlink(q);
- if (r < 0) {
- fprintf(stderr, "Failed to remove %s: %m\n", q);
- r = -errno;
- free(v);
- goto finish;
- } else
- fprintf(stderr, "Removed %s.\n", q);
- }
-
- c++;
- free(v);
- }
-
- r = c;
-
-finish:
- if (d)
- closedir(d);
- free(p);
- free(q);
-
- return r;
-}
-
-static int rmdir_one(const char *prefix, const char *suffix) {
- char *p;
-
- if (asprintf(&p, "%s/%s", prefix, suffix) < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- if (rmdir(p) < 0) {
- if (errno != ENOENT && errno != ENOTEMPTY) {
- fprintf(stderr, "Failed to remove %s: %m\n", p);
- free(p);
- return -errno;
- }
- } else
- fprintf(stderr, "Removed %s.\n", p);
-
- free(p);
- return 0;
-}
-
-
-static int remove_binaries(const char *esp_path) {
- char *p;
- int r, q;
-
- if (asprintf(&p, "%s/EFI/systemd-boot", esp_path) < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- r = rm_rf(p, false, false, false);
- free(p);
-
- q = remove_boot_efi(esp_path);
- if (q < 0 && r == 0)
- r = q;
-
- q = rmdir_one(esp_path, "loader/entries");
- if (q < 0 && r == 0)
- r = q;
-
- q = rmdir_one(esp_path, "loader");
- if (q < 0 && r == 0)
- r = q;
-
- q = rmdir_one(esp_path, "EFI/Boot");
- if (q < 0 && r == 0)
- r = q;
-
- q = rmdir_one(esp_path, "EFI/systemd-boot");
- if (q < 0 && r == 0)
- r = q;
-
- q = rmdir_one(esp_path, "EFI");
- if (q < 0 && r == 0)
- r = q;
-
- return r;
-}
-
-static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
- uint16_t slot;
- int r;
-
- if (!is_efi_boot())
- return 0;
-
- r = find_slot(uuid, path, &slot);
- if (r != 1)
- return 0;
-
- r = efi_remove_boot_option(slot);
- if (r < 0)
- return r;
-
- if (in_order)
- remove_from_order(slot);
-
- return 0;
-}
-
-static int install_loader_config(const char *esp_path) {
- char *p = NULL;
- char line[64];
- char *machine = NULL;
- FILE *f;
-
- f = fopen("/etc/machine-id", "re");
- if (!f)
- return -errno;
-
- if (fgets(line, sizeof(line), f) != NULL) {
- char *s;
-
- s = strchr(line, '\n');
- if (s)
- s[0] = '\0';
- if (strlen(line) == 32)
- machine = line;
- }
-
- fclose(f);
-
- if (!machine)
- return -ESRCH;
-
- if (asprintf(&p, "%s/%s", esp_path, "loader/loader.conf") < 0) {
- fprintf(stderr, "Out of memory.\n");
- return -ENOMEM;
- }
-
- f = fopen(p, "wxe");
- if (f) {
- fprintf(f, "#timeout 3\n");
- fprintf(f, "default %s-*\n", machine);
- fclose(f);
- }
-
- free(p);
- return 0;
-}
-
-static int help(void) {
- printf("%s [COMMAND] [OPTIONS...]\n"
- "\n"
- "Install, update or remove the sdboot EFI boot manager.\n\n"
- " -h --help Show this help\n"
- " --version Print version\n"
- " --path=PATH Path to the EFI System Partition (ESP)\n"
- " --no-variables Don't touch EFI variables\n"
- "\n"
- "Comands:\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;
-}
-
-static const char *arg_path = NULL;
-static bool arg_touch_variables = true;
-
-static int parse_argv(int argc, char *argv[]) {
- enum {
- ARG_PATH = 0x100,
- ARG_VERSION,
- ARG_NO_VARIABLES,
- };
-
- static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "path", required_argument, NULL, ARG_PATH },
- { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
- { NULL, 0, NULL, 0 }
- };
-
- int c;
-
- assert(argc >= 0);
- assert(argv);
-
- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
- switch (c) {
-
- case 'h':
- help();
- return 0;
-
- case ARG_VERSION:
- printf(VERSION "\n");
- return 0;
-
- case ARG_PATH:
- arg_path = optarg;
- break;
-
- case ARG_NO_VARIABLES:
- arg_touch_variables = false;
- break;
-
- case '?':
- return -EINVAL;
-
- default:
- fprintf(stderr, "Unknown option code '%c'.\n", c);
- return -EINVAL;
- }
- }
-
- return 1;
-}
-
-static int bootctl_main(int argc, char*argv[]) {
- enum action {
- ACTION_STATUS,
- ACTION_INSTALL,
- ACTION_UPDATE,
- ACTION_REMOVE
- } arg_action = ACTION_STATUS;
- static const struct {
- const char* verb;
- enum action action;
- } verbs[] = {
- { "status", ACTION_STATUS },
- { "install", ACTION_INSTALL },
- { "update", ACTION_UPDATE },
- { "remove", ACTION_REMOVE },
- };
-
- sd_id128_t uuid = {};
- uint32_t part = 0;
- uint64_t pstart = 0;
- uint64_t psize = 0;
- unsigned int i;
- int q;
- int r;
-
- if (argv[optind]) {
- for (i = 0; i < ELEMENTSOF(verbs); i++) {
- if (!streq(argv[optind], verbs[i].verb))
- continue;
- arg_action = verbs[i].action;
- break;
- }
- if (i >= ELEMENTSOF(verbs)) {
- fprintf(stderr, "Unknown operation %s\n", argv[optind]);
- r = -EINVAL;
- goto finish;
- }
- }
-
- if (!arg_path)
- arg_path = "/boot";
-
- if (geteuid() != 0) {
- fprintf(stderr, "Need to be root.\n");
- r = -EPERM;
- goto finish;
- }
-
- r = verify_esp(arg_path, &part, &pstart, &psize, &uuid);
- if (r == -ENODEV && !arg_path)
- fprintf(stderr, "You might want to use --path= to indicate the path to your ESP, in case it is not mounted to /boot.\n");
- if (r < 0)
- goto finish;
-
- switch (arg_action) {
- case ACTION_STATUS: {
- _cleanup_free_ char *fw_type = NULL;
- _cleanup_free_ char *fw_info = NULL;
- _cleanup_free_ char *loader = NULL;
- _cleanup_free_ char *loader_path = NULL;
- sd_id128_t loader_part_uuid = {};
-
- efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareType", &fw_type);
- efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareInfo", &fw_info);
- efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &loader);
- if (efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderImageIdentifier", &loader_path) > 0)
- efi_tilt_backslashes(loader_path);
- efi_loader_get_device_part_uuid(&loader_part_uuid);
-
- printf("System:\n");
- printf(" Firmware: %s (%s)\n", fw_type, strna(fw_info));
- printf(" Secure Boot: %s\n", is_efi_secure_boot() ? "enabled" : "disabled");
- printf(" Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "setup" : "user");
- printf("\n");
-
- printf("Loader:\n");
- printf(" Product: %s\n", strna(loader));
- if (!sd_id128_equal(loader_part_uuid, SD_ID128_NULL))
- printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
- SD_ID128_FORMAT_VAL(loader_part_uuid));
- else
- printf(" Partition: n/a\n");
- printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(loader_path));
- printf("\n");
-
- r = status_binaries(arg_path, uuid);
- if (r < 0)
- goto finish;
-
- if (arg_touch_variables)
- r = status_variables();
- break;
- }
-
- case ACTION_INSTALL:
- case ACTION_UPDATE:
- umask(0002);
-
- r = install_binaries(arg_path, arg_action == ACTION_INSTALL);
- if (r < 0)
- goto finish;
-
- if (arg_action == ACTION_INSTALL)
- install_loader_config(arg_path);
-
- if (arg_touch_variables)
- r = install_variables(arg_path,
- part, pstart, psize, uuid,
- "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
- arg_action == ACTION_INSTALL);
- break;
-
- case ACTION_REMOVE:
- r = remove_binaries(arg_path);
-
- if (arg_touch_variables) {
- q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
- if (q < 0 && r == 0)
- r = q;
- }
- break;
- }
-
-finish:
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
-
-int main(int argc, char *argv[]) {
- int r;
-
- log_parse_environment();
- log_open();
-
- r = parse_argv(argc, argv);
- if (r <= 0)
- goto finish;
-
- r = bootctl_main(argc, argv);
-
- finish:
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/src/boot/efi/.gitignore b/src/boot/efi/.gitignore
deleted file mode 100644
index e193acbe12..0000000000
--- a/src/boot/efi/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/systemd_boot.so
-/stub.so
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
deleted file mode 100644
index eb1a4e3b66..0000000000
--- a/src/boot/efi/boot.c
+++ /dev/null
@@ -1,1834 +0,0 @@
-/*-*- 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-2015 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2012-2015 Harald Hoyer <harald@redhat.com>
- */
-
-#include <efi.h>
-#include <efilib.h>
-
-#include "util.h"
-#include "console.h"
-#include "graphics.h"
-#include "pefile.h"
-#include "linux.h"
-
-#ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI
-#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL
-#endif
-
-/* magic string to find in the binary image */
-static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-boot " VERSION " ####";
-
-static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE;
-
-enum loader_type {
- LOADER_UNDEFINED,
- LOADER_EFI,
- LOADER_LINUX
-};
-
-typedef struct {
- CHAR16 *file;
- CHAR16 *title_show;
- CHAR16 *title;
- CHAR16 *version;
- CHAR16 *machine_id;
- EFI_HANDLE *device;
- enum loader_type type;
- CHAR16 *loader;
- CHAR16 *options;
- CHAR16 key;
- EFI_STATUS (*call)(VOID);
- BOOLEAN no_autoselect;
- BOOLEAN non_unique;
-} ConfigEntry;
-
-typedef struct {
- ConfigEntry **entries;
- UINTN entry_count;
- INTN idx_default;
- INTN idx_default_efivar;
- UINTN timeout_sec;
- UINTN timeout_sec_config;
- INTN timeout_sec_efivar;
- CHAR16 *entry_default_pattern;
- CHAR16 *entry_oneshot;
- CHAR16 *options_edit;
- BOOLEAN no_editor;
-} Config;
-
-static VOID cursor_left(UINTN *cursor, UINTN *first)
-{
- if ((*cursor) > 0)
- (*cursor)--;
- else if ((*first) > 0)
- (*first)--;
-}
-
-static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len)
-{
- if ((*cursor)+1 < x_max)
- (*cursor)++;
- else if ((*first) + (*cursor) < len)
- (*first)++;
-}
-
-static BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max, UINTN y_pos) {
- CHAR16 *line;
- UINTN size;
- UINTN len;
- UINTN first;
- CHAR16 *print;
- UINTN cursor;
- UINTN clear;
- BOOLEAN exit;
- BOOLEAN enter;
-
- if (!line_in)
- line_in = L"";
- size = StrLen(line_in) + 1024;
- line = AllocatePool(size * sizeof(CHAR16));
- StrCpy(line, line_in);
- len = StrLen(line);
- print = AllocatePool((x_max+1) * sizeof(CHAR16));
-
- uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE);
-
- first = 0;
- cursor = 0;
- clear = 0;
- enter = FALSE;
- exit = FALSE;
- while (!exit) {
- EFI_STATUS err;
- UINT64 key;
- UINTN i;
-
- i = len - first;
- if (i >= x_max-1)
- i = x_max-1;
- CopyMem(print, line + first, i * sizeof(CHAR16));
- while (clear > 0 && i < x_max-1) {
- clear--;
- print[i++] = ' ';
- }
- print[i] = '\0';
-
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_pos);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, print);
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
-
- err = console_key_read(&key, TRUE);
- if (EFI_ERROR(err))
- continue;
-
- switch (key) {
- case KEYPRESS(0, SCAN_ESC, 0):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'c'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'g'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('c')):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('g')):
- exit = TRUE;
- break;
-
- case KEYPRESS(0, SCAN_HOME, 0):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'a'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('a')):
- /* beginning-of-line */
- cursor = 0;
- first = 0;
- continue;
-
- case KEYPRESS(0, SCAN_END, 0):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'e'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('e')):
- /* end-of-line */
- cursor = len - first;
- if (cursor+1 >= x_max) {
- cursor = x_max-1;
- first = len - (x_max-1);
- }
- continue;
-
- case KEYPRESS(0, SCAN_DOWN, 0):
- case KEYPRESS(EFI_ALT_PRESSED, 0, 'f'):
- case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_RIGHT, 0):
- /* forward-word */
- while (line[first + cursor] && line[first + cursor] == ' ')
- cursor_right(&cursor, &first, x_max, len);
- while (line[first + cursor] && line[first + cursor] != ' ')
- cursor_right(&cursor, &first, x_max, len);
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
- continue;
-
- case KEYPRESS(0, SCAN_UP, 0):
- case KEYPRESS(EFI_ALT_PRESSED, 0, 'b'):
- case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_LEFT, 0):
- /* backward-word */
- if ((first + cursor) > 0 && line[first + cursor-1] == ' ') {
- cursor_left(&cursor, &first);
- while ((first + cursor) > 0 && line[first + cursor] == ' ')
- cursor_left(&cursor, &first);
- }
- while ((first + cursor) > 0 && line[first + cursor-1] != ' ')
- cursor_left(&cursor, &first);
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
- continue;
-
- case KEYPRESS(0, SCAN_RIGHT, 0):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'f'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('f')):
- /* forward-char */
- if (first + cursor == len)
- continue;
- cursor_right(&cursor, &first, x_max, len);
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
- continue;
-
- case KEYPRESS(0, SCAN_LEFT, 0):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'b'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('b')):
- /* backward-char */
- cursor_left(&cursor, &first);
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
- continue;
-
- case KEYPRESS(EFI_ALT_PRESSED, 0, 'd'):
- /* kill-word */
- clear = 0;
- for (i = first + cursor; i < len && line[i] == ' '; i++)
- clear++;
- for (; i < len && line[i] != ' '; i++)
- clear++;
-
- for (i = first + cursor; i + clear < len; i++)
- line[i] = line[i + clear];
- len -= clear;
- line[len] = '\0';
- continue;
-
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'w'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('w')):
- case KEYPRESS(EFI_ALT_PRESSED, 0, CHAR_BACKSPACE):
- /* backward-kill-word */
- clear = 0;
- if ((first + cursor) > 0 && line[first + cursor-1] == ' ') {
- cursor_left(&cursor, &first);
- clear++;
- while ((first + cursor) > 0 && line[first + cursor] == ' ') {
- cursor_left(&cursor, &first);
- clear++;
- }
- }
- while ((first + cursor) > 0 && line[first + cursor-1] != ' ') {
- cursor_left(&cursor, &first);
- clear++;
- }
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
-
- for (i = first + cursor; i + clear < len; i++)
- line[i] = line[i + clear];
- len -= clear;
- line[len] = '\0';
- continue;
-
- case KEYPRESS(0, SCAN_DELETE, 0):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'd'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('d')):
- if (len == 0)
- continue;
- if (first + cursor == len)
- continue;
- for (i = first + cursor; i < len; i++)
- line[i] = line[i+1];
- clear = 1;
- len--;
- continue;
-
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'k'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('k')):
- /* kill-line */
- line[first + cursor] = '\0';
- clear = len - (first + cursor);
- len = first + cursor;
- continue;
-
- case KEYPRESS(0, 0, CHAR_LINEFEED):
- case KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN):
- if (StrCmp(line, line_in) != 0) {
- *line_out = line;
- line = NULL;
- }
- enter = TRUE;
- exit = TRUE;
- break;
-
- case KEYPRESS(0, 0, CHAR_BACKSPACE):
- if (len == 0)
- continue;
- if (first == 0 && cursor == 0)
- continue;
- for (i = first + cursor-1; i < len; i++)
- line[i] = line[i+1];
- clear = 1;
- len--;
- if (cursor > 0)
- cursor--;
- if (cursor > 0 || first == 0)
- continue;
- /* show full line if it fits */
- if (len < x_max) {
- cursor = first;
- first = 0;
- continue;
- }
- /* jump left to see what we delete */
- if (first > 10) {
- first -= 10;
- cursor = 10;
- } else {
- cursor = first;
- first = 0;
- }
- continue;
-
- case KEYPRESS(0, 0, ' ') ... KEYPRESS(0, 0, '~'):
- case KEYPRESS(0, 0, 0x80) ... KEYPRESS(0, 0, 0xffff):
- if (len+1 == size)
- continue;
- for (i = len; i > first + cursor; i--)
- line[i] = line[i-1];
- line[first + cursor] = KEYCHAR(key);
- len++;
- line[len] = '\0';
- if (cursor+1 < x_max)
- cursor++;
- else if (first + cursor < len)
- first++;
- continue;
- }
- }
-
- uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
- FreePool(print);
- FreePool(line);
- return enter;
-}
-
-static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) {
- UINTN i;
-
- if (key == 0)
- return -1;
-
- /* select entry by number key */
- if (key >= '1' && key <= '9') {
- i = key - '0';
- if (i > config->entry_count)
- i = config->entry_count;
- return i-1;
- }
-
- /* find matching key in config entries */
- for (i = start; i < config->entry_count; i++)
- if (config->entries[i]->key == key)
- return i;
-
- for (i = 0; i < start; i++)
- if (config->entries[i]->key == key)
- return i;
-
- return -1;
-}
-
-static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
- UINT64 key;
- UINTN i;
- CHAR16 *s;
- CHAR8 *b;
- UINTN x;
- UINTN y;
- UINTN size;
-
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
- uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
-
- Print(L"systemd-boot version: " VERSION "\n");
- Print(L"architecture: " EFI_MACHINE_TYPE_NAME "\n");
- Print(L"loaded image: %s\n", loaded_image_path);
- Print(L"UEFI specification: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
- Print(L"firmware vendor: %s\n", ST->FirmwareVendor);
- Print(L"firmware version: %d.%02d\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
-
- if (uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x, &y) == EFI_SUCCESS)
- Print(L"console size: %d x %d\n", x, y);
-
- if (efivar_get_raw(&global_guid, L"SecureBoot", &b, &size) == EFI_SUCCESS) {
- Print(L"SecureBoot: %s\n", yes_no(*b > 0));
- FreePool(b);
- }
-
- if (efivar_get_raw(&global_guid, L"SetupMode", &b, &size) == EFI_SUCCESS) {
- Print(L"SetupMode: %s\n", *b > 0 ? L"setup" : L"user");
- FreePool(b);
- }
-
- if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) {
- Print(L"OsIndicationsSupported: %d\n", (UINT64)*b);
- FreePool(b);
- }
- Print(L"\n");
-
- Print(L"timeout: %d\n", config->timeout_sec);
- if (config->timeout_sec_efivar >= 0)
- Print(L"timeout (EFI var): %d\n", config->timeout_sec_efivar);
- Print(L"timeout (config): %d\n", config->timeout_sec_config);
- if (config->entry_default_pattern)
- Print(L"default pattern: '%s'\n", config->entry_default_pattern);
- Print(L"editor: %s\n", yes_no(!config->no_editor));
- Print(L"\n");
-
- Print(L"config entry count: %d\n", config->entry_count);
- Print(L"entry selected idx: %d\n", config->idx_default);
- if (config->idx_default_efivar >= 0)
- Print(L"entry EFI var idx: %d\n", config->idx_default_efivar);
- Print(L"\n");
-
- if (efivar_get_int(L"LoaderConfigTimeout", &i) == EFI_SUCCESS)
- Print(L"LoaderConfigTimeout: %d\n", i);
- if (config->entry_oneshot)
- Print(L"LoaderEntryOneShot: %s\n", config->entry_oneshot);
- if (efivar_get(L"LoaderDevicePartUUID", &s) == EFI_SUCCESS) {
- Print(L"LoaderDevicePartUUID: %s\n", s);
- FreePool(s);
- }
- if (efivar_get(L"LoaderEntryDefault", &s) == EFI_SUCCESS) {
- Print(L"LoaderEntryDefault: %s\n", s);
- FreePool(s);
- }
-
- Print(L"\n--- press key ---\n\n");
- console_key_read(&key, TRUE);
-
- for (i = 0; i < config->entry_count; i++) {
- ConfigEntry *entry;
-
- if (key == KEYPRESS(0, SCAN_ESC, 0) || key == KEYPRESS(0, 0, 'q'))
- break;
-
- entry = config->entries[i];
- Print(L"config entry: %d/%d\n", i+1, config->entry_count);
- if (entry->file)
- Print(L"file '%s'\n", entry->file);
- Print(L"title show '%s'\n", entry->title_show);
- if (entry->title)
- Print(L"title '%s'\n", entry->title);
- if (entry->version)
- Print(L"version '%s'\n", entry->version);
- if (entry->machine_id)
- Print(L"machine-id '%s'\n", entry->machine_id);
- if (entry->device) {
- EFI_DEVICE_PATH *device_path;
- CHAR16 *str;
-
- device_path = DevicePathFromHandle(entry->device);
- if (device_path) {
- str = DevicePathToStr(device_path);
- Print(L"device handle '%s'\n", str);
- FreePool(str);
- }
- }
- if (entry->loader)
- Print(L"loader '%s'\n", entry->loader);
- if (entry->options)
- Print(L"options '%s'\n", entry->options);
- Print(L"auto-select %s\n", yes_no(!entry->no_autoselect));
- if (entry->call)
- Print(L"internal call yes\n");
-
- Print(L"\n--- press key ---\n\n");
- console_key_read(&key, TRUE);
- }
-
- uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
-}
-
-static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, CHAR16 *loaded_image_path) {
- EFI_STATUS err;
- UINTN visible_max;
- UINTN idx_highlight;
- UINTN idx_highlight_prev;
- UINTN idx_first;
- UINTN idx_last;
- BOOLEAN refresh;
- BOOLEAN highlight;
- UINTN i;
- UINTN line_width;
- CHAR16 **lines;
- UINTN x_start;
- UINTN y_start;
- UINTN x_max;
- UINTN y_max;
- CHAR16 *status;
- CHAR16 *clearline;
- INTN timeout_remain;
- INT16 idx;
- BOOLEAN exit = FALSE;
- BOOLEAN run = TRUE;
- BOOLEAN wait = FALSE;
-
- graphics_mode(FALSE);
- uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE);
- uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
-
- /* draw a single character to make ClearScreen work on some firmware */
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L" ");
- uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
-
- err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max);
- if (EFI_ERROR(err)) {
- x_max = 80;
- y_max = 25;
- }
-
- /* we check 10 times per second for a keystroke */
- if (config->timeout_sec > 0)
- timeout_remain = config->timeout_sec * 10;
- else
- timeout_remain = -1;
-
- idx_highlight = config->idx_default;
- idx_highlight_prev = 0;
-
- visible_max = y_max - 2;
-
- if ((UINTN)config->idx_default >= visible_max)
- idx_first = config->idx_default-1;
- else
- idx_first = 0;
-
- idx_last = idx_first + visible_max-1;
-
- refresh = TRUE;
- highlight = FALSE;
-
- /* length of the longest entry */
- line_width = 5;
- for (i = 0; i < config->entry_count; i++) {
- UINTN entry_len;
-
- entry_len = StrLen(config->entries[i]->title_show);
- if (line_width < entry_len)
- line_width = entry_len;
- }
- if (line_width > x_max-6)
- line_width = x_max-6;
-
- /* offsets to center the entries on the screen */
- x_start = (x_max - (line_width)) / 2;
- if (config->entry_count < visible_max)
- y_start = ((visible_max - config->entry_count) / 2) + 1;
- else
- y_start = 0;
-
- /* menu entries title lines */
- lines = AllocatePool(sizeof(CHAR16 *) * config->entry_count);
- for (i = 0; i < config->entry_count; i++) {
- UINTN j, k;
-
- lines[i] = AllocatePool(((x_max+1) * sizeof(CHAR16)));
- for (j = 0; j < x_start; j++)
- lines[i][j] = ' ';
-
- for (k = 0; config->entries[i]->title_show[k] != '\0' && j < x_max; j++, k++)
- lines[i][j] = config->entries[i]->title_show[k];
-
- for (; j < x_max; j++)
- lines[i][j] = ' ';
- lines[i][x_max] = '\0';
- }
-
- status = NULL;
- clearline = AllocatePool((x_max+1) * sizeof(CHAR16));
- for (i = 0; i < x_max; i++)
- clearline[i] = ' ';
- clearline[i] = 0;
-
- while (!exit) {
- UINT64 key;
-
- if (refresh) {
- for (i = 0; i < config->entry_count; i++) {
- if (i < idx_first || i > idx_last)
- continue;
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + i - idx_first);
- if (i == idx_highlight)
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
- EFI_BLACK|EFI_BACKGROUND_LIGHTGRAY);
- else
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
- EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, lines[i]);
- if ((INTN)i == config->idx_default_efivar) {
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x_start-3, y_start + i - idx_first);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L"=>");
- }
- }
- refresh = FALSE;
- } else if (highlight) {
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + idx_highlight_prev - idx_first);
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, lines[idx_highlight_prev]);
- if ((INTN)idx_highlight_prev == config->idx_default_efivar) {
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x_start-3, y_start + idx_highlight_prev - idx_first);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L"=>");
- }
-
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + idx_highlight - idx_first);
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_BLACK|EFI_BACKGROUND_LIGHTGRAY);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, lines[idx_highlight]);
- if ((INTN)idx_highlight == config->idx_default_efivar) {
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x_start-3, y_start + idx_highlight - idx_first);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L"=>");
- }
- highlight = FALSE;
- }
-
- if (timeout_remain > 0) {
- FreePool(status);
- status = PoolPrint(L"Boot in %d sec.", (timeout_remain + 5) / 10);
- }
-
- /* print status at last line of screen */
- if (status) {
- UINTN len;
- UINTN x;
-
- /* center line */
- len = StrLen(status);
- if (len < x_max)
- x = (x_max - len) / 2;
- else
- x = 0;
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline + (x_max - x));
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, status);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1 + x + len);
- }
-
- err = console_key_read(&key, wait);
- if (EFI_ERROR(err)) {
- /* timeout reached */
- if (timeout_remain == 0) {
- exit = TRUE;
- break;
- }
-
- /* sleep and update status */
- if (timeout_remain > 0) {
- uefi_call_wrapper(BS->Stall, 1, 100 * 1000);
- timeout_remain--;
- continue;
- }
-
- /* timeout disabled, wait for next key */
- wait = TRUE;
- continue;
- }
-
- timeout_remain = -1;
-
- /* clear status after keystroke */
- if (status) {
- FreePool(status);
- status = NULL;
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1);
- }
-
- idx_highlight_prev = idx_highlight;
-
- switch (key) {
- case KEYPRESS(0, SCAN_UP, 0):
- case KEYPRESS(0, 0, 'k'):
- if (idx_highlight > 0)
- idx_highlight--;
- break;
-
- case KEYPRESS(0, SCAN_DOWN, 0):
- case KEYPRESS(0, 0, 'j'):
- if (idx_highlight < config->entry_count-1)
- idx_highlight++;
- break;
-
- case KEYPRESS(0, SCAN_HOME, 0):
- case KEYPRESS(EFI_ALT_PRESSED, 0, '<'):
- if (idx_highlight > 0) {
- refresh = TRUE;
- idx_highlight = 0;
- }
- break;
-
- case KEYPRESS(0, SCAN_END, 0):
- case KEYPRESS(EFI_ALT_PRESSED, 0, '>'):
- if (idx_highlight < config->entry_count-1) {
- refresh = TRUE;
- idx_highlight = config->entry_count-1;
- }
- break;
-
- case KEYPRESS(0, SCAN_PAGE_UP, 0):
- if (idx_highlight > visible_max)
- idx_highlight -= visible_max;
- else
- idx_highlight = 0;
- break;
-
- case KEYPRESS(0, SCAN_PAGE_DOWN, 0):
- idx_highlight += visible_max;
- if (idx_highlight > config->entry_count-1)
- idx_highlight = config->entry_count-1;
- break;
-
- case KEYPRESS(0, 0, CHAR_LINEFEED):
- case KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN):
- exit = TRUE;
- break;
-
- case KEYPRESS(0, SCAN_F1, 0):
- case KEYPRESS(0, 0, 'h'):
- case KEYPRESS(0, 0, '?'):
- status = StrDuplicate(L"(d)efault, (t/T)timeout, (e)dit, (v)ersion (Q)uit (P)rint (h)elp");
- break;
-
- case KEYPRESS(0, 0, 'Q'):
- exit = TRUE;
- run = FALSE;
- break;
-
- case KEYPRESS(0, 0, 'd'):
- if (config->idx_default_efivar != (INTN)idx_highlight) {
- /* store the selected entry in a persistent EFI variable */
- efivar_set(L"LoaderEntryDefault", config->entries[idx_highlight]->file, TRUE);
- config->idx_default_efivar = idx_highlight;
- status = StrDuplicate(L"Default boot entry selected.");
- } else {
- /* clear the default entry EFI variable */
- efivar_set(L"LoaderEntryDefault", NULL, TRUE);
- config->idx_default_efivar = -1;
- status = StrDuplicate(L"Default boot entry cleared.");
- }
- refresh = TRUE;
- break;
-
- case KEYPRESS(0, 0, '-'):
- case KEYPRESS(0, 0, 'T'):
- if (config->timeout_sec_efivar > 0) {
- config->timeout_sec_efivar--;
- efivar_set_int(L"LoaderConfigTimeout", config->timeout_sec_efivar, TRUE);
- if (config->timeout_sec_efivar > 0)
- status = PoolPrint(L"Menu timeout set to %d sec.", config->timeout_sec_efivar);
- else
- status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
- } else if (config->timeout_sec_efivar <= 0){
- config->timeout_sec_efivar = -1;
- efivar_set(L"LoaderConfigTimeout", NULL, TRUE);
- if (config->timeout_sec_config > 0)
- status = PoolPrint(L"Menu timeout of %d sec is defined by configuration file.",
- config->timeout_sec_config);
- else
- status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
- }
- break;
-
- case KEYPRESS(0, 0, '+'):
- case KEYPRESS(0, 0, 't'):
- if (config->timeout_sec_efivar == -1 && config->timeout_sec_config == 0)
- config->timeout_sec_efivar++;
- config->timeout_sec_efivar++;
- efivar_set_int(L"LoaderConfigTimeout", config->timeout_sec_efivar, TRUE);
- if (config->timeout_sec_efivar > 0)
- status = PoolPrint(L"Menu timeout set to %d sec.",
- config->timeout_sec_efivar);
- else
- status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
- break;
-
- case KEYPRESS(0, 0, 'e'):
- /* only the options of configured entries can be edited */
- if (config->no_editor || config->entries[idx_highlight]->type == LOADER_UNDEFINED)
- break;
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1);
- if (line_edit(config->entries[idx_highlight]->options, &config->options_edit, x_max-1, y_max-1))
- exit = TRUE;
- uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1);
- uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1);
- break;
-
- case KEYPRESS(0, 0, 'v'):
- status = PoolPrint(L"systemd-boot " VERSION " (" EFI_MACHINE_TYPE_NAME "), UEFI Specification %d.%02d, Vendor %s %d.%02d",
- ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff,
- ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
- break;
-
- case KEYPRESS(0, 0, 'P'):
- print_status(config, loaded_image_path);
- refresh = TRUE;
- break;
-
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'l'):
- case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('l')):
- refresh = TRUE;
- break;
-
- default:
- /* jump with a hotkey directly to a matching entry */
- idx = entry_lookup_key(config, idx_highlight+1, KEYCHAR(key));
- if (idx < 0)
- break;
- idx_highlight = idx;
- refresh = TRUE;
- }
-
- if (idx_highlight > idx_last) {
- idx_last = idx_highlight;
- idx_first = 1 + idx_highlight - visible_max;
- refresh = TRUE;
- } else if (idx_highlight < idx_first) {
- idx_first = idx_highlight;
- idx_last = idx_highlight + visible_max-1;
- refresh = TRUE;
- }
-
- if (!refresh && idx_highlight != idx_highlight_prev)
- highlight = TRUE;
- }
-
- *chosen_entry = config->entries[idx_highlight];
-
- for (i = 0; i < config->entry_count; i++)
- FreePool(lines[i]);
- FreePool(lines);
- FreePool(clearline);
-
- uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_WHITE|EFI_BACKGROUND_BLACK);
- uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
- return run;
-}
-
-static VOID config_add_entry(Config *config, ConfigEntry *entry) {
- if ((config->entry_count & 15) == 0) {
- UINTN i;
-
- i = config->entry_count + 16;
- if (config->entry_count == 0)
- config->entries = AllocatePool(sizeof(VOID *) * i);
- else
- config->entries = ReallocatePool(config->entries,
- sizeof(VOID *) * config->entry_count, sizeof(VOID *) * i);
- }
- config->entries[config->entry_count++] = entry;
-}
-
-static VOID config_entry_free(ConfigEntry *entry) {
- FreePool(entry->title_show);
- FreePool(entry->title);
- FreePool(entry->machine_id);
- FreePool(entry->loader);
- FreePool(entry->options);
-}
-
-static BOOLEAN is_digit(CHAR16 c)
-{
- return (c >= '0') && (c <= '9');
-}
-
-static UINTN c_order(CHAR16 c)
-{
- if (c == '\0')
- return 0;
- if (is_digit(c))
- return 0;
- else if ((c >= 'a') && (c <= 'z'))
- return c;
- else
- return c + 0x10000;
-}
-
-static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2)
-{
- CHAR16 *os1 = s1;
- CHAR16 *os2 = s2;
-
- while (*s1 || *s2) {
- INTN first;
-
- while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
- INTN order;
-
- order = c_order(*s1) - c_order(*s2);
- if (order)
- return order;
- s1++;
- s2++;
- }
-
- while (*s1 == '0')
- s1++;
- while (*s2 == '0')
- s2++;
-
- first = 0;
- while (is_digit(*s1) && is_digit(*s2)) {
- if (first == 0)
- first = *s1 - *s2;
- s1++;
- s2++;
- }
-
- if (is_digit(*s1))
- return 1;
- if (is_digit(*s2))
- return -1;
-
- if (first)
- return first;
- }
-
- return StrCmp(os1, os2);
-}
-
-static CHAR8 *line_get_key_value(CHAR8 *content, CHAR8 *sep, UINTN *pos, CHAR8 **key_ret, CHAR8 **value_ret) {
- CHAR8 *line;
- UINTN linelen;
- CHAR8 *value;
-
-skip:
- line = content + *pos;
- if (*line == '\0')
- return NULL;
-
- linelen = 0;
- while (line[linelen] && !strchra((CHAR8 *)"\n\r", line[linelen]))
- linelen++;
-
- /* move pos to next line */
- *pos += linelen;
- if (content[*pos])
- (*pos)++;
-
- /* empty line */
- if (linelen == 0)
- goto skip;
-
- /* terminate line */
- line[linelen] = '\0';
-
- /* remove leading whitespace */
- while (strchra((CHAR8 *)" \t", *line)) {
- line++;
- linelen--;
- }
-
- /* remove trailing whitespace */
- while (linelen > 0 && strchra(sep, line[linelen-1]))
- linelen--;
- line[linelen] = '\0';
-
- if (*line == '#')
- goto skip;
-
- /* split key/value */
- value = line;
- while (*value && !strchra(sep, *value))
- value++;
- if (*value == '\0')
- goto skip;
- *value = '\0';
- value++;
- while (*value && strchra(sep, *value))
- value++;
-
- /* unquote */
- if (value[0] == '\"' && line[linelen-1] == '\"') {
- value++;
- line[linelen-1] = '\0';
- }
-
- *key_ret = line;
- *value_ret = value;
- return line;
-}
-
-static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
- CHAR8 *line;
- UINTN pos = 0;
- CHAR8 *key, *value;
-
- line = content;
- while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) {
- if (strcmpa((CHAR8 *)"timeout", key) == 0) {
- CHAR16 *s;
-
- s = stra_to_str(value);
- config->timeout_sec_config = Atoi(s);
- config->timeout_sec = config->timeout_sec_config;
- FreePool(s);
- continue;
- }
-
- if (strcmpa((CHAR8 *)"default", key) == 0) {
- FreePool(config->entry_default_pattern);
- config->entry_default_pattern = stra_to_str(value);
- StrLwr(config->entry_default_pattern);
- continue;
- }
-
- if (strcmpa((CHAR8 *)"editor", key) == 0) {
- BOOLEAN on;
-
- if (EFI_ERROR(parse_boolean(value, &on)))
- continue;
- config->no_editor = !on;
- }
- }
-}
-
-static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR16 *file, CHAR8 *content, CHAR16 *loaded_image_path) {
- ConfigEntry *entry;
- CHAR8 *line;
- UINTN pos = 0;
- CHAR8 *key, *value;
- UINTN len;
- CHAR16 *initrd = NULL;
-
- entry = AllocateZeroPool(sizeof(ConfigEntry));
-
- line = content;
- while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) {
- if (strcmpa((CHAR8 *)"title", key) == 0) {
- FreePool(entry->title);
- entry->title = stra_to_str(value);
- continue;
- }
-
- if (strcmpa((CHAR8 *)"version", key) == 0) {
- FreePool(entry->version);
- entry->version = stra_to_str(value);
- continue;
- }
-
- if (strcmpa((CHAR8 *)"machine-id", key) == 0) {
- FreePool(entry->machine_id);
- entry->machine_id = stra_to_str(value);
- continue;
- }
-
- if (strcmpa((CHAR8 *)"linux", key) == 0) {
- FreePool(entry->loader);
- entry->type = LOADER_LINUX;
- entry->loader = stra_to_path(value);
- entry->key = 'l';
- continue;
- }
-
- if (strcmpa((CHAR8 *)"efi", key) == 0) {
- entry->type = LOADER_EFI;
- FreePool(entry->loader);
- entry->loader = stra_to_path(value);
-
- /* do not add an entry for ourselves */
- if (StriCmp(entry->loader, loaded_image_path) == 0) {
- entry->type = LOADER_UNDEFINED;
- break;
- }
- continue;
- }
-
- if (strcmpa((CHAR8 *)"architecture", key) == 0) {
- /* do not add an entry for an EFI image of architecture not matching with that of the image */
- if (strcmpa((CHAR8 *)EFI_MACHINE_TYPE_NAME, value) != 0) {
- entry->type = LOADER_UNDEFINED;
- break;
- }
- continue;
- }
-
- if (strcmpa((CHAR8 *)"initrd", key) == 0) {
- CHAR16 *new;
-
- new = stra_to_path(value);
- if (initrd) {
- CHAR16 *s;
-
- s = PoolPrint(L"%s initrd=%s", initrd, new);
- FreePool(initrd);
- initrd = s;
- } else
- initrd = PoolPrint(L"initrd=%s", new);
- FreePool(new);
- continue;
- }
-
- if (strcmpa((CHAR8 *)"options", key) == 0) {
- CHAR16 *new;
-
- new = stra_to_str(value);
- if (entry->options) {
- CHAR16 *s;
-
- s = PoolPrint(L"%s %s", entry->options, new);
- FreePool(entry->options);
- entry->options = s;
- } else {
- entry->options = new;
- new = NULL;
- }
- FreePool(new);
- continue;
- }
- }
-
- if (entry->type == LOADER_UNDEFINED) {
- config_entry_free(entry);
- FreePool(initrd);
- FreePool(entry);
- return;
- }
-
- /* add initrd= to options */
- if (entry->type == LOADER_LINUX && initrd) {
- if (entry->options) {
- CHAR16 *s;
-
- s = PoolPrint(L"%s %s", initrd, entry->options);
- FreePool(entry->options);
- entry->options = s;
- } else {
- entry->options = initrd;
- initrd = NULL;
- }
- }
- FreePool(initrd);
-
- entry->device = device;
- entry->file = StrDuplicate(file);
- len = StrLen(entry->file);
- /* remove ".conf" */
- if (len > 5)
- entry->file[len - 5] = '\0';
- StrLwr(entry->file);
-
- config_add_entry(config, entry);
-}
-
-static VOID config_load(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path) {
- EFI_FILE_HANDLE entries_dir;
- EFI_STATUS err;
- CHAR8 *content = NULL;
- UINTN sec;
- UINTN len;
- UINTN i;
-
- len = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content);
- if (len > 0)
- config_defaults_load_from_file(config, content);
- FreePool(content);
-
- err = efivar_get_int(L"LoaderConfigTimeout", &sec);
- if (!EFI_ERROR(err)) {
- config->timeout_sec_efivar = sec;
- config->timeout_sec = sec;
- } else
- config->timeout_sec_efivar = -1;
-
- err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &entries_dir, L"\\loader\\entries", EFI_FILE_MODE_READ, 0ULL);
- if (!EFI_ERROR(err)) {
- for (;;) {
- CHAR16 buf[256];
- UINTN bufsize;
- EFI_FILE_INFO *f;
- CHAR8 *content = NULL;
- UINTN len;
-
- bufsize = sizeof(buf);
- err = uefi_call_wrapper(entries_dir->Read, 3, entries_dir, &bufsize, buf);
- if (bufsize == 0 || EFI_ERROR(err))
- break;
-
- f = (EFI_FILE_INFO *) buf;
- if (f->FileName[0] == '.')
- continue;
- if (f->Attribute & EFI_FILE_DIRECTORY)
- continue;
-
- len = StrLen(f->FileName);
- if (len < 6)
- continue;
- if (StriCmp(f->FileName + len - 5, L".conf") != 0)
- continue;
- if (StrnCmp(f->FileName, L"auto-", 5) == 0)
- continue;
-
- len = file_read(entries_dir, f->FileName, 0, 0, &content);
- if (len > 0)
- config_entry_add_from_file(config, device, f->FileName, content, loaded_image_path);
- FreePool(content);
- }
- uefi_call_wrapper(entries_dir->Close, 1, entries_dir);
- }
-
- /* sort entries after version number */
- for (i = 1; i < config->entry_count; i++) {
- BOOLEAN more;
- UINTN k;
-
- more = FALSE;
- for (k = 0; k < config->entry_count - i; k++) {
- ConfigEntry *entry;
-
- if (str_verscmp(config->entries[k]->file, config->entries[k+1]->file) <= 0)
- continue;
- entry = config->entries[k];
- config->entries[k] = config->entries[k+1];
- config->entries[k+1] = entry;
- more = TRUE;
- }
- if (!more)
- break;
- }
-}
-
-static VOID config_default_entry_select(Config *config) {
- CHAR16 *var;
- EFI_STATUS err;
- UINTN i;
-
- /*
- * The EFI variable to specify a boot entry for the next, and only the
- * next reboot. The variable is always cleared directly after it is read.
- */
- err = efivar_get(L"LoaderEntryOneShot", &var);
- if (!EFI_ERROR(err)) {
- BOOLEAN found = FALSE;
-
- for (i = 0; i < config->entry_count; i++) {
- if (StrCmp(config->entries[i]->file, var) == 0) {
- config->idx_default = i;
- found = TRUE;
- break;
- }
- }
-
- config->entry_oneshot = StrDuplicate(var);
- efivar_set(L"LoaderEntryOneShot", NULL, TRUE);
- FreePool(var);
- if (found)
- return;
- }
-
- /*
- * The EFI variable to select the default boot entry overrides the
- * configured pattern. The variable can be set and cleared by pressing
- * the 'd' key in the loader selection menu, the entry is marked with
- * an '*'.
- */
- err = efivar_get(L"LoaderEntryDefault", &var);
- if (!EFI_ERROR(err)) {
- BOOLEAN found = FALSE;
-
- for (i = 0; i < config->entry_count; i++) {
- if (StrCmp(config->entries[i]->file, var) == 0) {
- config->idx_default = i;
- config->idx_default_efivar = i;
- found = TRUE;
- break;
- }
- }
- FreePool(var);
- if (found)
- return;
- }
- config->idx_default_efivar = -1;
-
- if (config->entry_count == 0)
- return;
-
- /*
- * Match the pattern from the end of the list to the start, find last
- * entry (largest number) matching the given pattern.
- */
- if (config->entry_default_pattern) {
- i = config->entry_count;
- while (i--) {
- if (config->entries[i]->no_autoselect)
- continue;
- if (MetaiMatch(config->entries[i]->file, config->entry_default_pattern)) {
- config->idx_default = i;
- return;
- }
- }
- }
-
- /* select the last suitable entry */
- i = config->entry_count;
- while (i--) {
- if (config->entries[i]->no_autoselect)
- continue;
- config->idx_default = i;
- return;
- }
-
- /* no entry found */
- config->idx_default = -1;
-}
-
-/* generate a unique title, avoiding non-distinguishable menu entries */
-static VOID config_title_generate(Config *config) {
- UINTN i, k;
- BOOLEAN unique;
-
- /* set title */
- for (i = 0; i < config->entry_count; i++) {
- CHAR16 *title;
-
- FreePool(config->entries[i]->title_show);
- title = config->entries[i]->title;
- if (!title)
- title = config->entries[i]->file;
- config->entries[i]->title_show = StrDuplicate(title);
- }
-
- unique = TRUE;
- for (i = 0; i < config->entry_count; i++) {
- for (k = 0; k < config->entry_count; k++) {
- if (i == k)
- continue;
- if (StrCmp(config->entries[i]->title_show, config->entries[k]->title_show) != 0)
- continue;
-
- unique = FALSE;
- config->entries[i]->non_unique = TRUE;
- config->entries[k]->non_unique = TRUE;
- }
- }
- if (unique)
- return;
-
- /* add version to non-unique titles */
- for (i = 0; i < config->entry_count; i++) {
- CHAR16 *s;
-
- if (!config->entries[i]->non_unique)
- continue;
- if (!config->entries[i]->version)
- continue;
-
- s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, config->entries[i]->version);
- FreePool(config->entries[i]->title_show);
- config->entries[i]->title_show = s;
- config->entries[i]->non_unique = FALSE;
- }
-
- unique = TRUE;
- for (i = 0; i < config->entry_count; i++) {
- for (k = 0; k < config->entry_count; k++) {
- if (i == k)
- continue;
- if (StrCmp(config->entries[i]->title_show, config->entries[k]->title_show) != 0)
- continue;
-
- unique = FALSE;
- config->entries[i]->non_unique = TRUE;
- config->entries[k]->non_unique = TRUE;
- }
- }
- if (unique)
- return;
-
- /* add machine-id to non-unique titles */
- for (i = 0; i < config->entry_count; i++) {
- CHAR16 *s;
- CHAR16 *m;
-
- if (!config->entries[i]->non_unique)
- continue;
- if (!config->entries[i]->machine_id)
- continue;
-
- m = StrDuplicate(config->entries[i]->machine_id);
- m[8] = '\0';
- s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, m);
- FreePool(config->entries[i]->title_show);
- config->entries[i]->title_show = s;
- config->entries[i]->non_unique = FALSE;
- FreePool(m);
- }
-
- unique = TRUE;
- for (i = 0; i < config->entry_count; i++) {
- for (k = 0; k < config->entry_count; k++) {
- if (i == k)
- continue;
- if (StrCmp(config->entries[i]->title_show, config->entries[k]->title_show) != 0)
- continue;
-
- unique = FALSE;
- config->entries[i]->non_unique = TRUE;
- config->entries[k]->non_unique = TRUE;
- }
- }
- if (unique)
- return;
-
- /* add file name to non-unique titles */
- for (i = 0; i < config->entry_count; i++) {
- CHAR16 *s;
-
- if (!config->entries[i]->non_unique)
- continue;
- s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, config->entries[i]->file);
- FreePool(config->entries[i]->title_show);
- config->entries[i]->title_show = s;
- config->entries[i]->non_unique = FALSE;
- }
-}
-
-static BOOLEAN config_entry_add_call(Config *config, CHAR16 *title, EFI_STATUS (*call)(VOID)) {
- ConfigEntry *entry;
-
- entry = AllocateZeroPool(sizeof(ConfigEntry));
- entry->title = StrDuplicate(title);
- entry->call = call;
- entry->no_autoselect = TRUE;
- config_add_entry(config, entry);
- return TRUE;
-}
-
-static ConfigEntry *config_entry_add_loader(Config *config, EFI_HANDLE *device,
- enum loader_type type,CHAR16 *file, CHAR16 key, CHAR16 *title, CHAR16 *loader) {
- ConfigEntry *entry;
-
- entry = AllocateZeroPool(sizeof(ConfigEntry));
- entry->type = type;
- entry->title = StrDuplicate(title);
- entry->device = device;
- entry->loader = StrDuplicate(loader);
- entry->file = StrDuplicate(file);
- StrLwr(entry->file);
- entry->key = key;
- config_add_entry(config, entry);
-
- return entry;
-}
-
-static BOOLEAN config_entry_add_loader_auto(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path,
- CHAR16 *file, CHAR16 key, CHAR16 *title, CHAR16 *loader) {
- EFI_FILE_HANDLE handle;
- ConfigEntry *entry;
- EFI_STATUS err;
-
- /* do not add an entry for ourselves */
- if (loaded_image_path && StriCmp(loader, loaded_image_path) == 0)
- return FALSE;
-
- /* check existence */
- err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, loader, EFI_FILE_MODE_READ, 0ULL);
- if (EFI_ERROR(err))
- return FALSE;
- uefi_call_wrapper(handle->Close, 1, handle);
-
- entry = config_entry_add_loader(config, device, LOADER_UNDEFINED, file, key, title, loader);
- if (!entry)
- return FALSE;
-
- /* do not boot right away into auto-detected entries */
- entry->no_autoselect = TRUE;
-
- return TRUE;
-}
-
-static VOID config_entry_add_osx(Config *config) {
- EFI_STATUS err;
- UINTN handle_count = 0;
- EFI_HANDLE *handles = NULL;
-
- err = LibLocateHandle(ByProtocol, &FileSystemProtocol, NULL, &handle_count, &handles);
- if (!EFI_ERROR(err)) {
- UINTN i;
-
- for (i = 0; i < handle_count; i++) {
- EFI_FILE *root;
- BOOLEAN found;
-
- root = LibOpenRoot(handles[i]);
- if (!root)
- continue;
- found = config_entry_add_loader_auto(config, handles[i], root, NULL, L"auto-osx", 'a', L"OS X",
- L"\\System\\Library\\CoreServices\\boot.efi");
- uefi_call_wrapper(root->Close, 1, root);
- if (found)
- break;
- }
-
- FreePool(handles);
- }
-}
-
-static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_image, EFI_FILE *root_dir) {
- EFI_FILE_HANDLE linux_dir;
- EFI_STATUS err;
-
- err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &linux_dir, L"\\EFI\\Linux", EFI_FILE_MODE_READ, 0ULL);
- if (!EFI_ERROR(err)) {
- for (;;) {
- CHAR16 buf[256];
- UINTN bufsize;
- EFI_FILE_INFO *f;
- CHAR8 *sections[] = {
- (UINT8 *)".osrel",
- NULL
- };
- UINTN offs[ELEMENTSOF(sections)-1] = {};
- UINTN szs[ELEMENTSOF(sections)-1] = {};
- UINTN addrs[ELEMENTSOF(sections)-1] = {};
- CHAR8 *content = NULL;
- UINTN len;
- CHAR8 *line;
- UINTN pos = 0;
- CHAR8 *key, *value;
- CHAR16 *os_name = NULL;
- CHAR16 *os_id = NULL;
- CHAR16 *os_version = NULL;
-
- bufsize = sizeof(buf);
- err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf);
- if (bufsize == 0 || EFI_ERROR(err))
- break;
-
- f = (EFI_FILE_INFO *) buf;
- if (f->FileName[0] == '.')
- continue;
- if (f->Attribute & EFI_FILE_DIRECTORY)
- continue;
- len = StrLen(f->FileName);
- if (len < 5)
- continue;
- if (StriCmp(f->FileName + len - 4, L".efi") != 0)
- continue;
-
- /* look for an .osrel section in the .efi binary */
- err = pefile_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs);
- if (EFI_ERROR(err))
- continue;
-
- len = file_read(linux_dir, f->FileName, offs[0], szs[0], &content);
- if (len <= 0)
- continue;
-
- /* read properties from the embedded os-release file */
- line = content;
- while ((line = line_get_key_value(content, (CHAR8 *)"=", &pos, &key, &value))) {
- if (strcmpa((CHAR8 *)"PRETTY_NAME", key) == 0) {
- os_name = stra_to_str(value);
- continue;
- }
-
- if (strcmpa((CHAR8 *)"ID", key) == 0) {
- os_id = stra_to_str(value);
- continue;
- }
-
- if (strcmpa((CHAR8 *)"VERSION_ID", key) == 0) {
- os_version = stra_to_str(value);
- continue;
- }
- }
-
- if (os_name && os_id && os_version) {
- CHAR16 *conf;
- CHAR16 *path;
-
- conf = PoolPrint(L"%s-%s", os_id, os_version);
- path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
- config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path);
- FreePool(conf);
- FreePool(path);
- FreePool(os_name);
- FreePool(os_id);
- FreePool(os_version);
- }
-
- FreePool(content);
- }
- uefi_call_wrapper(linux_dir->Close, 1, linux_dir);
- }
-}
-
-static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, const ConfigEntry *entry) {
- EFI_HANDLE image;
- EFI_DEVICE_PATH *path;
- CHAR16 *options;
- EFI_STATUS err;
-
- path = FileDevicePath(entry->device, entry->loader);
- if (!path) {
- Print(L"Error getting device path.");
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- return EFI_INVALID_PARAMETER;
- }
-
- err = uefi_call_wrapper(BS->LoadImage, 6, FALSE, parent_image, path, NULL, 0, &image);
- if (EFI_ERROR(err)) {
- Print(L"Error loading %s: %r", entry->loader, err);
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- goto out;
- }
-
- if (config->options_edit)
- options = config->options_edit;
- else if (entry->options)
- options = entry->options;
- else
- options = NULL;
- if (options) {
- EFI_LOADED_IMAGE *loaded_image;
-
- err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
- parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (EFI_ERROR(err)) {
- Print(L"Error getting LoadedImageProtocol handle: %r", err);
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- goto out_unload;
- }
- loaded_image->LoadOptions = options;
- loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16);
- }
-
- efivar_set_time_usec(L"LoaderTimeExecUSec", 0);
- err = uefi_call_wrapper(BS->StartImage, 3, image, NULL, NULL);
-out_unload:
- uefi_call_wrapper(BS->UnloadImage, 1, image);
-out:
- FreePool(path);
- return err;
-}
-
-static EFI_STATUS reboot_into_firmware(VOID) {
- CHAR8 *b;
- UINTN size;
- UINT64 osind;
- EFI_STATUS err;
-
- osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
-
- err = efivar_get_raw(&global_guid, L"OsIndications", &b, &size);
- if (!EFI_ERROR(err))
- osind |= (UINT64)*b;
- FreePool(b);
-
- err = efivar_set_raw(&global_guid, L"OsIndications", (CHAR8 *)&osind, sizeof(UINT64), TRUE);
- if (EFI_ERROR(err))
- return err;
-
- err = uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold, EFI_SUCCESS, 0, NULL);
- Print(L"Error calling ResetSystem: %r", err);
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- return err;
-}
-
-static VOID config_free(Config *config) {
- UINTN i;
-
- for (i = 0; i < config->entry_count; i++)
- config_entry_free(config->entries[i]);
- FreePool(config->entries);
- FreePool(config->entry_default_pattern);
- FreePool(config->options_edit);
- FreePool(config->entry_oneshot);
-}
-
-EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
- CHAR16 *s;
- CHAR8 *b;
- UINTN size;
- EFI_LOADED_IMAGE *loaded_image;
- EFI_FILE *root_dir;
- CHAR16 *loaded_image_path;
- EFI_DEVICE_PATH *device_path;
- EFI_STATUS err;
- Config config;
- UINT64 init_usec;
- BOOLEAN menu = FALSE;
-
- InitializeLib(image, sys_table);
- init_usec = time_usec();
- efivar_set_time_usec(L"LoaderTimeInitUSec", init_usec);
- efivar_set(L"LoaderInfo", L"systemd-boot " VERSION, FALSE);
- s = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
- efivar_set(L"LoaderFirmwareInfo", s, FALSE);
- FreePool(s);
- s = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
- efivar_set(L"LoaderFirmwareType", s, FALSE);
- FreePool(s);
-
- 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;
- }
-
- /* export the device path this image is started from */
- device_path = DevicePathFromHandle(loaded_image->DeviceHandle);
- if (device_path) {
- EFI_DEVICE_PATH *path, *paths;
-
- paths = UnpackDevicePath(device_path);
- for (path = paths; !IsDevicePathEnd(path); path = NextDevicePathNode(path)) {
- HARDDRIVE_DEVICE_PATH *drive;
- CHAR16 uuid[37];
-
- if (DevicePathType(path) != MEDIA_DEVICE_PATH)
- continue;
- if (DevicePathSubType(path) != MEDIA_HARDDRIVE_DP)
- continue;
- drive = (HARDDRIVE_DEVICE_PATH *)path;
- if (drive->SignatureType != SIGNATURE_TYPE_GUID)
- continue;
-
- GuidToString(uuid, (EFI_GUID *)&drive->Signature);
- efivar_set(L"LoaderDevicePartUUID", uuid, FALSE);
- break;
- }
- FreePool(paths);
- }
-
- 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;
- }
-
-
- /* the filesystem path to this image, to prevent adding ourselves to the menu */
- loaded_image_path = DevicePathToStr(loaded_image->FilePath);
- efivar_set(L"LoaderImageIdentifier", loaded_image_path, FALSE);
-
- /* scan "\loader\entries\*.conf" files */
- ZeroMem(&config, sizeof(Config));
- config_load(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
-
- /* if we find some well-known loaders, add them to the end of the list */
- config_entry_add_linux(&config, loaded_image, root_dir);
- config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
- L"auto-windows", 'w', L"Windows Boot Manager", L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi");
- config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
- L"auto-efi-shell", 's', L"EFI Shell", L"\\shell" EFI_MACHINE_TYPE_NAME ".efi");
- config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path,
- L"auto-efi-default", '\0', L"EFI Default Loader", L"\\EFI\\Boot\\boot" EFI_MACHINE_TYPE_NAME ".efi");
- config_entry_add_osx(&config);
-
- if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) {
- UINT64 osind = (UINT64)*b;
-
- if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
- config_entry_add_call(&config, L"Reboot Into Firmware Interface", reboot_into_firmware);
- FreePool(b);
- }
-
- if (config.entry_count == 0) {
- Print(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- goto out;
- }
-
- config_title_generate(&config);
-
- /* select entry by configured pattern or EFI LoaderDefaultEntry= variable*/
- config_default_entry_select(&config);
-
- /* if no configured entry to select from was found, enable the menu */
- if (config.idx_default == -1) {
- config.idx_default = 0;
- if (config.timeout_sec == 0)
- config.timeout_sec = 10;
- }
-
- /* select entry or show menu when key is pressed or timeout is set */
- if (config.timeout_sec == 0) {
- UINT64 key;
-
- err = console_key_read(&key, FALSE);
- if (!EFI_ERROR(err)) {
- INT16 idx;
-
- /* find matching key in config entries */
- idx = entry_lookup_key(&config, config.idx_default, KEYCHAR(key));
- if (idx >= 0)
- config.idx_default = idx;
- else
- menu = TRUE;
- }
- } else
- menu = TRUE;
-
- for (;;) {
- ConfigEntry *entry;
-
- entry = config.entries[config.idx_default];
- if (menu) {
- efivar_set_time_usec(L"LoaderTimeMenuUSec", 0);
- uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x10000, 0, NULL);
- if (!menu_run(&config, &entry, loaded_image_path))
- break;
-
- /* run special entry like "reboot" */
- if (entry->call) {
- entry->call();
- continue;
- }
- }
-
- /* export the selected boot entry to the system */
- efivar_set(L"LoaderEntrySelected", entry->file, FALSE);
-
- uefi_call_wrapper(BS->SetWatchdogTimer, 4, 5 * 60, 0x10000, 0, NULL);
- err = image_start(image, &config, entry);
- if (EFI_ERROR(err)) {
- graphics_mode(FALSE);
- Print(L"\nFailed to execute %s (%s): %r\n", entry->title, entry->loader, err);
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- goto out;
- }
-
- menu = TRUE;
- config.timeout_sec = 0;
- }
- err = EFI_SUCCESS;
-out:
- FreePool(loaded_image_path);
- config_free(&config);
- uefi_call_wrapper(root_dir->Close, 1, root_dir);
- uefi_call_wrapper(BS->CloseProtocol, 4, image, &LoadedImageProtocol, image, NULL);
- return err;
-}
diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c
deleted file mode 100644
index 6206c80317..0000000000
--- a/src/boot/efi/console.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*-*- 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;
-}
diff --git a/src/boot/efi/console.h b/src/boot/efi/console.h
deleted file mode 100644
index 5c7808a067..0000000000
--- a/src/boot/efi/console.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- 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
diff --git a/src/boot/efi/graphics.c b/src/boot/efi/graphics.c
deleted file mode 100644
index 2e9c11f5a0..0000000000
--- a/src/boot/efi/graphics.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*-*- 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, &current, &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;
-}
diff --git a/src/boot/efi/graphics.h b/src/boot/efi/graphics.h
deleted file mode 100644
index 3ee4972798..0000000000
--- a/src/boot/efi/graphics.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- 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);
-#endif
diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c
deleted file mode 100644
index 809c69310e..0000000000
--- a/src/boot/efi/linux.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*-*- 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;
-}
diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h
deleted file mode 100644
index aff69a9778..0000000000
--- a/src/boot/efi/linux.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- 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
diff --git a/src/boot/efi/pefile.c b/src/boot/efi/pefile.c
deleted file mode 100644
index e6fedbc929..0000000000
--- a/src/boot/efi/pefile.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*-*- 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, &sect);
- 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;
-}
diff --git a/src/boot/efi/pefile.h b/src/boot/efi/pefile.h
deleted file mode 100644
index ca2f9a2508..0000000000
--- a/src/boot/efi/pefile.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*-*- 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
diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c
deleted file mode 100644
index 470ea3e2cc..0000000000
--- a/src/boot/efi/splash.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*-*- 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 "graphics.h"
-#include "splash.h"
-
-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 = ((UINTN) 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(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background) {
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL pixel = {};
- EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
- EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
- 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;
-
- if (!background) {
- if (StriCmp(L"Apple", ST->FirmwareVendor) == 0) {
- pixel.Red = 0xc0;
- pixel.Green = 0xc0;
- pixel.Blue = 0xc0;
- }
- background = &pixel;
- }
-
- err = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
- if (EFI_ERROR(err))
- return err;
-
- 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);
- return err;
-}
diff --git a/src/boot/efi/splash.h b/src/boot/efi/splash.h
deleted file mode 100644
index 0183e79b16..0000000000
--- a/src/boot/efi/splash.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*-*- 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_SPLASH_H
-#define __SDBOOT_SPLASH_H
-
-EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background);
-#endif
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
deleted file mode 100644
index 0b1bc491ed..0000000000
--- a/src/boot/efi/stub.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*-*- 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 "graphics.h"
-#include "splash.h"
-#include "linux.h"
-
-/* magic string to find in the binary image */
-static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-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",
- (UINT8 *)".splash",
- 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;
- }
-
- if (szs[3] > 0)
- graphics_splash((UINT8 *)((UINTN)loaded_image->ImageBase + addrs[3]), szs[3], NULL);
-
- err = linux_exec(image, cmdline, cmdline_len,
- (UINTN)loaded_image->ImageBase + addrs[1],
- (UINTN)loaded_image->ImageBase + addrs[2], szs[2]);
-
- graphics_mode(FALSE);
- Print(L"Execution of embedded linux image failed: %r\n", err);
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- return err;
-}
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
deleted file mode 100644
index ba5ed7d22f..0000000000
--- a/src/boot/efi/util.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*-*- 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 parse_boolean(CHAR8 *v, BOOLEAN *b) {
- if (strcmpa(v, (CHAR8 *)"1") == 0 ||
- strcmpa(v, (CHAR8 *)"yes") == 0 ||
- strcmpa(v, (CHAR8 *)"y") == 0 ||
- strcmpa(v, (CHAR8 *)"true") == 0) {
- *b = TRUE;
- return EFI_SUCCESS;
- }
-
- if (strcmpa(v, (CHAR8 *)"0") == 0 ||
- strcmpa(v, (CHAR8 *)"no") == 0 ||
- strcmpa(v, (CHAR8 *)"n") == 0 ||
- strcmpa(v, (CHAR8 *)"false") == 0) {
- *b = FALSE;
- return EFI_SUCCESS;
- }
-
- return EFI_INVALID_PARAMETER;
-}
-
-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;
-}
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
deleted file mode 100644
index 4727a34d1f..0000000000
--- a/src/boot/efi/util.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*-*- 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]))
-
-static inline const CHAR16 *yes_no(BOOLEAN b) {
- return b ? L"yes" : L"no";
-}
-
-EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b);
-
-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