2022-07-08 18:49:15 +01:00
|
|
|
/* SPDX-FileCopyrightText: 2022 Andrius Štikonas <andrius@stikonas.eu>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
|
|
|
|
|
|
/* Written in a low level C that is close to assembly.
|
|
|
|
* We skip error checking since this is a prototype for hex0 code */
|
|
|
|
|
|
|
|
#include "efi/efi.h"
|
|
|
|
|
2022-07-30 10:08:23 +01:00
|
|
|
#define max_string 2048
|
2022-07-08 18:49:15 +01:00
|
|
|
|
|
|
|
#define HARDWARE_DEVICE_PATH 1
|
|
|
|
#define END_HARDWARE_DEVICE_PATH 0x7F
|
|
|
|
#define END_ENTIRE_DEVICE_PATH 0xFF
|
|
|
|
#define MEMORY_MAPPED 3
|
|
|
|
|
|
|
|
efi_status_t efi_main(efi_handle_t image_handle, struct efi_system_table *system)
|
|
|
|
{
|
|
|
|
struct efi_loaded_image_protocol *image, *child_image;
|
|
|
|
struct efi_simple_file_system_protocol *rootfs;
|
|
|
|
struct efi_file_protocol *rootdir;
|
|
|
|
struct efi_guid guid1 = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
|
|
|
struct efi_guid guid2 = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
|
|
|
struct efi_guid guid3 = EFI_FILE_INFO_GUID;
|
|
|
|
|
2022-07-11 22:44:15 +01:00
|
|
|
system->boot->set_watchdog_timer(0, 0, 0, NULL);
|
|
|
|
|
2022-07-08 18:49:15 +01:00
|
|
|
/* Open Loaded Image protocol */
|
|
|
|
system->boot->open_protocol(image_handle, &guid1, (void **) &image, image_handle, 0,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
|
|
|
|
|
|
|
|
/* Command line args */
|
|
|
|
uint16_t *options = image->load_options;
|
|
|
|
uint16_t default_file[] = L"kaem.amd64";
|
|
|
|
uint16_t *script_file;
|
|
|
|
do {
|
|
|
|
++options;
|
|
|
|
} while (*options != ' ' && *options != 0); /* Skip app name */
|
|
|
|
|
|
|
|
if (! *options) {
|
|
|
|
script_file = default_file;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
script_file = ++options;
|
|
|
|
}
|
|
|
|
|
2022-07-30 10:08:23 +01:00
|
|
|
/* Get root file system */
|
2022-07-08 18:49:15 +01:00
|
|
|
efi_handle_t root_device = image->device;
|
|
|
|
system->boot->open_protocol(root_device, &guid2, (void **) &rootfs, image_handle, 0,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
|
2022-07-30 10:08:23 +01:00
|
|
|
/* Get root directory */
|
2022-07-08 18:49:15 +01:00
|
|
|
rootfs->open_volume(rootfs, &rootdir);
|
|
|
|
|
|
|
|
/* Open file for reading */
|
|
|
|
struct efi_file_protocol *fin;
|
|
|
|
efi_status_t status = rootdir->open(rootdir, &fin, script_file, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY);
|
|
|
|
if(status != EFI_SUCCESS) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t *command;
|
|
|
|
system->boot->allocate_pool(EFI_LOADER_DATA, 2 * max_string, (void **) &command);
|
|
|
|
|
|
|
|
unsigned int command_length = 0; /* length of command without arguments */
|
|
|
|
unsigned int i;
|
|
|
|
uint8_t c;
|
|
|
|
efi_uint_t size = 1;
|
2022-07-30 10:08:23 +01:00
|
|
|
efi_uint_t file_size;
|
2022-07-08 18:49:15 +01:00
|
|
|
efi_uint_t return_code;
|
|
|
|
void *executable;
|
|
|
|
efi_handle_t child_ih;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
i = 0;
|
|
|
|
command_length = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
fin->read(fin, &size, &c);
|
|
|
|
if (size == 0) {
|
|
|
|
rootdir->close(fin);
|
|
|
|
system->boot->free_pool(command);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
else if(c == '\n') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (c == ' ' && command_length == 0) {
|
|
|
|
command_length = i;
|
|
|
|
}
|
|
|
|
else if (c == '#') {
|
|
|
|
/* Line comments */
|
|
|
|
do {
|
|
|
|
fin->read(fin, &size, &c);
|
|
|
|
} while (c != '\n');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
command[i] = c;
|
|
|
|
i++;
|
|
|
|
} while(true);
|
|
|
|
|
|
|
|
if (command_length == 0 ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
command[i] = 0;
|
|
|
|
|
|
|
|
system->out->output_string(system->out, L" +> ");
|
|
|
|
system->out->output_string(system->out, command);
|
|
|
|
system->out->output_string(system->out, L"\r\n");
|
|
|
|
|
|
|
|
command[command_length] = 0;
|
|
|
|
|
|
|
|
/* Open executable file for reading and load it into memory */
|
|
|
|
struct efi_file_protocol *fcmd;
|
|
|
|
efi_status_t status = rootdir->open(rootdir, &fcmd, command, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY);
|
|
|
|
if(status != EFI_SUCCESS) {
|
|
|
|
system->boot->free_pool(command);
|
|
|
|
rootdir->close(fin);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2022-07-30 22:44:48 +01:00
|
|
|
/* Deal with command line arguments */
|
|
|
|
command[command_length] = ' ';
|
|
|
|
|
2022-07-08 18:49:15 +01:00
|
|
|
struct efi_file_info *file_info;
|
2022-07-25 19:57:44 +01:00
|
|
|
file_size = sizeof(struct efi_file_info);
|
|
|
|
system->boot->allocate_pool(EFI_LOADER_DATA, file_size, (void **) &file_info);
|
|
|
|
fcmd->get_info(fcmd, &guid3, &file_size, file_info);
|
|
|
|
file_size = file_info->file_size;
|
2022-07-08 18:49:15 +01:00
|
|
|
system->boot->free_pool(file_info);
|
|
|
|
|
2022-07-25 19:57:44 +01:00
|
|
|
system->boot->allocate_pool(EFI_LOADER_CODE, file_size, (void **) &executable);
|
|
|
|
fcmd->read(fcmd, &file_size, executable);
|
2022-07-30 10:08:23 +01:00
|
|
|
fcmd->close(fcmd);
|
2022-07-08 18:49:15 +01:00
|
|
|
|
|
|
|
struct efi_device_path_protocol *device_path;
|
|
|
|
system->boot->allocate_pool(EFI_LOADER_DATA, 4 + sizeof(struct efi_device_path_protocol), (void **) &device_path);
|
|
|
|
device_path->type = HARDWARE_DEVICE_PATH;
|
|
|
|
device_path->subtype = MEMORY_MAPPED;
|
|
|
|
device_path->length = sizeof(struct efi_device_path_protocol);
|
|
|
|
device_path->memory_type = EFI_LOADER_CODE;
|
|
|
|
device_path->start_address = (uint64_t) executable;
|
2022-07-25 19:57:44 +01:00
|
|
|
device_path->end_address = (uint64_t) executable + file_size;
|
2022-07-08 18:49:15 +01:00
|
|
|
device_path[1].type = END_HARDWARE_DEVICE_PATH;
|
|
|
|
device_path[1].subtype = END_ENTIRE_DEVICE_PATH;
|
|
|
|
device_path[1].length = 4;
|
|
|
|
|
2022-07-25 19:57:44 +01:00
|
|
|
system->boot->load_image(0, image_handle, device_path, executable, file_size, &child_ih);
|
2022-07-08 18:49:15 +01:00
|
|
|
system->boot->free_pool(device_path);
|
|
|
|
system->boot->free_pool(executable);
|
|
|
|
|
|
|
|
system->boot->open_protocol(child_ih, &guid1, (void **) &child_image, child_ih, 0,
|
|
|
|
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
|
|
|
|
child_image->load_options = command;
|
2022-07-30 22:44:48 +01:00
|
|
|
child_image->load_options_size = i;
|
2022-07-08 18:49:15 +01:00
|
|
|
child_image->device = image->device;
|
|
|
|
|
|
|
|
/* Run command */
|
|
|
|
return_code = system->boot->start_image(child_ih, 0, 0);
|
|
|
|
|
|
|
|
if(return_code != 0) {
|
|
|
|
system->boot->free_pool(command);
|
|
|
|
system->out->output_string(system->out, L"Subprocess error.\r\n");
|
2022-07-30 10:08:23 +01:00
|
|
|
rootdir->close(fin);
|
2022-07-08 18:49:15 +01:00
|
|
|
return return_code;
|
|
|
|
}
|
|
|
|
} while(true);
|
|
|
|
}
|