Skip to content

Commit 16ec1ed

Browse files
grandpaulzhangxp1998
authored andcommitted
[lib][uefi]: add support for loading UEFI app from a FAT partition.
Modify uefi_load command to support loading UEFI app from a FAT partition. When loading without '/', it will load the UEFI app from a block device. And if loading with '/', it will treat as a path to a FAT partition. Signed-off-by: Ying-Chun Liu (PaulLiu) <paulliu@debian.org>
1 parent b300554 commit 16ec1ed

File tree

2 files changed

+108
-20
lines changed

2 files changed

+108
-20
lines changed

lib/uefi/include/uefi/uefi.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
extern "C" {
77
#endif
88

9-
int load_pe_file(const char *blkdev);
9+
int load_pe_blockdev(const char *blkdev);
10+
int load_pe_fs(const char *path);
1011

1112
#ifdef __cplusplus
1213
}
1314
#endif
1415

15-
#endif
16+
#endif

lib/uefi/uefi.cpp

Lines changed: 105 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "uefi/uefi.h"
1919

2020
#include <lib/bio.h>
21+
#include <lib/fs.h>
2122
#include <lib/heap.h>
2223
#include <lk/console_cmd.h>
2324
#include <lk/debug.h>
@@ -68,7 +69,57 @@ void fill(T *data, size_t skip, uint8_t begin = 0) {
6869

6970
static char16_t firmwareVendor[] = u"Little Kernel";
7071

71-
int load_sections_and_execute(bdev_t *dev,
72+
class ImageReader {
73+
public:
74+
virtual ssize_t read(char *buf, off_t offset, size_t len) = 0;
75+
virtual void get_name(char *buf, size_t buf_size) = 0;
76+
};
77+
78+
class ImageReaderBdev final : public ImageReader {
79+
private:
80+
bdev_t *dev;
81+
82+
public:
83+
ImageReaderBdev(bdev_t *dev1): dev(dev1) {}
84+
85+
ssize_t read(char *buf, off_t offset, size_t len) {
86+
return bio_read(dev, static_cast<void *>(buf), offset, len);
87+
}
88+
89+
void get_name(char *buf, size_t buf_size) {
90+
if (buf_size <= 0) {
91+
return;
92+
}
93+
strncpy(buf, dev->name, buf_size - 1);
94+
}
95+
};
96+
97+
class ImageReaderFilehandle final : public ImageReader {
98+
private:
99+
filehandle *file_handle;
100+
const char *path;
101+
102+
public:
103+
ImageReaderFilehandle(filehandle *file_handle1, const char *path1): file_handle(file_handle1), path(path1) {}
104+
105+
ssize_t read(char *buf, off_t offset, size_t len) {
106+
return fs_read_file(file_handle, buf, offset, len);
107+
}
108+
109+
void get_name(char *buf, size_t buf_size) {
110+
if (buf_size <= 0) {
111+
return;
112+
}
113+
strncpy(buf, path, buf_size);
114+
for (size_t i = 0; i < buf_size && buf[i]; i++) {
115+
if (buf[i] == '/') {
116+
buf[i] = '\\';
117+
}
118+
}
119+
}
120+
};
121+
122+
int load_sections_and_execute(ImageReader *reader,
72123
const IMAGE_NT_HEADERS64 *pe_header) {
73124
const auto file_header = &pe_header->FileHeader;
74125
const auto optional_header = &pe_header->OptionalHeader;
@@ -100,12 +151,13 @@ int load_sections_and_execute(bdev_t *dev,
100151
}
101152
memset(image_base, 0, virtual_size);
102153
DEFER { free_pages(image_base, virtual_size / PAGE_SIZE); };
103-
bio_read(dev, image_base, 0, section_header[0].PointerToRawData);
154+
reader->read(image_base, 0, section_header[0].PointerToRawData);
104155

105156
for (size_t i = 0; i < sections; i++) {
106157
const auto &section = section_header[i];
107-
bio_read(dev, image_base + section.VirtualAddress, section.PointerToRawData,
108-
section.SizeOfRawData);
158+
reader->read(image_base + section.VirtualAddress,
159+
section.PointerToRawData,
160+
section.SizeOfRawData);
109161
}
110162
printf("Relocating image from 0x%llx to %p\n", optional_header->ImageBase,
111163
image_base);
@@ -145,7 +197,9 @@ int load_sections_and_execute(bdev_t *dev,
145197
printf("efi_initialize_system_table_pointer failed: %lu\n", status);
146198
return -static_cast<int>(status);
147199
}
148-
setup_debug_support(table, image_base, virtual_size, dev);
200+
char path[FS_MAX_PATH_LEN];
201+
reader->get_name(path, sizeof(path));
202+
setup_debug_support(table, image_base, virtual_size, path);
149203

150204
constexpr size_t kStackSize = 1 * 1024ul * 1024;
151205
auto stack = reinterpret_cast<char *>(alloc_page(kStackSize, 23));
@@ -168,7 +222,11 @@ int cmd_uefi_load(int argc, const console_cmd_args *argv) {
168222
printf("Usage: %s <name of block device to load from>\n", argv[0].str);
169223
return 1;
170224
}
171-
load_pe_file(argv[1].str);
225+
if (argv[1].str[0] == '/') {
226+
load_pe_fs(argv[1].str);
227+
} else {
228+
load_pe_blockdev(argv[1].str);
229+
}
172230
return 0;
173231
}
174232

@@ -201,21 +259,12 @@ STATIC_COMMAND_END(uefi);
201259

202260
} // namespace
203261

204-
int load_pe_file(const char *blkdev) {
205-
bdev_t *dev = bio_open(blkdev);
206-
if (!dev) {
207-
printf("error opening block device %s\n", blkdev);
208-
return -1;
209-
}
210-
DEFER {
211-
bio_close(dev);
212-
dev = nullptr;
213-
};
262+
int load_pe_file(ImageReader *reader) {
214263
constexpr size_t kBlocKSize = 4096;
215264

216265
lk_time_t t = current_time();
217266
uint8_t *address = static_cast<uint8_t *>(malloc(kBlocKSize));
218-
ssize_t err = bio_read(dev, static_cast<void *>(address), 0, kBlocKSize);
267+
ssize_t err = reader->read(reinterpret_cast<char *>(address), 0, kBlocKSize);
219268
t = current_time() - t;
220269
dprintf(INFO, "bio_read returns %d, took %u msecs (%d bytes/sec)\n", (int)err,
221270
(uint)t, (uint32_t)((uint64_t)err * 1000 / t));
@@ -253,7 +302,45 @@ int load_pe_file(const char *blkdev) {
253302
ToString(optional_header->Subsystem));
254303
}
255304
printf("Valid UEFI application found.\n");
256-
auto ret = load_sections_and_execute(dev, pe_header);
305+
auto ret = load_sections_and_execute(reader, pe_header);
257306
printf("UEFI Application return code: %d\n", ret);
258307
return ret;
259308
}
309+
310+
int load_pe_blockdev(const char *blkdev) {
311+
bdev_t *dev = bio_open(blkdev);
312+
313+
if (!dev) {
314+
printf("error opening block device %s\n", blkdev);
315+
return -1;
316+
}
317+
318+
DEFER {
319+
bio_close(dev);
320+
dev = nullptr;
321+
};
322+
323+
ImageReaderBdev reader(dev);
324+
325+
return load_pe_file(&reader);
326+
}
327+
328+
int load_pe_fs(const char *path) {
329+
filehandle *file_handle = nullptr;
330+
331+
status_t status = fs_open_file(path, &file_handle);
332+
if (status < 0) {
333+
printf("error opening file %s\n", path);
334+
return -1;
335+
}
336+
337+
DEFER {
338+
fs_close_file(file_handle);
339+
file_handle = nullptr;
340+
};
341+
342+
ImageReaderFilehandle reader(file_handle, path);
343+
344+
return load_pe_file(&reader);
345+
346+
}

0 commit comments

Comments
 (0)