Skip to content

Commit 6f7e843

Browse files
committed
Add dtbhack.efi - a tiny app to install and patch dtb
1 parent 17a52a1 commit 6f7e843

8 files changed

Lines changed: 473 additions & 17 deletions

File tree

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
[submodule "external/arm64-sysreg-lib"]
55
path = external/arm64-sysreg-lib
66
url = https://github.com/ashwio/arm64-sysreg-lib.git
7+
[submodule "external/dtc"]
8+
path = external/dtc
9+
url = https://git.kernel.org/pub/scm/utils/dtc/dtc.git

Makefile

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ OUT_DIR := $(CURDIR)/out
1414
GNUEFI_DIR = $(CURDIR)/external/gnu-efi
1515
GNUEFI_OUT = $(GNUEFI_DIR)/$(ARCH)
1616

17+
LIBFDT_INC = $(CURDIR)/external/dtc/libfdt/
1718
SYSREG_INC = $(CURDIR)/external/arm64-sysreg-lib/include
1819

1920
CFLAGS += \
2021
-I$(GNUEFI_DIR)/inc/ -I$(GNUEFI_DIR)/inc/$(ARCH) -I$(GNUEFI_DIR)/inc/protocol \
21-
-I$(SYSREG_INC) \
22+
-I$(SYSREG_INC) -I$(LIBFDT_INC) -Isrc/include \
2223
-fpic -fshort-wchar -fno-stack-protector -ffreestanding \
2324
-DCONFIG_$(ARCH) -D__MAKEWITH_GNUEFI -DGNU_EFI_USE_MS_ABI \
2425
-mstrict-align
@@ -38,30 +39,46 @@ LIBEFI_A := $(GNUEFI_OUT)/lib/libefi.a
3839
LIBGNUEFI_A := $(GNUEFI_OUT)/gnuefi/libgnuefi.a
3940
CRT0_O := $(GNUEFI_OUT)/gnuefi/crt0-efi-$(ARCH).o
4041

42+
LIBFDT_OBJS := \
43+
$(OUT_DIR)/external/dtc/libfdt/fdt.o \
44+
$(OUT_DIR)/external/dtc/libfdt/fdt_ro.o \
45+
$(OUT_DIR)/external/dtc/libfdt/fdt_wip.o \
46+
$(OUT_DIR)/external/dtc/libfdt/fdt_sw.o \
47+
$(OUT_DIR)/external/dtc/libfdt/fdt_rw.o \
48+
$(OUT_DIR)/external/dtc/libfdt/fdt_empty_tree.o \
49+
$(OUT_DIR)/external/dtc/libfdt/fdt_addresses.o \
50+
$(OUT_DIR)/external/dtc/libfdt/fdt_check.o \
51+
52+
DTBHACK_LDFLAGS := \
53+
-Wl,--defsym=EFI_SUBSYSTEM=$(SUBSYSTEM_APP)
54+
55+
DTBHACK_OBJS := \
56+
$(OUT_DIR)/src/dtbhack_main.o \
57+
$(OUT_DIR)/src/util.o \
58+
$(OUT_DIR)/src/libc.o \
59+
$(LIBFDT_OBJS)
60+
4161
SLTEST_LDFLAGS := \
4262
-Wl,--defsym=EFI_SUBSYSTEM=$(SUBSYSTEM_APP)
4363

4464
SLTEST_OBJS := \
45-
$(OUT_DIR)/test_main.o \
46-
$(OUT_DIR)/util.o \
47-
$(OUT_DIR)/arch.o \
48-
$(OUT_DIR)/sl.o \
49-
$(OUT_DIR)/trans.o \
65+
$(OUT_DIR)/src/test_main.o \
66+
$(OUT_DIR)/src/util.o \
67+
$(OUT_DIR)/src/arch.o \
68+
$(OUT_DIR)/src/sl.o \
69+
$(OUT_DIR)/src/trans.o \
5070

5171
SLBOUNCE_LDFLAGS := \
5272
-Wl,--defsym=EFI_SUBSYSTEM=$(SUBSYSTEM_RT)
5373

5474
SLBOUNCE_OBJS := \
55-
$(OUT_DIR)/bounce_main.o \
56-
$(OUT_DIR)/util.o \
57-
$(OUT_DIR)/arch.o \
58-
$(OUT_DIR)/sl.o \
59-
$(OUT_DIR)/trans.o \
75+
$(OUT_DIR)/src/bounce_main.o \
76+
$(OUT_DIR)/src/util.o \
77+
$(OUT_DIR)/src/arch.o \
78+
$(OUT_DIR)/src/sl.o \
79+
$(OUT_DIR)/src/trans.o \
6080

