]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/drivers.c
Merge pull request #20894 from andir/editorconfig
[thirdparty/systemd.git] / src / boot / efi / drivers.c
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
9 static VOID efi_unload_image(EFI_HANDLE *h) {
10 if (*h)
11 (VOID) uefi_call_wrapper(BS->UnloadImage, 1, *h);
12 }
13
14 static EFI_STATUS load_one_driver(
15 EFI_HANDLE parent_image,
16 EFI_LOADED_IMAGE *loaded_image,
17 const CHAR16 *fname) {
18
19 _cleanup_(efi_unload_image) EFI_HANDLE image = NULL;
20 _cleanup_freepool_ EFI_DEVICE_PATH *path = NULL;
21 _cleanup_freepool_ CHAR16 *spath = NULL;
22 EFI_STATUS err;
23
24 assert(parent_image);
25 assert(loaded_image);
26 assert(fname);
27
28 spath = PoolPrint(L"\\EFI\\systemd\\drivers\\%s", fname);
29 if (!spath)
30 return log_oom();
31
32 path = FileDevicePath(loaded_image->DeviceHandle, spath);
33 if (!path)
34 return log_oom();
35
36 err = uefi_call_wrapper(
37 BS->LoadImage, 6,
38 FALSE,
39 parent_image,
40 path,
41 NULL, 0,
42 &image);
43 if (EFI_ERROR(err))
44 return log_error_status_stall(err, L"Failed to load image %s: %r", fname, err);
45
46 err = uefi_call_wrapper(
47 BS->HandleProtocol, 3,
48 image,
49 &LoadedImageProtocol,
50 (VOID **)&loaded_image);
51 if (EFI_ERROR(err))
52 return log_error_status_stall(err, L"Failed to find protocol in driver image s: %r", fname, err);
53
54 if (loaded_image->ImageCodeType != EfiBootServicesCode &&
55 loaded_image->ImageCodeType != EfiRuntimeServicesCode)
56 return log_error_status_stall(EFI_INVALID_PARAMETER, L"Image %s is not a driver, refusing: %r", fname);
57
58 err = uefi_call_wrapper(
59 BS->StartImage, 3,
60 image,
61 NULL,
62 NULL);
63 if (EFI_ERROR(err))
64 return log_error_status_stall(err, L"Failed to start image %s: %r", fname, err);
65
66 TAKE_PTR(image);
67 return EFI_SUCCESS;
68 }
69
70 static EFI_STATUS reconnect(VOID) {
71 _cleanup_freepool_ EFI_HANDLE *handles = NULL;
72 UINTN n_handles = 0;
73 EFI_STATUS err;
74
75 /* Reconnects all handles, so that any loaded drivers can take effect. */
76
77 err = uefi_call_wrapper(
78 BS->LocateHandleBuffer, 5,
79 AllHandles,
80 NULL,
81 NULL,
82 &n_handles,
83 &handles);
84 if (EFI_ERROR(err))
85 return log_error_status_stall(err, L"Failed to get list of handles: %r", err);
86
87 for (UINTN i = 0; i < n_handles; i++) {
88 err = uefi_call_wrapper(
89 BS->ConnectController, 4,
90 handles[i],
91 NULL,
92 NULL,
93 TRUE);
94 if (err == EFI_NOT_FOUND) /* No drivers for this handle */
95 continue;
96 if (EFI_ERROR(err))
97 log_error_status_stall(err, L"Failed to reconnect handle %u, ignoring: %r", i, err);
98 }
99
100 return EFI_SUCCESS;
101 }
102
103 EFI_STATUS load_drivers(
104 EFI_HANDLE parent_image,
105 EFI_LOADED_IMAGE *loaded_image,
106 EFI_FILE_HANDLE root_dir) {
107
108 _cleanup_(FileHandleClosep) EFI_FILE_HANDLE drivers_dir = NULL;
109 _cleanup_freepool_ EFI_FILE_INFO *dirent = NULL;
110 _cleanup_freepool_ EFI_DEVICE_PATH *path = NULL;
111 UINTN dirent_size = 0, n_succeeded = 0;
112 EFI_STATUS err;
113
114 err = open_directory(
115 root_dir,
116 L"\\EFI\\systemd\\drivers",
117 &drivers_dir);
118 if (err == EFI_NOT_FOUND)
119 return EFI_SUCCESS;
120 if (EFI_ERROR(err))
121 return log_error_status_stall(err, L"Failed to open \\EFI\\systemd\\drivers: %r", err);
122
123 for (;;) {
124 _cleanup_freepool_ CHAR16 *d = NULL;
125
126 err = readdir_harder(drivers_dir, &dirent, &dirent_size);
127 if (EFI_ERROR(err))
128 return log_error_status_stall(err, L"Failed to read extra directory of loaded image: %r", err);
129 if (!dirent) /* End of directory */
130 break;
131
132 if (dirent->FileName[0] == '.')
133 continue;
134 if (dirent->Attribute & EFI_FILE_DIRECTORY)
135 continue;
136 if (!endswith_no_case(dirent->FileName, EFI_MACHINE_TYPE_NAME L".efi"))
137 continue;
138
139 err = load_one_driver(parent_image, loaded_image, dirent->FileName);
140 if (EFI_ERROR(err))
141 continue;
142
143 n_succeeded++;
144 }
145
146 if (n_succeeded > 0)
147 (VOID) reconnect();
148
149 return EFI_SUCCESS;
150 }