summaryrefslogtreecommitdiffstats
path: root/pad_for_optiplex.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--pad_for_optiplex.py69
1 files changed, 69 insertions, 0 deletions
diff --git a/pad_for_optiplex.py b/pad_for_optiplex.py
new file mode 100644
index 0000000..2d48552
--- /dev/null
+++ b/pad_for_optiplex.py
@@ -0,0 +1,69 @@
1#!/usr/bin/env python3
2"""pad_for_optiplex.py — pad a UEFI bootloader PE for Optiplex 7010
3
4The Optiplex 7010 AMI Aptio firmware rejects PEs smaller than ~160KB
5("no bootable devices"). This pads the PE to match systemd-boot's size
6and sets SizeOfImage accordingly.
7"""
8
9import struct, sys, os
10
11def pad(path):
12 try:
13 with open(path, 'rb') as f:
14 d = bytearray(f.read())
15 except IOError as e:
16 print(f" ERROR: cannot read {path}: {e}")
17 return False
18
19 po = struct.unpack('<I', d[0x3C:0x40])[0]
20 if d[po:po+4] != b'PE\x00\x00':
21 print(f" Not a PE file")
22 return False
23
24 opt = po + 24
25
26 # Target size: 160256 bytes (matching systemd-boot)
27 target = 160256
28 if len(d) >= target:
29 print(f" Already >= {target} bytes ({len(d)}), nothing to do")
30 return True
31
32 # Compute SizeOfImage: round current SizeOfImage to match file growth
33 cur_si = struct.unpack('<I', d[opt+56:opt+60])[0]
34 cur_file_size = len(d)
35
36 # The file is padded after all sections. SizeOfImage is the highest
37 # RVA + virtual size, rounded up to SectionAlignment. After padding
38 # the file, we need to increase SizeOfImage so the firmware sees a
39 # consistent image.
40 #
41 # Simple approach: set SizeOfImage = target - file_delta + old_si
42 # Actually: SizeOfImage already covers our sections at up to ~0x4000.
43 # We just need to make it large enough for the padded region.
44 # Use systemd-boot's SizeOfImage = 0x2d000 as reference.
45 file_growth = target - len(d)
46 new_si = ((cur_si + file_growth + 0xfff) // 0x1000) * 0x1000
47
48 # Pad the file
49 d += b'\x00' * file_growth
50
51 # Update SizeOfImage in optional header
52 struct.pack_into('<I', d, opt+56, new_si)
53
54 try:
55 with open(path, 'wb') as f:
56 f.write(d)
57 except IOError as e:
58 print(f" ERROR: cannot write {path}: {e}")
59 return False
60
61 print(f" Padded: {len(d)} bytes (was {cur_file_size}), SizeOfImage = {new_si:#x}")
62 return True
63
64if __name__ == '__main__':
65 if len(sys.argv) < 2:
66 print(f"Usage: {sys.argv[0]} <pe-path>")
67 sys.exit(1)
68 if not pad(sys.argv[1]):
69 sys.exit(1)