]>
Commit | Line | Data |
---|---|---|
a65627a8 TL |
1 | #!/usr/bin/env python3 |
2 | # | |
3 | # Copyright 2021 Canonical Ltd. | |
4 | # Authors: | |
5 | # - dann frazier <dann.frazier@canonical.com> | |
6 | # | |
7 | # This program is free software: you can redistribute it and/or modify it | |
8 | # under the terms of the GNU General Public License version 3, as published | |
9 | # by the Free Software Foundation. | |
10 | # | |
11 | # This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | # ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | |
13 | # SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | # General Public License for more details. | |
15 | # | |
16 | # You should have received a copy of the GNU General Public License along with | |
17 | # this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | # | |
19 | ||
20 | import argparse | |
21 | import os.path | |
22 | import pexpect | |
23 | import shutil | |
24 | import sys | |
25 | from UEFI.Filesystems import FatFsImage, EfiBootableIsoImage | |
26 | from UEFI.Qemu import QemuEfiMachine, QemuEfiVariant, QemuEfiFlashSize | |
27 | from UEFI import Qemu | |
28 | ||
29 | if __name__ == '__main__': | |
30 | parser = argparse.ArgumentParser() | |
31 | parser.add_argument( | |
32 | "-f", "--flavor", help="UEFI Flavor", | |
33 | choices=['AAVMF', 'OVMF', 'OVMF_4M'], | |
34 | required=True, | |
35 | ) | |
36 | parser.add_argument( | |
37 | "-e", "--enrolldefaultkeys", | |
38 | help='Path to "EnrollDefaultKeys" EFI binary', | |
39 | required=True, | |
40 | ) | |
41 | parser.add_argument( | |
42 | "-s", "--shell", | |
43 | help='Path to "Shell" EFI binary', | |
44 | required=True, | |
45 | ) | |
46 | parser.add_argument( | |
47 | "-C", "--certificate", | |
48 | help='base64-encoded PK/KEK1 certificate', | |
49 | required=True, | |
50 | ) | |
51 | parser.add_argument( | |
52 | "-c", "--code", | |
53 | help='UEFI code image', | |
54 | required=True, | |
55 | ) | |
dd9d3a52 TL |
56 | parser.add_argument( |
57 | "--no-default", | |
58 | action="store_true", | |
59 | help='Do not enroll the default keys, just the PK/KEK1 certificate', | |
60 | ) | |
a65627a8 TL |
61 | parser.add_argument( |
62 | "-V", "--vars-template", | |
63 | help='UEFI vars template', | |
64 | required=True, | |
65 | ) | |
66 | parser.add_argument( | |
67 | "-o", "--out-file", | |
68 | help="Output file for generated vars template", | |
69 | required=True, | |
70 | ) | |
71 | parser.add_argument("-d", "--debug", action="store_true", | |
72 | help="Emit debug messages") | |
73 | args = parser.parse_args() | |
74 | ||
75 | FlavorConfig = { | |
76 | 'AAVMF': { | |
77 | 'EfiArch': 'AA64', | |
78 | 'QemuCommand': Qemu.QemuCommand( | |
79 | QemuEfiMachine.AAVMF, | |
80 | code_path=args.code, | |
81 | vars_template_path=args.vars_template, | |
82 | ), | |
83 | }, | |
84 | 'OVMF': { | |
85 | 'EfiArch': 'X64', | |
86 | 'QemuCommand': Qemu.QemuCommand( | |
87 | QemuEfiMachine.OVMF_Q35, | |
88 | variant=QemuEfiVariant.SECBOOT, | |
89 | flash_size=QemuEfiFlashSize.SIZE_2MB, | |
90 | code_path=args.code, | |
91 | vars_template_path=args.vars_template, | |
92 | ), | |
93 | }, | |
94 | 'OVMF_4M': { | |
95 | 'EfiArch': 'X64', | |
96 | 'QemuCommand': Qemu.QemuCommand( | |
97 | QemuEfiMachine.OVMF_Q35, | |
98 | variant=QemuEfiVariant.SECBOOT, | |
99 | flash_size=QemuEfiFlashSize.SIZE_2MB, | |
100 | code_path=args.code, | |
101 | vars_template_path=args.vars_template, | |
102 | ), | |
103 | }, | |
104 | } | |
105 | ||
106 | eltorito = FatFsImage(64) | |
107 | eltorito.makedirs(os.path.join('EFI', 'BOOT')) | |
108 | removable_media_path = os.path.join( | |
109 | 'EFI', 'BOOT', f"BOOT{FlavorConfig[args.flavor]['EfiArch']}.EFI" | |
110 | ) | |
111 | eltorito.insert_file(args.shell, removable_media_path) | |
112 | eltorito.insert_file( | |
113 | args.enrolldefaultkeys, | |
114 | args.enrolldefaultkeys.split(os.path.sep)[-1] | |
115 | ) | |
116 | iso = EfiBootableIsoImage(eltorito) | |
117 | ||
118 | q = FlavorConfig[args.flavor]['QemuCommand'] | |
119 | q.add_disk(iso.path) | |
120 | q.add_oem_string(11, args.certificate) | |
121 | ||
122 | child = pexpect.spawn(' '.join(q.command)) | |
123 | if args.debug: | |
124 | child.logfile = sys.stdout.buffer | |
125 | child.expect(['Press .* or any other key to continue'], timeout=60) | |
126 | child.sendline('\x1b') | |
127 | child.expect(['Shell> ']) | |
128 | child.sendline('FS0:\r') | |
129 | child.expect(['FS0:\\\\> ']) | |
dd9d3a52 TL |
130 | enrollcmd = ['EnrollDefaultKeys.efi'] |
131 | if args.no_default: | |
132 | enrollcmd.append("--no-default") | |
133 | child.sendline(f'{" ".join(enrollcmd)}\r') | |
134 | child.expect(['FS0:\\\\> ']) | |
135 | # Clear the BootOrder. See #1015759 | |
136 | child.sendline('setvar BootOrder =\r') | |
a65627a8 TL |
137 | child.expect(['FS0:\\\\> ']) |
138 | child.sendline('reset -s\r') | |
139 | child.wait() | |
140 | shutil.copy(q.pflash.varfile_path, args.out_file) |