61-
all: $(OUT_DIR) $(LIBEFI_A) $(LIBGNUEFI_A) $(OUT_DIR)/sltest.efi $(OUT_DIR)/slbounce.efi
62-
63-
$(OUT_DIR):
64-
mkdir $@
81+
all: $(LIBEFI_A) $(LIBGNUEFI_A) $(OUT_DIR)/sltest.efi $(OUT_DIR)/slbounce.efi $(OUT_DIR)/dtbhack.efi
6582

6683
$(LIBEFI_A):
6784
@echo [ DEP ] $@
@@ -83,17 +100,23 @@ $(OUT_DIR)/slbounce.so: $(SLBOUNCE_OBJS)
83100
@echo [ LD ] $$(basename $@)
84101
@$(CC) $(SLBOUNCE_LDFLAGS) $(LDFLAGS) $(CRT0_O) $^ -o $@ $(LIBS)
85102

103+
$(OUT_DIR)/dtbhack.so: $(DTBHACK_OBJS)
104+
@echo [ LD ] $$(basename $@)
105+
@$(CC) $(DTBHACK_LDFLAGS) $(LDFLAGS) $(CRT0_O) $^ -o $@ $(LIBS)
106+
86107
$(OUT_DIR)/%.efi: $(OUT_DIR)/%.so
87108
@echo [ CPY ] $$(basename $@)
88109
@$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel* \
89110
-j .rela* -j .reloc -j .eh_frame -O binary $< $@
90111

91-
$(OUT_DIR)/%.o: src/%.c
112+
$(OUT_DIR)/%.o: %.c
92113
@echo [ CC ] $$(basename $@)
114+
@mkdir -p $(dir $@)
93115
@$(CC) $(CFLAGS) -c $< -o $@
94116

95-
$(OUT_DIR)/%.o: src/%.s
117+
$(OUT_DIR)/%.o: %.s
96118
@echo [ ASM ] $$(basename $@)
119+
@mkdir -p $(dir $@)
97120
@$(AS) -c $< -o $@
98121

99122
.PHONY: clean

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ with anything else...
1313
Usage
1414
-----
1515

