]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_vhd.c
45ce7c6cbdb1376769d7aa51df730bc3680fa15f
[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_isolen = 0;
48 static char *g_vhdboot_totbuf = NULL;
49 static char *g_vhdboot_isobuf = NULL;
50 static grub_uint64_t g_img_trim_head_secnum = 0;
51
52 static int ventoy_vhd_find_bcd(int *bcdoffset, int *bcdlen, const char *path)
53 {
54 grub_uint32_t offset;
55 grub_file_t file;
56 char cmdbuf[128];
57
58 grub_snprintf(cmdbuf, sizeof(cmdbuf), "loopback vhdiso mem:0x%lx:size:%d", (ulong)g_vhdboot_isobuf, g_vhdboot_isolen);
59
60 grub_script_execute_sourcecode(cmdbuf);
61
62 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(vhdiso)%s", path);
63 if (!file)
64 {
65 return 1;
66 }
67
68 grub_file_read(file, &offset, 4);
69 offset = (grub_uint32_t)grub_iso9660_get_last_read_pos(file);
70
71 *bcdoffset = (int)offset;
72 *bcdlen = (int)file->size;
73
74 debug("vhdiso bcd file offset:%d len:%d\n", *bcdoffset, *bcdlen);
75
76 grub_file_close(file);
77
78 grub_script_execute_sourcecode("loopback -d vhdiso");
79
80 return 0;
81 }
82
83 static int ventoy_vhd_patch_path(char *vhdpath, ventoy_patch_vhd *patch1, ventoy_patch_vhd *patch2,
84 int bcdoffset, int bcdlen)
85 {
86 int i;
87 int cnt = 0;
88 char *pos;
89 grub_size_t pathlen;
90 const char *plat;
91 char *newpath = NULL;
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 while ((*vhdpath) != '/')
100 {
101 vhdpath++;
102 }
103
104 pathlen = sizeof(grub_uint16_t) * (grub_strlen(vhdpath) + 1);
105 debug("unicode path for <%s> len:%d\n", vhdpath, (int)pathlen);
106
107 unicode_path = grub_zalloc(pathlen);
108 if (!unicode_path)
109 {
110 return 0;
111 }
112
113 plat = grub_env_get("grub_platform");
114
115 if (plat && (plat[0] == 'e')) /* UEFI */
116 {
117 pos = g_vhdboot_isobuf + bcdoffset;
118
119 /* winload.exe ==> winload.efi */
120 for (i = 0; i + (int)sizeof(winloadexe) < bcdlen; i++)
121 {
122 if (*((grub_uint32_t *)(pos + i)) == 0x00690077 &&
123 grub_memcmp(pos + i, winloadexe, sizeof(winloadexe)) == 0)
124 {
125 pos[i + sizeof(winloadexe) - 4] = 0x66;
126 pos[i + sizeof(winloadexe) - 2] = 0x69;
127 cnt++;
128 }
129 }
130
131 debug("winload patch %d times\n", cnt);
132 }
133
134 newpath = grub_strdup(vhdpath);
135 for (pos = newpath; *pos; pos++)
136 {
137 if (*pos == '/')
138 {
139 *pos = '\\';
140 }
141 }
142
143 grub_utf8_to_utf16(unicode_path, pathlen, (grub_uint8_t *)newpath, -1, NULL);
144 grub_memcpy(patch1->vhd_file_path, unicode_path, pathlen);
145 grub_memcpy(patch2->vhd_file_path, unicode_path, pathlen);
146
147 grub_free(newpath);
148 return 0;
149 }
150
151 static int ventoy_vhd_read_parttbl(const char *filename, ventoy_gpt_info *gpt, int *index, grub_uint64_t *poffset)
152 {
153 int i;
154 int find = 0;
155 int ret = 1;
156 grub_uint64_t start;
157 grub_file_t file = NULL;
158 grub_disk_t disk = NULL;
159 grub_uint8_t zeroguid[16] = {0};
160
161 file = grub_file_open(filename, VENTOY_FILE_TYPE);
162 if (!file)
163 {
164 goto end;
165 }
166
167 disk = grub_disk_open(file->device->disk->name);
168 if (!disk)
169 {
170 goto end;
171 }
172
173 grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), gpt);
174
175 start = file->device->disk->partition->start;
176
177 if (grub_memcmp(gpt->Head.Signature, "EFI PART", 8) == 0)
178 {
179 debug("GPT part start: %llu\n", (ulonglong)start);
180 for (i = 0; i < 128; i++)
181 {
182 if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16))
183 {
184 if (start == gpt->PartTbl[i].StartLBA)
185 {
186 *index = i;
187 find = 1;
188 break;
189 }
190 }
191 }
192 }
193 else
194 {
195 debug("MBR part start: %llu\n", (ulonglong)start);
196 for (i = 0; i < 4; i++)
197 {
198 if ((grub_uint32_t)start == gpt->MBR.PartTbl[i].StartSectorId)
199 {
200 *index = i;
201 find = 1;
202 break;
203 }
204 }
205 }
206
207 if (find == 0) // MBR Logical partition
208 {
209 if (file->device->disk->partition->number > 0)
210 {
211 *index = file->device->disk->partition->number;
212 debug("Fall back part number: %d\n", *index);
213 }
214 }
215
216 *poffset = start;
217 ret = 0;
218
219 end:
220 check_free(file, grub_file_close);
221 check_free(disk, grub_disk_close);
222
223 return ret;
224 }
225
226 static int ventoy_vhd_patch_disk(const char *vhdpath, ventoy_patch_vhd *patch1, ventoy_patch_vhd *patch2)
227 {
228 int partIndex = 0;
229 grub_uint64_t offset = 0;
230 char efipart[16] = {0};
231 ventoy_gpt_info *gpt = NULL;
232
233 if (vhdpath[0] == '/')
234 {
235 gpt = g_ventoy_part_info;
236 partIndex = 0;
237 debug("This is Ventoy ISO partIndex %d %s\n", partIndex, vhdpath);
238 }
239 else
240 {
241 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
242 ventoy_vhd_read_parttbl(vhdpath, gpt, &partIndex, &offset);
243 debug("This is HDD partIndex %d %s\n", partIndex, vhdpath);
244 }
245
246 grub_memcpy(efipart, gpt->Head.Signature, sizeof(gpt->Head.Signature));
247
248 grub_memset(patch1, 0, OFFSET_OF(ventoy_patch_vhd, vhd_file_path));
249 grub_memset(patch2, 0, OFFSET_OF(ventoy_patch_vhd, vhd_file_path));
250
251 if (grub_strncmp(efipart, "EFI PART", 8) == 0)
252 {
253 ventoy_debug_dump_guid("GPT disk GUID: ", gpt->Head.DiskGuid);
254 ventoy_debug_dump_guid("GPT partIndex GUID: ", gpt->PartTbl[partIndex].PartGuid);
255
256 grub_memcpy(patch1->disk_signature_or_guid, gpt->Head.DiskGuid, 16);
257 grub_memcpy(patch1->part_offset_or_guid, gpt->PartTbl[partIndex].PartGuid, 16);
258 grub_memcpy(patch2->disk_signature_or_guid, gpt->Head.DiskGuid, 16);
259 grub_memcpy(patch2->part_offset_or_guid, gpt->PartTbl[partIndex].PartGuid, 16);
260
261 patch1->part_type = patch2->part_type = 0;
262 }
263 else
264 {
265 if (offset == 0)
266 {
267 offset = gpt->MBR.PartTbl[partIndex].StartSectorId;
268 }
269 offset *= 512;
270 debug("MBR disk signature: %02x%02x%02x%02x Part(%d) offset:%llu\n",
271 gpt->MBR.BootCode[0x1b8 + 0], gpt->MBR.BootCode[0x1b8 + 1],
272 gpt->MBR.BootCode[0x1b8 + 2], gpt->MBR.BootCode[0x1b8 + 3],
273 partIndex + 1, offset);
274
275 grub_memcpy(patch1->part_offset_or_guid, &offset, 8);
276 grub_memcpy(patch2->part_offset_or_guid, &offset, 8);
277
278 grub_memcpy(patch1->disk_signature_or_guid, gpt->MBR.BootCode + 0x1b8, 4);
279 grub_memcpy(patch2->disk_signature_or_guid, gpt->MBR.BootCode + 0x1b8, 4);
280
281 patch1->part_type = patch2->part_type = 1;
282 }
283
284 if (gpt != g_ventoy_part_info)
285 {
286 grub_free(gpt);
287 }
288
289 return 0;
290 }
291
292 static int ventoy_find_vhdpatch_offset(int bcdoffset, int bcdlen, int *offset)
293 {
294 int i;
295 int cnt = 0;
296 grub_uint8_t *buf = (grub_uint8_t *)(g_vhdboot_isobuf + bcdoffset);
297 grub_uint8_t magic[16] = {
298 0x5C, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00
299 };
300
301 for (i = 0; i < bcdlen - 16 && cnt < 2; i++)
302 {
303 if (*(grub_uint32_t *)(buf + i) == 0x0058005C)
304 {
305 if (grub_memcmp(magic, buf + i, 16) == 0)
306 {
307 *offset++ = i - (int)OFFSET_OF(ventoy_patch_vhd, vhd_file_path);
308 cnt++;
309 }
310 }
311 }
312
313 return 0;
314 }
315
316 grub_err_t ventoy_cmd_patch_vhdboot(grub_extcmd_context_t ctxt, int argc, char **args)
317 {
318 int rc;
319 int bcdoffset, bcdlen;
320 int patchoffset[2];
321 ventoy_patch_vhd *patch1;
322 ventoy_patch_vhd *patch2;
323
324 (void)ctxt;
325 (void)argc;
326
327 grub_env_unset("vtoy_vhd_buf_addr");
328
329 debug("patch vhd <%s>\n", args[0]);
330
331 if ((!g_vhdboot_enable) || (!g_vhdboot_totbuf))
332 {
333 debug("vhd boot not ready %d %p\n", g_vhdboot_enable, g_vhdboot_totbuf);
334 return 0;
335 }
336
337 rc = ventoy_vhd_find_bcd(&bcdoffset, &bcdlen, "/boot/bcd");
338 if (rc)
339 {
340 debug("failed to get bcd location %d\n", rc);
341 }
342 else
343 {
344 ventoy_find_vhdpatch_offset(bcdoffset, bcdlen, patchoffset);
345 patch1 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + bcdoffset + patchoffset[0]);
346 patch2 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + bcdoffset + patchoffset[1]);
347
348 debug("Find /boot/bcd (%d %d) now patch it (offset: 0x%x 0x%x) ...\n",
349 bcdoffset, bcdlen, patchoffset[0], patchoffset[1]);
350 ventoy_vhd_patch_disk(args[0], patch1, patch2);
351 ventoy_vhd_patch_path(args[0], patch1, patch2, bcdoffset, bcdlen);
352 }
353
354 rc = ventoy_vhd_find_bcd(&bcdoffset, &bcdlen, "/boot/BCD");
355 if (rc)
356 {
357 debug("No file /boot/BCD \n");
358 }
359 else
360 {
361 ventoy_find_vhdpatch_offset(bcdoffset, bcdlen, patchoffset);
362 patch1 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + bcdoffset + patchoffset[0]);
363 patch2 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + bcdoffset + patchoffset[1]);
364
365 debug("Find /boot/BCD (%d %d) now patch it (offset: 0x%x 0x%x) ...\n",
366 bcdoffset, bcdlen, patchoffset[0], patchoffset[1]);
367 ventoy_vhd_patch_disk(args[0], patch1, patch2);
368 ventoy_vhd_patch_path(args[0], patch1, patch2, bcdoffset, bcdlen);
369 }
370
371 /* set buffer and size */
372 #ifdef GRUB_MACHINE_EFI
373 ventoy_memfile_env_set("vtoy_vhd_buf", g_vhdboot_totbuf, (ulonglong)(g_vhdboot_isolen + sizeof(ventoy_chain_head)));
374 #else
375 ventoy_memfile_env_set("vtoy_vhd_buf", g_vhdboot_isobuf, (ulonglong)g_vhdboot_isolen);
376 #endif
377
378 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
379 }
380
381 grub_err_t ventoy_cmd_load_vhdboot(grub_extcmd_context_t ctxt, int argc, char **args)
382 {
383 int buflen;
384 grub_file_t file;
385
386 (void)ctxt;
387 (void)argc;
388
389 g_vhdboot_enable = 0;
390 grub_check_free(g_vhdboot_totbuf);
391
392 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
393 if (!file)
394 {
395 return 0;
396 }
397
398 debug("load vhd boot: <%s> <%lu>\n", args[0], (ulong)file->size);
399
400 if (file->size < VTOY_SIZE_1KB * 32)
401 {
402 grub_file_close(file);
403 return 0;
404 }
405
406 g_vhdboot_isolen = (int)file->size;
407
408 buflen = (int)(file->size + sizeof(ventoy_chain_head));
409
410 #ifdef GRUB_MACHINE_EFI
411 g_vhdboot_totbuf = (char *)grub_efi_allocate_iso_buf(buflen);
412 #else
413 g_vhdboot_totbuf = (char *)grub_malloc(buflen);
414 #endif
415
416 if (!g_vhdboot_totbuf)
417 {
418 grub_file_close(file);
419 return 0;
420 }
421
422 g_vhdboot_isobuf = g_vhdboot_totbuf + sizeof(ventoy_chain_head);
423
424 grub_file_read(file, g_vhdboot_isobuf, file->size);
425 grub_file_close(file);
426
427 g_vhdboot_enable = 1;
428
429 return 0;
430 }
431
432 static int ventoy_raw_trim_head(grub_uint64_t offset)
433 {
434 grub_uint32_t i;
435 grub_uint32_t memsize;
436 grub_uint32_t imgstart = 0;
437 grub_uint32_t imgsecs = 0;
438 grub_uint64_t sectors = 0;
439 grub_uint64_t cursecs = 0;
440 grub_uint64_t delta = 0;
441
442 if ((!g_img_chunk_list.chunk) || (!offset))
443 {
444 debug("image chunk not ready %p %lu\n", g_img_chunk_list.chunk, (ulong)offset);
445 return 0;
446 }
447
448 debug("image trim head %lu\n", (ulong)offset);
449
450 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
451 {
452 cursecs = g_img_chunk_list.chunk[i].disk_end_sector + 1 - g_img_chunk_list.chunk[i].disk_start_sector;
453 sectors += cursecs;
454 if (sectors >= offset)
455 {
456 delta = cursecs - (sectors - offset);
457 break;
458 }
459 }
460
461 if (sectors < offset || i >= g_img_chunk_list.cur_chunk)
462 {
463 debug("Invalid size %lu %lu\n", (ulong)sectors, (ulong)offset);
464 return 0;
465 }
466
467 if (sectors == offset)
468 {
469 memsize = (g_img_chunk_list.cur_chunk - (i + 1)) * sizeof(ventoy_img_chunk);
470 grub_memmove(g_img_chunk_list.chunk, g_img_chunk_list.chunk + i + 1, memsize);
471 g_img_chunk_list.cur_chunk -= (i + 1);
472 }
473 else
474 {
475 g_img_chunk_list.chunk[i].disk_start_sector += delta;
476 g_img_chunk_list.chunk[i].img_start_sector += (grub_uint32_t)(delta / 4);
477
478 if (i > 0)
479 {
480 memsize = (g_img_chunk_list.cur_chunk - i) * sizeof(ventoy_img_chunk);
481 grub_memmove(g_img_chunk_list.chunk, g_img_chunk_list.chunk + i, memsize);
482 g_img_chunk_list.cur_chunk -= i;
483 }
484 }
485
486 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
487 {
488 imgsecs = g_img_chunk_list.chunk[i].img_end_sector + 1 - g_img_chunk_list.chunk[i].img_start_sector;
489 g_img_chunk_list.chunk[i].img_start_sector = imgstart;
490 g_img_chunk_list.chunk[i].img_end_sector = imgstart + (imgsecs - 1);
491 imgstart += imgsecs;
492 }
493
494 return 0;
495 }
496
497 grub_err_t ventoy_cmd_get_vtoy_type(grub_extcmd_context_t ctxt, int argc, char **args)
498 {
499 int i;
500 int altboot = 0;
501 int offset = -1;
502 grub_file_t file;
503 grub_uint8_t data = 0;
504 vhd_footer_t vhdfoot;
505 VDIPREHEADER vdihdr;
506 char type[16] = {0};
507 ventoy_gpt_info *gpt = NULL;
508
509 (void)ctxt;
510
511 g_img_trim_head_secnum = 0;
512
513 if (argc != 4)
514 {
515 return 0;
516 }
517
518 file = grub_file_open(args[0], VENTOY_FILE_TYPE);
519 if (!file)
520 {
521 debug("Failed to open file %s\n", args[0]);
522 return 0;
523 }
524
525 grub_snprintf(type, sizeof(type), "unknown");
526
527 grub_file_seek(file, file->size - 512);
528 grub_file_read(file, &vhdfoot, sizeof(vhdfoot));
529
530 if (grub_strncmp(vhdfoot.cookie, "conectix", 8) == 0)
531 {
532 offset = 0;
533 grub_snprintf(type, sizeof(type), "vhd%u", grub_swap_bytes32(vhdfoot.disktype));
534 }
535 else
536 {
537 grub_file_seek(file, 0);
538 grub_file_read(file, &vdihdr, sizeof(vdihdr));
539 if (vdihdr.u32Signature == VDI_IMAGE_SIGNATURE &&
540 grub_strncmp(vdihdr.szFileInfo, VDI_IMAGE_FILE_INFO, grub_strlen(VDI_IMAGE_FILE_INFO)) == 0)
541 {
542 offset = 2 * 1048576;
543 g_img_trim_head_secnum = offset / 512;
544 grub_snprintf(type, sizeof(type), "vdi");
545 }
546 else
547 {
548 offset = 0;
549 grub_snprintf(type, sizeof(type), "raw");
550 }
551 }
552
553 grub_env_set(args[1], type);
554 debug("<%s> vtoy type: <%s> offset:%d\n", args[0], type, offset);
555
556 if (offset >= 0)
557 {
558 gpt = grub_zalloc(sizeof(ventoy_gpt_info));
559 if (!gpt)
560 {
561 grub_env_set(args[1], "unknown");
562 goto end;
563 }
564
565 grub_file_seek(file, offset);
566 grub_file_read(file, gpt, sizeof(ventoy_gpt_info));
567
568 if (gpt->MBR.Byte55 != 0x55 || gpt->MBR.ByteAA != 0xAA)
569 {
570 grub_env_set(args[1], "unknown");
571 debug("invalid mbr signature: 0x%x 0x%x\n", gpt->MBR.Byte55, gpt->MBR.ByteAA);
572 goto end;
573 }
574
575 if (grub_memcmp(gpt->Head.Signature, "EFI PART", 8) == 0)
576 {
577 grub_env_set(args[2], "gpt");
578 debug("part type: %s\n", "GPT");
579
580 if (gpt->MBR.PartTbl[0].FsFlag == 0xEE)
581 {
582 for (i = 0; i < 128; i++)
583 {
584 if (grub_memcmp(gpt->PartTbl[i].PartType, "Hah!IdontNeedEFI", 16) == 0)
585 {
586 debug("part %d is grub_bios part\n", i);
587 altboot = 1;
588 grub_env_set(args[3], "1");
589 break;
590 }
591 else if (gpt->PartTbl[i].LastLBA == 0)
592 {
593 break;
594 }
595 }
596 }
597
598 if (!altboot)
599 {
600 if (gpt->MBR.BootCode[92] == 0x22)
601 {
602 grub_file_seek(file, offset + 17908);
603 grub_file_read(file, &data, 1);
604 if (data == 0x23)
605 {
606 altboot = 1;
607 grub_env_set(args[3], "1");
608 }
609 else
610 {
611 debug("offset data=0x%x\n", data);
612 }
613 }
614 else
615 {
616 debug("BootCode: 0x%x\n", gpt->MBR.BootCode[92]);
617 }
618 }
619 }
620 else
621 {
622 grub_env_set(args[2], "mbr");
623 debug("part type: %s\n", "MBR");
624
625 for (i = 0; i < 4; i++)
626 {
627 if (gpt->MBR.PartTbl[i].FsFlag == 0xEF)
628 {
629 debug("part %d is esp part in MBR mode\n", i);
630 altboot = 1;
631 grub_env_set(args[3], "1");
632 break;
633 }
634 }
635 }
636 }
637 else
638 {
639 debug("part type: %s\n", "xxx");
640 }
641
642 end:
643 grub_check_free(gpt);
644 grub_file_close(file);
645 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
646 }
647
648 grub_err_t ventoy_cmd_raw_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
649 {
650 grub_uint32_t size = 0;
651 grub_uint32_t img_chunk_size = 0;
652 grub_file_t file;
653 grub_disk_t disk;
654 const char *pLastChain = NULL;
655 ventoy_chain_head *chain;
656
657 (void)ctxt;
658 (void)argc;
659
660 if (NULL == g_img_chunk_list.chunk)
661 {
662 grub_printf("ventoy not ready\n");
663 return 1;
664 }
665
666 if (g_img_trim_head_secnum > 0)
667 {
668 ventoy_raw_trim_head(g_img_trim_head_secnum);
669 }
670
671 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
672 if (!file)
673 {
674 return 1;
675 }
676
677 if (grub_strncmp(args[0], g_iso_path, grub_strlen(g_iso_path)))
678 {
679 file->vlnk = 1;
680 }
681
682 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
683
684 size = sizeof(ventoy_chain_head) + img_chunk_size;
685
686 pLastChain = grub_env_get("vtoy_chain_mem_addr");
687 if (pLastChain)
688 {
689 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
690 if (chain)
691 {
692 debug("free last chain memory %p\n", chain);
693 grub_free(chain);
694 }
695 }
696
697 chain = ventoy_alloc_chain(size);
698 if (!chain)
699 {
700 grub_printf("Failed to alloc chain raw memory size %u\n", size);
701 grub_file_close(file);
702 return 1;
703 }
704
705 ventoy_memfile_env_set("vtoy_chain_mem", chain, (ulonglong)size);
706
707 grub_env_export("vtoy_chain_mem_addr");
708 grub_env_export("vtoy_chain_mem_size");
709
710 grub_memset(chain, 0, sizeof(ventoy_chain_head));
711
712 /* part 1: os parameter */
713 g_ventoy_chain_type = ventoy_chain_linux;
714 ventoy_fill_os_param(file, &(chain->os_param));
715
716 /* part 2: chain head */
717 disk = file->device->disk;
718 chain->disk_drive = disk->id;
719 chain->disk_sector_size = (1 << disk->log_sector_size);
720
721 chain->real_img_size_in_bytes = file->size;
722 if (g_img_trim_head_secnum > 0)
723 {
724 chain->real_img_size_in_bytes -= g_img_trim_head_secnum * 512;
725 }
726
727 chain->virt_img_size_in_bytes = chain->real_img_size_in_bytes;
728 chain->boot_catalog = 0;
729
730 /* part 3: image chunk */
731 chain->img_chunk_offset = sizeof(ventoy_chain_head);
732 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
733 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
734
735 grub_file_seek(file, g_img_trim_head_secnum * 512);
736 grub_file_read(file, chain->boot_catalog_sector, 512);
737
738 grub_file_close(file);
739
740 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
741 }