]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/efi/drivers.c
Merge pull request #25389 from fbuihuu/update-test-for-opensuse
[thirdparty/systemd.git] / src / boot / efi / drivers.c
CommitLineData
2553a548
LP
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <efi.h>
4#include <efilib.h>
5
6#include "drivers.h"
7#include "util.h"
8
2553a548
LP
9static EFI_STATUS load_one_driver(
10 EFI_HANDLE parent_image,
b30a43df 11 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
3639d1b0 12 const char16_t *fname) {
2553a548 13
f386daa0 14 _cleanup_(unload_imagep) EFI_HANDLE image = NULL;
93521e55 15 _cleanup_free_ EFI_DEVICE_PATH *path = NULL;
3639d1b0 16 _cleanup_free_ char16_t *spath = NULL;
2553a548
LP
17 EFI_STATUS err;
18
19 assert(parent_image);
20 assert(loaded_image);
21 assert(fname);
22
0a15a824 23 spath = xpool_print(L"\\EFI\\systemd\\drivers\\%s", fname);
79a2b916
JJ
24 err = make_file_device_path(loaded_image->DeviceHandle, spath, &path);
25 if (err != EFI_SUCCESS)
26 return log_error_status_stall(err, L"Error making file device path: %r", err);
2553a548 27
e5a1b8f9 28 err = BS->LoadImage(false, parent_image, path, NULL, 0, &image);
2a5e4fe4 29 if (err != EFI_SUCCESS)
2553a548
LP
30 return log_error_status_stall(err, L"Failed to load image %s: %r", fname, err);
31
12f32748 32 err = BS->HandleProtocol(image, &LoadedImageProtocol, (void **)&loaded_image);
2a5e4fe4 33 if (err != EFI_SUCCESS)
ce5e7872 34 return log_error_status_stall(err, L"Failed to find protocol in driver image %s: %r", fname, err);
2553a548
LP
35
36 if (loaded_image->ImageCodeType != EfiBootServicesCode &&
37 loaded_image->ImageCodeType != EfiRuntimeServicesCode)
ce5e7872 38 return log_error_status_stall(EFI_INVALID_PARAMETER, L"Image %s is not a driver, refusing.", fname);
2553a548 39
12f32748 40 err = BS->StartImage(image, NULL, NULL);
2a5e4fe4 41 if (err != EFI_SUCCESS) {
8fb16fee
JJ
42 /* EFI_ABORTED signals an initializing driver. It uses this error code on success
43 * so that it is unloaded after. */
44 if (err != EFI_ABORTED)
45 log_error_stall(L"Failed to start image %s: %r", fname, err);
46 return err;
47 }
2553a548
LP
48
49 TAKE_PTR(image);
50 return EFI_SUCCESS;
51}
52
5b3e33c2 53EFI_STATUS reconnect_all_drivers(void) {
98ac5192
JJ
54 _cleanup_free_ EFI_HANDLE *handles = NULL;
55 size_t n_handles = 0;
56 EFI_STATUS err;
2553a548 57
98ac5192 58 /* Reconnects all handles, so that any loaded drivers can take effect. */
2553a548 59
98ac5192
JJ
60 err = BS->LocateHandleBuffer(AllHandles, NULL, NULL, &n_handles, &handles);
61 if (err != EFI_SUCCESS)
62 return log_error_status_stall(err, L"Failed to get list of handles: %r", err);
2553a548 63
98ac5192
JJ
64 for (size_t i = 0; i < n_handles; i++)
65 /* Some firmware gives us some bogus handles (or they might become bad due to
66 * reconnecting everything). Security policy may also prevent us from doing so too.
67 * There is nothing we can realistically do on errors anyways, so just ignore them. */
68 (void) BS->ConnectController(handles[i], NULL, NULL, true);
2553a548 69
98ac5192 70 return EFI_SUCCESS;
2553a548
LP
71}
72
73EFI_STATUS load_drivers(
74 EFI_HANDLE parent_image,
b30a43df 75 EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
85eb489e 76 EFI_FILE *root_dir) {
2553a548 77
85eb489e 78 _cleanup_(file_closep) EFI_FILE *drivers_dir = NULL;
93521e55 79 _cleanup_free_ EFI_FILE_INFO *dirent = NULL;
2553a548
LP
80 UINTN dirent_size = 0, n_succeeded = 0;
81 EFI_STATUS err;
82
83 err = open_directory(
84 root_dir,
85 L"\\EFI\\systemd\\drivers",
86 &drivers_dir);
87 if (err == EFI_NOT_FOUND)
88 return EFI_SUCCESS;
2a5e4fe4 89 if (err != EFI_SUCCESS)
2553a548
LP
90 return log_error_status_stall(err, L"Failed to open \\EFI\\systemd\\drivers: %r", err);
91
92 for (;;) {
2553a548 93 err = readdir_harder(drivers_dir, &dirent, &dirent_size);
2a5e4fe4 94 if (err != EFI_SUCCESS)
2553a548
LP
95 return log_error_status_stall(err, L"Failed to read extra directory of loaded image: %r", err);
96 if (!dirent) /* End of directory */
97 break;
98
99 if (dirent->FileName[0] == '.')
100 continue;
785b5fcf 101 if (FLAGS_SET(dirent->Attribute, EFI_FILE_DIRECTORY))
2553a548
LP
102 continue;
103 if (!endswith_no_case(dirent->FileName, EFI_MACHINE_TYPE_NAME L".efi"))
104 continue;
105
106 err = load_one_driver(parent_image, loaded_image, dirent->FileName);
2a5e4fe4 107 if (err != EFI_SUCCESS)
2553a548
LP
108 continue;
109
110 n_succeeded++;
111 }
112
113 if (n_succeeded > 0)
5b3e33c2 114 (void) reconnect_all_drivers();
2553a548
LP
115
116 return EFI_SUCCESS;
117}