16+
### sltest.efi
17+
1618
To test that slbounce can work on your device, run `sltest.efi` with an absolute path to
1719
your `tcblaunch.exe` file. (Get that file from your Windows distribution). `sltest.efi`
1820
will immediately try switching to EL2 and issue PSCI power off command right after. If
@@ -23,6 +25,8 @@ If your device reboots or hangs, there is some issue and SL was not successful.
2325
fs0:\> sltest.efi path\to\tcblaunch.exe
2426
```
2527

28+
### slbounce.efi
29+
2630
To actually boot an OS with Secure-Launch switch to EL2, you can use `slbounce.efi`.
2731

2832
> [!CAUTION]
@@ -43,6 +47,33 @@ EBS.
4347

4448
If Secure-Launch fails at that point, the device will likely hang or reboot.
4549

50+
Unfortunately due to many firmware-spefic quirks implemented in Linux, it's not as simple
51+
as just booting your OS in EL2 after the SL happened. One would need to preform some
52+
changes to how Linux boots in order to not crash trying to talk to now non-existent
53+
hyp firmware.
54+
55+
### dtbhack.efi
56+
57+
Even though "Making Linux work" is out of scope for this project, since Linux is likely
58+
the most interesting software to run in EL2 on those devices, a quick hack is supplied
59+
in this repo to help with initial testing and bring-up.
60+
61+
`dtbhack.efi` is a very simple app that installs your device DTB into the UEFI system
62+
table and performs minimal (seemingly) necesary hacks to workaround some booting issues.
63+
64+
These include:
65+
66+
- Making a copy of cmd-db data
67+
- Removing zap-shader node
68+
69+
To use it, do:
70+
```
71+
fs0:\> dtbhack.efi path\to\your.dtb
72+
```
73+
74+
Please note that this will not fix every issue but only attempts to work around the most
75+
boot-critical ones.
76+
4677
Build
4778
-----
4879

external/dtc

Submodule dtc added at 3fbfdd0

src/dtbhack_main.c

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
/* Copyright (c) 2024 Nikita Travkin <nikita@trvn.ru> */
3+
4+
#include <stdint.h>
5+
6+
#define EFI_DEBUG 1
7+
8+
#include <efi.h>
9+
#include <efilib.h>
10+
#include <efidebug.h>
11+
12+
#include <libfdt.h>
13+
14+
#include "util.h"
15+
16+
static EFI_STATUS dtbhack_cmd_db_relocation(UINT8 *dtb)
17+
{
18+
EFI_STATUS status;
19+
uint32_t offset;
20+
int ret;
21+
22+
offset = fdt_node_offset_by_compatible(dtb, 0, "qcom,cmd-db");
23+
if (offset <= 0) {
24+
Print(L"Failed to find cmd-db node: %d\n", offset);
25+
return EFI_UNSUPPORTED;
26+
}
27+
28+
const fdt32_t *cmd_db_reg = fdt_getprop(dtb, offset, "reg", &ret);
29+
ASSERT(ret == 4 * 4);
30+
31+
uint64_t cmd_db_base = ((uint64_t)fdt32_to_cpu(cmd_db_reg[0]) << 32) | fdt32_to_cpu(cmd_db_reg[1]);
32+
uint64_t cmd_db_size = ((uint64_t)fdt32_to_cpu(cmd_db_reg[2]) << 32) | fdt32_to_cpu(cmd_db_reg[3]);
33+
ASSERT(cmd_db_base);
34+
ASSERT(cmd_db_size);
35+
36+
ret = fdt_nop_property(dtb, offset, "compatible");
37+
ASSERT(ret >= 0);
38+
39+
EFI_PHYSICAL_ADDRESS cmddb_phys = 0;
40+
UINT64 cmddb_pages = cmd_db_size / 4096 + 1;
41+
42+
status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiReservedMemoryType, cmddb_pages, &cmddb_phys);
43+
if (EFI_ERROR(status)) {
44+
Print(L"Failed to allocate memory: %d\n", status);
45+
return status;
46+
}
47+
Print(L"Relocating cmd-db: reg=0x%llx size=0x%llx new_addr=0x%llx\n", cmd_db_base, cmd_db_size, cmddb_phys);
48+
49+
CopyMem((UINT8*)cmddb_phys, (UINT8*)cmd_db_base, cmd_db_size);
50+
51+
int resmem_offset = fdt_path_offset(dtb, "/reserved-memory");
52+
if (resmem_offset <= 0)
53+
goto error_allocated;
54+
55+
offset = fdt_add_subnode(dtb, resmem_offset, "cmd-db-copy");
56+
if (offset <= 0)
57+
goto error_allocated;
58+
59+
ret = fdt_setprop_string(dtb, offset, "compatible", "qcom,cmd-db");
60+
if (ret)
61+
goto error_allocated;
62+
63+
ret = fdt_appendprop_addrrange(dtb, resmem_offset, offset, "reg", cmddb_phys, cmd_db_size);
64+
if (ret)
65+
goto error_allocated;
66+
67+
ret = fdt_setprop_empty(dtb, offset, "no-map");
68+
if (ret)
69+
goto error_allocated;
70+
71+
return EFI_SUCCESS;
72+
73+
error_allocated:
74+
uefi_call_wrapper(BS->FreePages, 2, cmddb_phys, cmddb_pages);
75+
return EFI_UNSUPPORTED;
76+
}
77+
78+
static EFI_STATUS dtbhack_zap_zap_shader(UINT8 *dtb)
79+
{
80+
uint32_t offset;
81+
int ret;
82+
83+
offset = fdt_node_offset_by_compatible(dtb, 0, "qcom,adreno");
84+
if (offset <= 0) {
85+
Print(L"Failed to find adreno node: %d\n", offset);
86+
return EFI_UNSUPPORTED;
87+
}
88+
89+
offset = fdt_subnode_offset(dtb, offset, "zap-shader");
90+
if (offset <= 0) {
91+
Print(L"Failed to find gpu/zap-shader node: %d\n", offset);
92+
return EFI_UNSUPPORTED;
93+
}
94+
95+
ret = fdt_nop_node(dtb, offset);
96+
if (ret) {
97+
Print(L"Failed to nop gpu/zap-shader node: %d\n", ret);
98+
return EFI_UNSUPPORTED;
99+
}
100+
101+
return EFI_SUCCESS;
102+
}
103+
104+
#define EFI_DTB_TABLE_GUID \
105+
{ 0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0} }
106+
107+
EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
108+
{
109+
CHAR16 **argv;
110+
INTN argc;
111+
EFI_STATUS status;
112+
int ret;
113+
114+
InitializeLib(ImageHandle, SystemTable);
115+
argc = GetShellArgcArgv(ImageHandle, &argv);
116+
117+
Print(L"DTB-Hack\n");
118+
119+
if (argc != 2) {
120+
Print(L"Usage: dtbhack.efi DTB\n\n");
121+
return EFI_INVALID_PARAMETER;
122+
}
123+
124+
CHAR16 *dtb_name = argv[1];
125+
126+
Print(L"Installing DTB: %s\n", dtb_name);
127+
128+
EFI_FILE_HANDLE volume = GetVolume(ImageHandle);
129+
if (!volume) {
130+
Print(L"Cant open volume\n");
131+
return EFI_INVALID_PARAMETER;
132+
}
133+
134+
EFI_FILE_HANDLE dtb_file = FileOpen(volume, dtb_name);
135+
if (!dtb_file) {
136+
Print(L"Cant open the file\n");
137+
return EFI_INVALID_PARAMETER;
138+
}
139+
140+
EFI_PHYSICAL_ADDRESS dtb_phys;
141+
UINT64 dtb_max_sz = 1 * 1024 * 1024;
142+
UINT64 dtb_pages = dtb_max_sz / 4096;
143+
144+
/* The spec mandates using "ACPI" memory type for any configuration tables like dtb */
145+
status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateAnyPages, EfiACPIReclaimMemory, dtb_pages, &dtb_phys);
146+
if (EFI_ERROR(status)) {
147+
Print(L"Failed to allocate memory: %d\n", status);
148+
return status;
149+
}
150+
151+
UINT8 *dtb = (UINT8 *)(dtb_phys);
152+
UINT64 dtb_sz = FileSize(dtb_file);
153+
154+
if (dtb_sz > 1 * 1024 * 1024) {
155+
Print(L"File too big!\n");
156+
status = EFI_BUFFER_TOO_SMALL;
157+
goto error_allocated;
158+
}
159+
160+
FileRead(dtb_file, dtb, dtb_sz);
161+
162+
/*
163+
* Now we need to update the DTB to make it usable.
164+
*/
165+
166+
ret = fdt_check_header(dtb);
167+
if (ret) {
168+
Print(L"fdt header check failed: %d\n", ret);
169+
status = EFI_LOAD_ERROR;
170+
goto error_allocated;
171+
}
172+
173+
ret = fdt_open_into(dtb, dtb, dtb_max_sz);
174+
if (ret) {
175+
Print(L"fdt open failed: %d\n", ret);
176+
status = EFI_LOAD_ERROR;
177+
goto error_allocated;
178+
}
179+
180+
/*
181+
* cmd-db memory is for some reason "broken" after switching to el2.
182+
* Let's make a copy in another place for fun and give linux that.
183+
*/
184+
status = dtbhack_cmd_db_relocation(dtb);
185+
if (EFI_ERROR(status)) {
186+
Print(L"Failed to relocate cmd-db: %d\n", status);
187+
goto error_allocated;
188+
}
189+
190+
/*
191+
* Since we are going to run in EL2, the hyp that would protect zap
192+
* shader is gone. We also seem to be able to just ignore it in EL2
193+
* since we now have the access to the needed registers.
194+
*/
195+
status = dtbhack_zap_zap_shader(dtb);
196+
if (EFI_ERROR(status)) {
197+
Print(L"Failed to nop-out zap shader: %d\n", status);
198+
goto error_allocated;
199+
}
200+
201+
ret = fdt_pack(dtb);
202+
if (ret) {
203+
Print(L"fdt pack failed: %d\n", ret);
204+
status = EFI_LOAD_ERROR;
205+
goto error_allocated;
206+
}
207+
208+
/*
209+
* Finally, we need to install the dtb into a UEFI table so
210+
* the OS can find it.
211+
*/
212+
213+
EFI_GUID EfiDtbTableGuid = EFI_DTB_TABLE_GUID;
214+
215+
status = uefi_call_wrapper(BS->InstallConfigurationTable, 2, &EfiDtbTableGuid, dtb);
216+
if (EFI_ERROR(status)) {
217+
Print(L"Failed to install dtb: %d\n", status);
218+
goto error_allocated;
219+
}
220+
221+
Print(L"The DTB configuration table was installed!\n");
222+
223+
return EFI_SUCCESS;
224+
225+
error_allocated:
226+
uefi_call_wrapper(BS->FreePages, 2, dtb_phys, dtb_pages);
227+
return ret;
228+
}
229+

src/include/stdlib.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef STDLIB_H
2+
#define STDLIB_H
3+
4+
5+
6+
#endif

0 commit comments

Comments
 (0)