]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_vhd.c
fed05e7ed5839ebe93507159d9720f6b8cf3f859
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy_vhd.c
1 /******************************************************************************
2 * ventoy_vhd.c
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY 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
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <grub/types.h>
22 #include <grub/misc.h>
23 #include <grub/mm.h>
24 #include <grub/err.h>
25 #include <grub/dl.h>
26 #include <grub/disk.h>
27 #include <grub/device.h>
28 #include <grub/term.h>
29 #include <grub/partition.h>
30 #include <grub/file.h>
31 #include <grub/normal.h>
32 #include <grub/extcmd.h>
33 #include <grub/datetime.h>
34 #include <grub/i18n.h>
35 #include <grub/net.h>
36 #include <grub/time.h>
37 #include <grub/crypto.h>
38 #include <grub/charset.h>
39 #ifdef GRUB_MACHINE_EFI
40 #include <grub/efi/efi.h>
41 #endif
42 #include <grub/ventoy.h>
43 #include "ventoy_def.h"
44
45 GRUB_MOD_LICENSE ("GPLv3+");
46
47 static int g_vhdboot_bcd_offset = 0;
48 static int g_vhdboot_bcd_len = 0;
49 static int g_vhdboot_isolen = 0;
50 static char *g_vhdboot_totbuf = NULL;
51 static char *g_vhdboot_isobuf = NULL;
52
53 static int ventoy_vhd_find_bcd(int *bcdoffset, int *bcdlen)
54 {
55 grub_uint32_t offset;
56 grub_file_t file;
57 char cmdbuf[128];
58
59 grub_snprintf(cmdbuf, sizeof(cmdbuf), "loopback vhdiso mem:0x%lx:size:%d", (ulong)g_vhdboot_isobuf, g_vhdboot_isolen);
60
61 grub_script_execute_sourcecode(cmdbuf);
62
63 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(vhdiso)/boot/bcd");
64 if (!file)
65 {
66 grub_printf("Failed to open bcd file in the image file\n");
67 return 1;
68 }
69
70 grub_file_read(file, &offset, 4);
71 offset = (grub_uint32_t)grub_iso9660_get_last_read_pos(file);
72
73 *bcdoffset = (int)offset;
74 *bcdlen = (int)file->size;
75
76 debug("vhdiso bcd file offset:%d len:%d\n", *bcdoffset, *bcdlen);
77
78 grub_file_close(file);
79
80 grub_script_execute_sourcecode("loopback -d vhdiso");
81
82 return 0;
83 }
84
85 static int ventoy_vhd_patch_path(char *vhdpath, ventoy_patch_vhd *patch1, ventoy_patch_vhd *patch2)
86 {
87 int i;
88 int cnt = 0;
89 char *pos;
90 grub_size_t pathlen;
91 const char *plat;
92 grub_uint16_t *unicode_path;
93 const grub_uint8_t winloadexe[] =
94 {
95 0x77, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x61, 0x00, 0x64, 0x00, 0x2E, 0x00,
96 0x65, 0x00, 0x78, 0x00, 0x65, 0x00
97 };
98
99 pathlen = sizeof(grub_uint16_t) * (grub_strlen(vhdpath) + 1);
100 debug("unicode path for <%s> len:%d\n", vhdpath, (int)pathlen);
101
102 unicode_path = grub_zalloc(pathlen);
103 if (!unicode_path)
104 {
105 return 0;
106 }
107
108 plat = grub_env_get("grub_platform");
109
110 if (plat && (plat[0] == 'e')) /* UEFI */
111 {
112 pos = g_vhdboot_isobuf + g_vhdboot_bcd_offset;
113
114 /* winload.exe ==> winload.efi */
115 for (i = 0; i + (int)sizeof(winloadexe) < g_vhdboot_bcd_len; i++)
116 {
117 if (*((grub_uint32_t *)(pos + i)) == 0x00690077 &&
118 grub_memcmp(pos + i, winloadexe, sizeof(winloadexe)) == 0)
119 {
120 pos[i + sizeof(winloadexe) - 4] = 0x66;
121 pos[i + sizeof(winloadexe) - 2] = 0x69;
122 cnt++;
123 }
124 }
125
126 debug("winload patch %d times\n", cnt);
127 }
128
129 for (pos = vhdpath; *pos; pos++)
130 {
131 if (*pos == '/')
132 {
133 *pos = '\\';
134 }
135 }
136
137 grub_utf8_to_utf16(unicode_path, pathlen, (grub_uint8_t *)vhdpath, -1, NULL);
138 grub_memcpy(patch1->vhd_file_path, unicode_path, pathlen);
139 grub_memcpy(patch2->vhd_file_path, unicode_path, pathlen);
140
141 return 0;
142 }
143
144 static int ventoy_vhd_patch_disk(char *isopart, ventoy_patch_vhd *patch1, ventoy_patch_vhd *patch2)
145 {
146 char *pos;
147 grub_disk_t disk;
148 ventoy_gpt_info *gptinfo;
149 char efipart[16] = {0};
150
151 pos = grub_strchr(isopart, ',');
152 if (pos)
153 {
154 *pos = 0;
155 }
156
157 pos = isopart;
158 if (*pos == '(')
159 {
160 pos++;
161 }
162
163 debug("vhd disk <%s>\n", pos);
164
165 disk = grub_disk_open(pos);
166 if (!disk)
167 {
168 debug("Failed to open disk %s\n", pos);
169 return 1;
170 }
171
172 gptinfo = (ventoy_gpt_info *)(g_vhdboot_isobuf + g_vhdboot_isolen);
173 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), gptinfo);
174
175 grub_memcpy(efipart, gptinfo->Head.Signature, sizeof(gptinfo->Head.Signature));
176
177 debug("part1 type: 0x%x <%s>\n", gptinfo->MBR.PartTbl[0].FsFlag, efipart);
178
179 if (grub_strncmp(efipart, "EFI PART", 8) == 0)
180 {
181 ventoy_debug_dump_guid("GPT disk GUID: ", gptinfo->Head.DiskGuid);
182 ventoy_debug_dump_guid("GPT part GUID: ", gptinfo->PartTbl[0].PartGuid);
183
184 grub_memcpy(patch1->disk_signature_or_guid, gptinfo->Head.DiskGuid, 16);
185 grub_memcpy(patch1->part_offset_or_guid, gptinfo->PartTbl[0].PartGuid, 16);
186 grub_memcpy(patch2->disk_signature_or_guid, gptinfo->Head.DiskGuid, 16);
187 grub_memcpy(patch2->part_offset_or_guid, gptinfo->PartTbl[0].PartGuid, 16);
188
189 patch1->part_type = patch2->part_type = 0;
190 }
191 else
192 {
193 debug("MBR disk signature: %02x%02x%02x%02x\n",
194 gptinfo->MBR.BootCode[0x1b8 + 0], gptinfo->MBR.BootCode[0x1b8 + 1],
195 gptinfo->MBR.BootCode[0x1b8 + 2], gptinfo->MBR.BootCode[0x1b8 + 3]);
196 grub_memcpy(patch1->disk_signature_or_guid, gptinfo->MBR.BootCode + 0x1b8, 4);
197 grub_memcpy(patch2->disk_signature_or_guid, gptinfo->MBR.BootCode + 0x1b8, 4);
198 }
199
200 grub_disk_close(disk);
201
202 return 0;
203 }
204
205 grub_err_t ventoy_cmd_patch_vhdboot(grub_extcmd_context_t ctxt, int argc, char **args)
206 {
207 int rc;
208 ventoy_patch_vhd *patch1;
209 ventoy_patch_vhd *patch2;
210 char envbuf[64];
211
212 (void)ctxt;
213 (void)argc;
214
215 grub_env_unset("vtoy_vhd_buf_addr");
216
217 debug("patch vhd <%s> <%s>\n", args[0], args[1]);
218
219 if ((!g_vhdboot_enable) || (!g_vhdboot_totbuf))
220 {
221 debug("vhd boot not ready %d %p\n", g_vhdboot_enable, g_vhdboot_totbuf);
222 return 0;
223 }
224
225 rc = ventoy_vhd_find_bcd(&g_vhdboot_bcd_offset, &g_vhdboot_bcd_len);
226 if (rc)
227 {
228 debug("failed to get bcd location %d\n", rc);
229 return 0;
230 }
231
232 patch1 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + g_vhdboot_bcd_offset + 0x495a);
233 patch2 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + g_vhdboot_bcd_offset + 0x50aa);
234
235 ventoy_vhd_patch_disk(args[0], patch1, patch2);
236 ventoy_vhd_patch_path(args[1], patch1, patch2);
237
238 /* set buffer and size */
239 #ifdef GRUB_MACHINE_EFI
240 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (ulong)g_vhdboot_totbuf);
241 grub_env_set("vtoy_vhd_buf_addr", envbuf);
242 grub_snprintf(envbuf, sizeof(envbuf), "%d", (int)(g_vhdboot_isolen + sizeof(ventoy_chain_head)));
243 grub_env_set("vtoy_vhd_buf_size", envbuf);
244 #else
245 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (ulong)g_vhdboot_isobuf);
246 grub_env_set("vtoy_vhd_buf_addr", envbuf);
247 grub_snprintf(envbuf, sizeof(envbuf), "%d", g_vhdboot_isolen);
248 grub_env_set("vtoy_vhd_buf_size", envbuf);
249 #endif
250
251 return 0;
252 }
253
254 grub_err_t ventoy_cmd_load_vhdboot(grub_extcmd_context_t ctxt, int argc, char **args)
255 {
256 int buflen;
257 grub_file_t file;
258
259 (void)ctxt;
260 (void)argc;
261
262 g_vhdboot_enable = 0;
263 grub_check_free(g_vhdboot_totbuf);
264
265 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
266 if (!file)
267 {
268 return 0;
269 }
270
271 debug("load vhd boot: <%s> <%lu>\n", args[0], (ulong)file->size);
272
273 if (file->size < VTOY_SIZE_1KB * 32)
274 {
275 grub_file_close(file);
276 return 0;
277 }
278
279 g_vhdboot_isolen = (int)file->size;
280
281 buflen = (int)(file->size + sizeof(ventoy_gpt_info) + sizeof(ventoy_chain_head));
282
283 #ifdef GRUB_MACHINE_EFI
284 g_vhdboot_totbuf = (char *)grub_efi_allocate_iso_buf(buflen);
285 #else
286 g_vhdboot_totbuf = (char *)grub_malloc(buflen);
287 #endif
288
289 if (!g_vhdboot_totbuf)
290 {
291 grub_file_close(file);
292 return 0;
293 }
294
295 g_vhdboot_isobuf = g_vhdboot_totbuf + sizeof(ventoy_chain_head);
296
297 grub_file_read(file, g_vhdboot_isobuf, file->size);
298 grub_file_close(file);
299
300 g_vhdboot_enable = 1;
301
302 return 0;
303 }
304