Skip to content

Commit 1cfdbed

Browse files
committed
efi: payload: add efi-initrd for initrd install.
Install the initrd using load file2 efi protocol but keep the ability to directly install the initrd from barebox. Signed-off-by: Chali Anis <chalianis1@gmail.com>
1 parent 1c2d8f9 commit 1cfdbed

5 files changed

Lines changed: 143 additions & 9 deletions

File tree

efi/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ config EFI_DEVICEPATH
4141
config EFI_FDT_FORCE
4242
bool
4343

44+
config EFI_INITRD_INSTALL
45+
bool
46+
4447
config EFI_PAYLOAD_DEFAULT_PATH
4548
string
4649
default "EFI/BOOT/BOOTARM.EFI" if ARM32

efi/payload/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
obj-y += init.o
44
obj-y += image.o
5+
obj-y += efi-initrd.o
56
obj-$(CONFIG_OFTREE) += fdt.o
67
bbenv-y += env-efi
78
obj-$(CONFIG_CMD_IOMEM) += iomem.o

efi/payload/efi-initrd.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <common.h>
3+
#include <driver.h>
4+
#include <init.h>
5+
#include <linux/hw_random.h>
6+
#include <efi.h>
7+
#include <efi/efi-device.h>
8+
#include <efi/device-path.h>
9+
#include <efi/efi-payload.h>
10+
11+
static efi_status_t EFIAPI efi_initrd_load_file2(
12+
struct efi_load_file_protocol *this, struct efi_device_path *file_path,
13+
bool boot_policy, unsigned long *buffer_size, void *buffer);
14+
15+
static const struct {
16+
struct efi_device_path_vendor vendor;
17+
struct efi_device_path end;
18+
} __packed initrd_dev_path = { { {
19+
DEVICE_PATH_TYPE_MEDIA_DEVICE,
20+
DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
21+
sizeof(initrd_dev_path.vendor),
22+
},
23+
EFI_LINUX_INITRD_MEDIA_GUID },
24+
{ DEVICE_PATH_TYPE_END, DEVICE_PATH_SUB_TYPE_END,
25+
DEVICE_PATH_END_LENGTH } };
26+
27+
static struct efi_device_path_memory *initrd_dev;
28+
static efi_handle_t lf2_handle = NULL;
29+
static struct efi_load_file_protocol efi_lf2_p = {
30+
.load_file = efi_initrd_load_file2
31+
};
32+
33+
static efi_status_t EFIAPI efi_initrd_load_file2(
34+
struct efi_load_file_protocol *this, struct efi_device_path *file_path,
35+
bool boot_policy, unsigned long *buffer_size, void *buffer)
36+
{
37+
size_t initrd_size;
38+
39+
pr_info("Anis here we call initrd load file2\n");
40+
41+
if (!this || this != &efi_lf2_p || !buffer_size)
42+
return EFI_INVALID_PARAMETER;
43+
44+
if (file_path->type != initrd_dev_path.end.type ||
45+
file_path->sub_type != initrd_dev_path.end.sub_type)
46+
return EFI_INVALID_PARAMETER;
47+
48+
if (boot_policy)
49+
return EFI_UNSUPPORTED;
50+
51+
initrd_size = initrd_dev->ending_address - initrd_dev->starting_address;
52+
if (!buffer || *buffer_size < initrd_size) {
53+
*buffer_size = initrd_size;
54+
return EFI_BUFFER_TOO_SMALL;
55+
} else {
56+
memcpy(buffer, (void *)(uintptr_t)initrd_dev->starting_address,
57+
initrd_size);
58+
*buffer_size = initrd_size;
59+
}
60+
61+
return EFI_SUCCESS;
62+
}
63+
64+
int efi_initrd_register(void *initrd, size_t initrd_sz)
65+
{
66+
efi_physical_addr_t mem;
67+
efi_status_t efiret;
68+
size_t sz;
69+
int ret;
70+
71+
sz = sizeof(struct efi_device_path_memory) +
72+
sizeof(struct efi_device_path);
73+
efiret = BS->allocate_pool(EFI_BOOT_SERVICES_DATA, sz, (void **)&mem);
74+
if (EFI_ERROR(efiret)) {
75+
pr_err("Failed to allocate memory for INITRD %s\n",
76+
efi_strerror(efiret));
77+
ret = -efi_errno(efiret);
78+
return ret;
79+
}
80+
81+
initrd_dev = efi_phys_to_virt(mem);
82+
initrd_dev->header.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
83+
initrd_dev->header.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
84+
initrd_dev->header.length = sizeof(struct efi_device_path_memory);
85+
initrd_dev->memory_type = EFI_LOADER_DATA;
86+
initrd_dev->starting_address = efi_virt_to_phys(initrd);
87+
initrd_dev->ending_address = efi_virt_to_phys(initrd) + initrd_sz;
88+
89+
memcpy(&initrd_dev[1], &initrd_dev_path.end, DEVICE_PATH_END_LENGTH);
90+
91+
efiret = BS->install_multiple_protocol_interfaces(
92+
&lf2_handle, &efi_load_file2_protocol_guid, &efi_lf2_p,
93+
&efi_device_path_protocol_guid, &initrd_dev_path, NULL);
94+
if (EFI_ERROR(efiret)) {
95+
pr_err("Failed to install protocols for INITRD %s\n",
96+
efi_strerror(efiret));
97+
ret = -efi_errno(efiret);
98+
goto out;
99+
}
100+
101+
return 0;
102+
out:
103+
BS->free_pool(efi_phys_to_virt(mem));
104+
return ret;
105+
}
106+
107+
void efi_initrd_unregister()
108+
{
109+
BS->uninstall_multiple_protocol_interfaces(
110+
lf2_handle, &efi_device_path_protocol_guid, &initrd_dev_path,
111+
&efi_load_file2_protocol_guid, &efi_lf2_p, NULL);
112+
113+
BS->free_pool(initrd_dev);
114+
initrd_dev = NULL;
115+
}

