aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/boot/efi/include/efilib.h5
-rw-r--r--sys/boot/efi/libefi/Makefile2
-rw-r--r--sys/boot/efi/libefi/libefi.c131
-rw-r--r--sys/boot/efi/loader/main.c22
-rw-r--r--sys/boot/ia64/efi/main.c22
5 files changed, 141 insertions, 41 deletions
diff --git a/sys/boot/efi/include/efilib.h b/sys/boot/efi/include/efilib.h
index 9d79939733e1..695f334d48bb 100644
--- a/sys/boot/efi/include/efilib.h
+++ b/sys/boot/efi/include/efilib.h
@@ -31,4 +31,7 @@ extern EFI_SYSTEM_TABLE *ST;
extern EFI_BOOT_SERVICES *BS;
extern EFI_RUNTIME_SERVICES *RS;
-void efi_init(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
+void efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
+
+EFI_STATUS main(int argc, CHAR16 *argv[]);
+void exit(EFI_STATUS status);
diff --git a/sys/boot/efi/libefi/Makefile b/sys/boot/efi/libefi/Makefile
index 894b14371c09..6ab48e254bc6 100644
--- a/sys/boot/efi/libefi/Makefile
+++ b/sys/boot/efi/libefi/Makefile
@@ -5,7 +5,7 @@
LIB= efi
INTERNALLIB= true
-SRCS= libefi.c efi_console.c time.c copy.c devicename.c module.c exit.c
+SRCS= libefi.c efi_console.c time.c copy.c devicename.c module.c
SRCS+= delay.c efifs.c efinet.c elf_freebsd.c bootinfo.c pal.s
.if ${MACHINE_ARCH} == "ia64"
diff --git a/sys/boot/efi/libefi/libefi.c b/sys/boot/efi/libefi/libefi.c
index c0bacc8a0bc5..e28d8db71f79 100644
--- a/sys/boot/efi/libefi/libefi.c
+++ b/sys/boot/efi/libefi/libefi.c
@@ -31,17 +31,146 @@ static const char rcsid[] =
#include <efi.h>
#include <efilib.h>
+#include <stand.h>
EFI_HANDLE IH;
EFI_SYSTEM_TABLE *ST;
EFI_BOOT_SERVICES *BS;
EFI_RUNTIME_SERVICES *RS;
+static EFI_PHYSICAL_ADDRESS heap;
+static UINTN heapsize;
+
+static CHAR16 *
+arg_skipsep(CHAR16 *argp)
+{
+
+ while (*argp == ' ' || *argp == '\t')
+ argp++;
+ return (argp);
+}
+
+static CHAR16 *
+arg_skipword(CHAR16 *argp)
+{
+
+ while (*argp && *argp != ' ' && *argp != '\t')
+ argp++;
+ return (argp);
+}
+
+void exit(EFI_STATUS exit_code)
+{
+
+ BS->FreePages(heap, EFI_SIZE_TO_PAGES(heapsize));
+ BS->Exit(IH, exit_code, 0, NULL);
+}
+
void
-efi_init(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
+efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
{
+ static EFI_GUID image_protocol = LOADED_IMAGE_PROTOCOL;
+ EFI_LOADED_IMAGE *img;
+ CHAR16 *argp, *args, **argv;
+ EFI_STATUS status;
+ int argc, addprog;
+
IH = image_handle;
ST = system_table;
BS = ST->BootServices;
RS = ST->RuntimeServices;
+
+ heapsize = 512*1024;
+ status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
+ EFI_SIZE_TO_PAGES(heapsize), &heap);
+ if (status != EFI_SUCCESS)
+ BS->Exit(IH, status, 0, NULL);
+
+ setheap((void *)heap, (void *)(heap + heapsize));
+
+ /* Use exit() from here on... */
+
+ status = BS->HandleProtocol(IH, &image_protocol, (VOID**)&img);
+ if (status != EFI_SUCCESS)
+ exit(status);
+
+ /*
+ * Pre-process the (optional) load options. If the option string
+ * is given as an ASCII string, we use a poor man's ASCII to
+ * Unicode-16 translation. The size of the option string as given
+ * to us includes the terminating null character. We assume the
+ * string is an ASCII string if strlen() plus the terminating
+ * '\0' is less than LoadOptionsSize. Even if all Unicode-16
+ * characters have the upper 8 bits non-zero, the terminating
+ * null character will cause a one-off.
+ * If the string is already in Unicode-16, we make a copy so that
+ * we know we can always modify the string.
+ */
+ if (img->LoadOptionsSize) {
+ if (img->LoadOptionsSize == strlen(img->LoadOptions) + 1) {
+ args = malloc(img->LoadOptionsSize << 1);
+ for (argc = 0; argc < img->LoadOptionsSize; argc++)
+ args[argc] = ((char*)img->LoadOptions)[argc];
+ } else {
+ args = malloc(img->LoadOptionsSize);
+ memcpy(args, img->LoadOptions, img->LoadOptionsSize);
+ }
+ } else
+ args = NULL;
+
+ /*
+ * Use a quick and dirty algorithm to build the argv vector. We
+ * first count the number of words. Then, after allocating the
+ * vector, we split the string up. We don't deal with quotes or
+ * other more advanced shell features.
+ * The EFI shell will pas the name of the image as the first
+ * word in the argument list. This does not happen if we're
+ * loaded by the boot manager. This is not so easy to figure
+ * out though. The ParentHandle is not always NULL, because
+ * there can be a function (=image) that will perform the task
+ * for the boot manager.
+ */
+ /* Part 1: Figure out if we need to add our program name. */
+ addprog = (args == NULL || img->ParentHandle == NULL ||
+ img->FilePath == NULL) ? 1 : 0;
+ if (!addprog) {
+ addprog =
+ (DevicePathType(img->FilePath) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType(img->FilePath) != MEDIA_FILEPATH_DP ||
+ DevicePathNodeLength(img->FilePath) <=
+ sizeof(FILEPATH_DEVICE_PATH)) ? 1 : 0;
+ if (!addprog) {
+ /* XXX todo. */
+ }
+ }
+ /* Part 2: count words. */
+ argc = (addprog) ? 1 : 0;
+ argp = args;
+ while (argp != NULL && *argp != 0) {
+ argp = arg_skipsep(argp);
+ if (*argp == 0)
+ break;
+ argc++;
+ argp = arg_skipword(argp);
+ }
+ /* Part 3: build vector. */
+ argv = malloc((argc + 1) * sizeof(CHAR16*));
+ argc = 0;
+ if (addprog)
+ argv[argc++] = L"loader.efi";
+ argp = args;
+ while (argp != NULL && *argp != 0) {
+ argp = arg_skipsep(argp);
+ if (*argp == 0)
+ break;
+ argv[argc++] = argp;
+ argp = arg_skipword(argp);
+ /* Terminate the words. */
+ if (*argp != 0)
+ *argp++ = 0;
+ }
+ argv[argc] = NULL;
+
+ status = main(argc, argv);
+ exit(status);
}
diff --git a/sys/boot/efi/loader/main.c b/sys/boot/efi/loader/main.c
index 5a886ed2e805..51ac572b9f3e 100644
--- a/sys/boot/efi/loader/main.c
+++ b/sys/boot/efi/loader/main.c
@@ -104,27 +104,13 @@ find_pal_proc(void)
}
EFI_STATUS
-efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
+main(int argc, CHAR16 *argv[])
{
- EFI_PHYSICAL_ADDRESS mem;
EFI_LOADED_IMAGE *img;
EFI_SIMPLE_NETWORK *net;
EFI_STATUS status;
- struct ia64_pal_result res;
- char buf[32];
int i;
- efi_init(image_handle, system_table);
-
- /*
- * Initialise the heap as early as possible. Once this is done,
- * alloc() is usable. The stack is buried inside us, so this is
- * safe.
- */
- BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
- 512*1024/4096, &mem);
- setheap((void *)mem, (void *)(mem + 512*1024));
-
/*
* XXX Chicken-and-egg problem; we want to have console output
* early, but some console attributes may depend on reading from
@@ -148,7 +134,7 @@ efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
(devsw[i]->dv_init)();
efinet_init_driver();
-
+
printf("\n");
printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
printf("(%s, %s)\n", bootprog_maker, bootprog_date);
@@ -156,14 +142,13 @@ efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
printf("Memory: %ld k\n", memsize() / 1024);
#endif
-
/*
* XXX quick and dirty check to see if we're loaded from the
* network. If so, we set the default device to 'net'. In all
* other cases we set the default device to 'disk'. We presume
* fixed positions in devsw for both net and disk.
*/
- BS->HandleProtocol(image_handle, &imgid, (VOID**)&img);
+ BS->HandleProtocol(IH, &imgid, (VOID**)&img);
status = BS->HandleProtocol(img->DeviceHandle, &netid, (VOID**)&net);
if (status == EFI_SUCCESS && net != NULL) {
@@ -177,7 +162,6 @@ efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
/* default to 'a' */
currdev.d_kind.efidisk.partition = 0;
}
-
currdev.d_type = currdev.d_dev->dv_type;
/*
diff --git a/sys/boot/ia64/efi/main.c b/sys/boot/ia64/efi/main.c
index 5a886ed2e805..51ac572b9f3e 100644
--- a/sys/boot/ia64/efi/main.c
+++ b/sys/boot/ia64/efi/main.c
@@ -104,27 +104,13 @@ find_pal_proc(void)
}
EFI_STATUS
-efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
+main(int argc, CHAR16 *argv[])
{
- EFI_PHYSICAL_ADDRESS mem;
EFI_LOADED_IMAGE *img;
EFI_SIMPLE_NETWORK *net;
EFI_STATUS status;
- struct ia64_pal_result res;
- char buf[32];
int i;
- efi_init(image_handle, system_table);
-
- /*
- * Initialise the heap as early as possible. Once this is done,
- * alloc() is usable. The stack is buried inside us, so this is
- * safe.
- */
- BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
- 512*1024/4096, &mem);
- setheap((void *)mem, (void *)(mem + 512*1024));
-
/*
* XXX Chicken-and-egg problem; we want to have console output
* early, but some console attributes may depend on reading from
@@ -148,7 +134,7 @@ efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
(devsw[i]->dv_init)();
efinet_init_driver();
-
+
printf("\n");
printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
printf("(%s, %s)\n", bootprog_maker, bootprog_date);
@@ -156,14 +142,13 @@ efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
printf("Memory: %ld k\n", memsize() / 1024);
#endif
-
/*
* XXX quick and dirty check to see if we're loaded from the
* network. If so, we set the default device to 'net'. In all
* other cases we set the default device to 'disk'. We presume
* fixed positions in devsw for both net and disk.
*/
- BS->HandleProtocol(image_handle, &imgid, (VOID**)&img);
+ BS->HandleProtocol(IH, &imgid, (VOID**)&img);
status = BS->HandleProtocol(img->DeviceHandle, &netid, (VOID**)&net);
if (status == EFI_SUCCESS && net != NULL) {
@@ -177,7 +162,6 @@ efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
/* default to 'a' */
currdev.d_kind.efidisk.partition = 0;
}
-
currdev.d_type = currdev.d_dev->dv_type;
/*