efi/payload/image.c

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -467,16 +467,24 @@ static int efi_load_ramdisk(struct efi_image_data *e)
467467
}
468468

469469
memcpy(vmem, (void *)initrd, initrd_size);
470-
471470
e->initrd_res->base = (uint64_t)mem;
472471
e->initrd_res->size = (uint64_t)initrd_size;
473-
474-
efiret = BS->install_configuration_table(&efi_linux_initrd_media_guid,
475-
(void *)e->initrd_res);
476-
if (EFI_ERROR(efiret)) {
477-
ret = -efi_errno(efiret);
478-
pr_err("Failed to install INITRD %s/n", efi_strerror(efiret));
479-
goto free_pages;
472+
473+
if (IS_ENABLED(CONFIG_EFI_INITRD_INSTALL)) {
474+
efiret = BS->install_configuration_table(&efi_linux_initrd_media_guid,
475+
(void *)e->initrd_res);
476+
if (EFI_ERROR(efiret)) {
477+
ret = -efi_errno(efiret);
478+
pr_err("Failed to install INITRD %s/n", efi_strerror(efiret));
479+
goto free_pages;
480+
}
481+
}
482+
else {
483+
ret = efi_initrd_register(vmem, initrd_size);
484+
if (ret) {
485+
pr_err("Failed to register INITRD %s/n", strerror(efiret));
486+
goto free_pages;
487+
}
480488
}
481489

482490
if (!from_fit && tmp)
@@ -496,7 +504,11 @@ static int efi_load_ramdisk(struct efi_image_data *e)
496504
}
497505

498506
static void efi_unload_ramdisk(struct efi_image_data *e) {
499-
BS->install_configuration_table(&efi_linux_initrd_media_guid, NULL);
507+
508+
if (IS_ENABLED(CONFIG_EFI_INITRD_INSTALL))
509+
BS->install_configuration_table(&efi_linux_initrd_media_guid, NULL);
510+
else
511+
efi_initrd_unregister();
500512

501513
efi_free_pages(efi_phys_to_virt(e->initrd_res->base),
502514
e->initrd_res->size);

include/efi/efi-payload.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,7 @@ int efi_set_variable_usec(char *name, efi_guid_t *vendor, uint64_t usec);
3434
void *efi_earlymem_alloc(const struct efi_system_table *sys_table,
3535
size_t *memsize, enum efi_memory_type mem_type);
3636

37+
int efi_initrd_register(void *initrd, size_t initrd_size);
38+
void efi_initrd_unregister(void);
39+
3740
#endif

0 commit comments

Comments
 (0)