1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
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.
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.
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/>.
21 #include <grub/types.h>
22 #include <grub/misc.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>
36 #include <grub/time.h>
37 #include <grub/crypto.h>
38 #include <grub/ventoy.h>
39 #include "ventoy_def.h"
41 GRUB_MOD_LICENSE ("GPLv3+");
46 static wim_lookup_entry
*g_replace_look
= NULL
;
48 grub_ssize_t
lzx_decompress ( const void *data
, grub_size_t len
, void *buf
);
50 static int wim_name_cmp(const char *search
, grub_uint16_t
*name
, grub_uint16_t namelen
)
52 char c1
= vtoy_to_upper(*search
);
53 char c2
= vtoy_to_upper(*name
);
55 while (namelen
> 0 && (c1
== c2
))
61 c1
= vtoy_to_upper(*search
);
62 c2
= vtoy_to_upper(*name
);
65 if (namelen
== 0 && *search
== 0)
73 static int ventoy_is_pe64(grub_uint8_t
*buffer
)
77 if (buffer
[0] != 'M' || buffer
[1] != 'Z')
82 pe_off
= *(grub_uint32_t
*)(buffer
+ 60);
84 if (buffer
[pe_off
] != 'P' || buffer
[pe_off
+ 1] != 'E')
89 if (*(grub_uint16_t
*)(buffer
+ pe_off
+ 24) == 0x020b)
97 grub_err_t
ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt
, int argc
, char **args
)
103 check_free(g_wim_data
.jump_bin_data
, grub_free
);
104 check_free(g_wim_data
.new_meta_data
, grub_free
);
105 check_free(g_wim_data
.new_lookup_data
, grub_free
);
107 grub_memset(&g_wim_data
, 0, sizeof(g_wim_data
));
112 static int ventoy_load_jump_exe(const char *path
, grub_uint8_t
**data
, grub_uint32_t
*size
, wim_hash
*hash
)
118 debug("windows load jump %s\n", path
);
120 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", path
);
123 debug("Can't open file %s\n", path
);
127 align
= ventoy_align((int)file
->size
, 2048);
129 debug("file %s size:%d align:%u\n", path
, (int)file
->size
, align
);
131 *size
= (grub_uint32_t
)file
->size
;
132 *data
= (grub_uint8_t
*)grub_malloc(align
);
135 debug("Failed to alloc memory size %u\n", align
);
139 grub_file_read(file
, (*data
), file
->size
);
143 grub_crypto_hash(GRUB_MD_SHA1
, hash
->sha1
, (*data
), file
->size
);
147 debug("%s", "jump bin 64 hash: ");
148 for (i
= 0; i
< sizeof(hash
->sha1
); i
++)
150 ventoy_debug("%02x ", hash
->sha1
[i
]);
158 grub_file_close(file
);
162 static int ventoy_get_override_info(grub_file_t file
)
164 grub_uint32_t start_block
;
165 grub_uint64_t file_offset
;
166 grub_uint64_t override_offset
;
167 grub_uint32_t override_len
;
168 grub_uint64_t fe_entry_size_offset
;
170 if (grub_strcmp(file
->fs
->name
, "iso9660") == 0)
172 g_wim_data
.iso_type
= 0;
173 override_len
= sizeof(ventoy_iso9660_override
);
174 override_offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
176 grub_file_read(file
, &start_block
, 1); // just read for hook trigger
177 file_offset
= grub_iso9660_get_last_read_pos(file
);
179 debug("iso9660 wim size:%llu override_offset:%llu file_offset:%llu\n",
180 (ulonglong
)file
->size
, (ulonglong
)override_offset
, (ulonglong
)file_offset
);
184 g_wim_data
.iso_type
= 1;
185 override_len
= sizeof(ventoy_udf_override
);
186 override_offset
= grub_udf_get_last_file_attr_offset(file
, &start_block
, &fe_entry_size_offset
);
188 file_offset
= grub_udf_get_file_offset(file
);
190 debug("UDF wim size:%llu override_offset:%llu file_offset:%llu start_block=%u\n",
191 (ulonglong
)file
->size
, (ulonglong
)override_offset
, (ulonglong
)file_offset
, start_block
);
194 g_wim_data
.file_offset
= file_offset
;
195 g_wim_data
.udf_start_block
= start_block
;
196 g_wim_data
.fe_entry_size_offset
= fe_entry_size_offset
;
197 g_wim_data
.override_offset
= override_offset
;
198 g_wim_data
.override_len
= override_len
;
203 static int ventoy_read_resource(grub_file_t fp
, wim_resource_header
*head
, void **buffer
)
205 int decompress_len
= 0;
206 int total_decompress
= 0;
208 grub_uint32_t chunk_num
= 0;
209 grub_uint32_t chunk_size
= 0;
210 grub_uint32_t last_chunk_size
= 0;
211 grub_uint32_t last_decompress_size
= 0;
212 grub_uint32_t cur_offset
= 0;
213 grub_uint8_t
*cur_dst
= NULL
;
214 grub_uint8_t
*buffer_compress
= NULL
;
215 grub_uint8_t
*buffer_decompress
= NULL
;
216 grub_uint32_t
*chunk_offset
= NULL
;
218 buffer_decompress
= (grub_uint8_t
*)grub_malloc(head
->raw_size
+ head
->size_in_wim
);
219 if (NULL
== buffer_decompress
)
224 grub_file_seek(fp
, head
->offset
);
226 if (head
->size_in_wim
== head
->raw_size
)
228 grub_file_read(fp
, buffer_decompress
, head
->size_in_wim
);
229 *buffer
= buffer_decompress
;
233 buffer_compress
= buffer_decompress
+ head
->raw_size
;
234 grub_file_read(fp
, buffer_compress
, head
->size_in_wim
);
236 chunk_num
= (head
->raw_size
+ WIM_CHUNK_LEN
- 1) / WIM_CHUNK_LEN
;
237 cur_offset
= (chunk_num
- 1) * 4;
238 chunk_offset
= (grub_uint32_t
*)buffer_compress
;
240 cur_dst
= buffer_decompress
;
242 for (i
= 0; i
< chunk_num
- 1; i
++)
244 chunk_size
= (i
== 0) ? chunk_offset
[i
] : chunk_offset
[i
] - chunk_offset
[i
- 1];
246 if (WIM_CHUNK_LEN
== chunk_size
)
248 grub_memcpy(cur_dst
, buffer_compress
+ cur_offset
, chunk_size
);
249 decompress_len
= (int)chunk_size
;
253 decompress_len
= (int)lzx_decompress(buffer_compress
+ cur_offset
, chunk_size
, cur_dst
);
256 //debug("chunk_size:%u decompresslen:%d\n", chunk_size, decompress_len);
258 total_decompress
+= decompress_len
;
259 cur_dst
+= decompress_len
;
260 cur_offset
+= chunk_size
;
264 last_chunk_size
= (grub_uint32_t
)(head
->size_in_wim
- cur_offset
);
265 last_decompress_size
= head
->raw_size
- total_decompress
;
267 if (last_chunk_size
< WIM_CHUNK_LEN
&& last_chunk_size
== last_decompress_size
)
269 debug("Last chunk %u uncompressed\n", last_chunk_size
);
270 grub_memcpy(cur_dst
, buffer_compress
+ cur_offset
, last_chunk_size
);
271 decompress_len
= (int)last_chunk_size
;
275 decompress_len
= (int)lzx_decompress(buffer_compress
+ cur_offset
, head
->size_in_wim
- cur_offset
, cur_dst
);
278 cur_dst
+= decompress_len
;
279 total_decompress
+= decompress_len
;
281 if (cur_dst
!= buffer_decompress
+ head
->raw_size
)
283 debug("head->size_in_wim:%llu head->raw_size:%llu cur_dst:%p buffer_decompress:%p total_decompress:%d\n",
284 (ulonglong
)head
->size_in_wim
, (ulonglong
)head
->raw_size
, cur_dst
, buffer_decompress
, total_decompress
);
285 grub_free(buffer_decompress
);
289 *buffer
= buffer_decompress
;
294 static wim_directory_entry
* search_wim_dirent(wim_directory_entry
*dir
, const char *search_name
)
298 if (dir
->len
&& dir
->name_len
)
300 if (wim_name_cmp(search_name
, (grub_uint16_t
*)(dir
+ 1), dir
->name_len
/ 2) == 0)
305 dir
= (wim_directory_entry
*)((grub_uint8_t
*)dir
+ dir
->len
);
311 static wim_directory_entry
* search_full_wim_dirent
314 wim_directory_entry
*dir
,
318 wim_directory_entry
*subdir
= NULL
;
319 wim_directory_entry
*search
= dir
;
323 subdir
= (wim_directory_entry
*)((char *)meta_data
+ search
->subdir
);
324 search
= search_wim_dirent(subdir
, *path
);
327 debug("%s search failed\n", *path
);
335 static wim_directory_entry
* search_replace_wim_dirent(void *meta_data
, wim_directory_entry
*dir
)
337 wim_directory_entry
*wim_dirent
= NULL
;
338 const char *winpeshl_path
[] = { "Windows", "System32", "winpeshl.exe", NULL
};
339 const char *pecmd_path
[] = { "Windows", "System32", "PECMD.exe", NULL
};
341 wim_dirent
= search_full_wim_dirent(meta_data
, dir
, winpeshl_path
);
347 wim_dirent
= search_full_wim_dirent(meta_data
, dir
, pecmd_path
);
357 static wim_lookup_entry
* ventoy_find_look_entry(wim_header
*header
, wim_lookup_entry
*lookup
, wim_hash
*hash
)
361 for (i
= 0; i
< (grub_uint32_t
)header
->lookup
.raw_size
/ sizeof(wim_lookup_entry
); i
++)
363 if (grub_memcmp(&lookup
[i
].hash
, hash
, sizeof(wim_hash
)) == 0)
372 static wim_lookup_entry
* ventoy_find_meta_entry(wim_header
*header
, wim_lookup_entry
*lookup
)
375 grub_uint32_t index
= 0;;
377 if ((header
== NULL
) || (lookup
== NULL
))
382 for (i
= 0; i
< (grub_uint32_t
)header
->lookup
.raw_size
/ sizeof(wim_lookup_entry
); i
++)
384 if (lookup
[i
].resource
.flags
& RESHDR_FLAG_METADATA
)
387 if (index
== header
->boot_index
)
397 static int ventoy_update_all_hash(void *meta_data
, wim_directory_entry
*dir
)
399 if ((meta_data
== NULL
) || (dir
== NULL
))
411 if (dir
->subdir
== 0 && grub_memcmp(dir
->hash
.sha1
, g_old_hash
.sha1
, sizeof(wim_hash
)) == 0)
413 debug("find target file, name_len:%u upadte hash\n", dir
->name_len
);
414 grub_memcpy(dir
->hash
.sha1
, &(g_wim_data
.bin_hash
), sizeof(wim_hash
));
419 ventoy_update_all_hash(meta_data
, (wim_directory_entry
*)((char *)meta_data
+ dir
->subdir
));
422 dir
= (wim_directory_entry
*)((char *)dir
+ dir
->len
);
428 static int ventoy_cat_exe_file_data(grub_uint32_t exe_len
, grub_uint8_t
*exe_data
)
432 grub_uint32_t jump_len
= 0;
433 grub_uint32_t jump_align
= 0;
434 grub_uint8_t
*jump_data
= NULL
;
436 pe64
= ventoy_is_pe64(exe_data
);
438 grub_snprintf(file
, sizeof(file
), "%s/vtoyjump%d.exe", grub_env_get("vtoy_path"), pe64
? 64 : 32);
439 ventoy_load_jump_exe(file
, &jump_data
, &jump_len
, NULL
);
440 jump_align
= ventoy_align(jump_len
, 16);
442 g_wim_data
.jump_exe_len
= jump_len
;
443 g_wim_data
.bin_raw_len
= jump_align
+ sizeof(ventoy_os_param
) + sizeof(ventoy_windows_data
) + exe_len
;
444 g_wim_data
.bin_align_len
= ventoy_align(g_wim_data
.bin_raw_len
, 2048);
446 g_wim_data
.jump_bin_data
= grub_malloc(g_wim_data
.bin_align_len
);
447 if (g_wim_data
.jump_bin_data
)
449 grub_memcpy(g_wim_data
.jump_bin_data
, jump_data
, jump_len
);
450 grub_memcpy(g_wim_data
.jump_bin_data
+ jump_align
+ sizeof(ventoy_os_param
) + sizeof(ventoy_windows_data
), exe_data
, exe_len
);
453 debug("jump_exe_len:%u bin_raw_len:%u bin_align_len:%u\n",
454 g_wim_data
.jump_exe_len
, g_wim_data
.bin_raw_len
, g_wim_data
.bin_align_len
);
459 int ventoy_fill_windows_rtdata(void *buf
, char *isopath
)
463 ventoy_windows_data
*data
= (ventoy_windows_data
*)buf
;
465 grub_memset(data
, 0, sizeof(ventoy_windows_data
));
467 pos
= grub_strstr(isopath
, "/");
473 script
= ventoy_plugin_get_install_template(pos
);
476 debug("auto install script <%s>\n", script
);
477 grub_snprintf(data
->auto_install_script
, sizeof(data
->auto_install_script
) - 1, "%s", script
);
481 debug("auto install script not found %p\n", pos
);
487 static int ventoy_update_before_chain(ventoy_os_param
*param
, char *isopath
)
489 grub_uint32_t jump_align
= 0;
490 wim_lookup_entry
*meta_look
= NULL
;
491 wim_security_header
*security
= NULL
;
492 wim_directory_entry
*rootdir
= NULL
;
493 wim_header
*head
= &(g_wim_data
.wim_header
);
494 wim_lookup_entry
*lookup
= (wim_lookup_entry
*)g_wim_data
.new_lookup_data
;
496 jump_align
= ventoy_align(g_wim_data
.jump_exe_len
, 16);
497 if (g_wim_data
.jump_bin_data
)
499 grub_memcpy(g_wim_data
.jump_bin_data
+ jump_align
, param
, sizeof(ventoy_os_param
));
500 ventoy_fill_windows_rtdata(g_wim_data
.jump_bin_data
+ jump_align
+ sizeof(ventoy_os_param
), isopath
);
503 grub_crypto_hash(GRUB_MD_SHA1
, g_wim_data
.bin_hash
.sha1
, g_wim_data
.jump_bin_data
, g_wim_data
.bin_raw_len
);
505 security
= (wim_security_header
*)g_wim_data
.new_meta_data
;
506 rootdir
= (wim_directory_entry
*)(g_wim_data
.new_meta_data
+ ((security
->len
+ 7) & 0xFFFFFFF8U
));
508 /* update all winpeshl.exe dirent entry's hash */
509 ventoy_update_all_hash(g_wim_data
.new_meta_data
, rootdir
);
511 /* update winpeshl.exe lookup entry data (hash/offset/length) */
514 debug("update replace lookup entry_id:%ld\n", ((long)g_replace_look
- (long)lookup
) / sizeof(wim_lookup_entry
));
515 g_replace_look
->resource
.raw_size
= g_wim_data
.bin_raw_len
;
516 g_replace_look
->resource
.size_in_wim
= g_wim_data
.bin_raw_len
;
517 g_replace_look
->resource
.flags
= 0;
518 g_replace_look
->resource
.offset
= g_wim_data
.wim_align_size
;
520 grub_memcpy(g_replace_look
->hash
.sha1
, g_wim_data
.bin_hash
.sha1
, sizeof(wim_hash
));
523 /* update metadata's hash */
524 meta_look
= ventoy_find_meta_entry(head
, lookup
);
527 debug("find meta lookup entry_id:%ld\n", ((long)meta_look
- (long)lookup
) / sizeof(wim_lookup_entry
));
528 grub_memcpy(&meta_look
->resource
, &head
->metadata
, sizeof(wim_resource_header
));
529 grub_crypto_hash(GRUB_MD_SHA1
, meta_look
->hash
.sha1
, g_wim_data
.new_meta_data
, g_wim_data
.new_meta_len
);
535 grub_err_t
ventoy_cmd_wimdows_locate_wim(grub_extcmd_context_t ctxt
, int argc
, char **args
)
539 grub_uint32_t exe_len
;
540 grub_uint8_t
*exe_data
= NULL
;
541 grub_uint8_t
*decompress_data
= NULL
;
542 wim_lookup_entry
*lookup
= NULL
;
543 wim_security_header
*security
= NULL
;
544 wim_directory_entry
*rootdir
= NULL
;
545 wim_directory_entry
*search
= NULL
;
546 wim_header
*head
= &(g_wim_data
.wim_header
);
551 debug("windows locate wim start %s\n", args
[0]);
553 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
556 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "Can't open file %s\n", args
[0]);
559 ventoy_get_override_info(file
);
561 grub_file_seek(file
, 0);
562 grub_file_read(file
, head
, sizeof(wim_header
));
564 if (grub_memcmp(head
->signature
, WIM_HEAD_SIGNATURE
, sizeof(head
->signature
)))
566 debug("Not a valid wim file %s\n", (char *)head
->signature
);
567 grub_file_close(file
);
571 if (head
->flags
& FLAG_HEADER_COMPRESS_XPRESS
)
573 debug("Xpress compress is not supported 0x%x\n", head
->flags
);
574 grub_file_close(file
);
578 rc
= ventoy_read_resource(file
, &head
->metadata
, (void **)&decompress_data
);
581 grub_printf("failed to read meta data %d\n", rc
);
582 grub_file_close(file
);
586 security
= (wim_security_header
*)decompress_data
;
587 rootdir
= (wim_directory_entry
*)(decompress_data
+ ((security
->len
+ 7) & 0xFFFFFFF8U
));
589 /* search winpeshl.exe dirent entry */
590 search
= search_replace_wim_dirent(decompress_data
, rootdir
);
593 debug("Failed to find replace file %p\n", search
);
594 grub_file_close(file
);
598 debug("find replace file at %p\n", search
);
600 grub_memcpy(&g_old_hash
, search
->hash
.sha1
, sizeof(wim_hash
));
602 debug("read lookup offset:%llu size:%llu\n", (ulonglong
)head
->lookup
.offset
, (ulonglong
)head
->lookup
.raw_size
);
603 lookup
= grub_malloc(head
->lookup
.raw_size
);
604 grub_file_seek(file
, head
->lookup
.offset
);
605 grub_file_read(file
, lookup
, head
->lookup
.raw_size
);
607 /* find and extact winpeshl.exe */
608 g_replace_look
= ventoy_find_look_entry(head
, lookup
, &g_old_hash
);
611 exe_len
= (grub_uint32_t
)g_replace_look
->resource
.raw_size
;
612 debug("find replace lookup entry_id:%ld raw_size:%u\n",
613 ((long)g_replace_look
- (long)lookup
) / sizeof(wim_lookup_entry
), exe_len
);
615 if (0 == ventoy_read_resource(file
, &(g_replace_look
->resource
), (void **)&(exe_data
)))
617 ventoy_cat_exe_file_data(exe_len
, exe_data
);
622 debug("failed to read replace file meta data %u\n", exe_len
);
627 debug("failed to find lookup entry for replace file 0x%02x 0x%02x\n", g_old_hash
.sha1
[0], g_old_hash
.sha1
[1]);
630 g_wim_data
.wim_raw_size
= (grub_uint32_t
)file
->size
;
631 g_wim_data
.wim_align_size
= ventoy_align(g_wim_data
.wim_raw_size
, 2048);
633 check_free(g_wim_data
.new_meta_data
, grub_free
);
634 g_wim_data
.new_meta_data
= decompress_data
;
635 g_wim_data
.new_meta_len
= head
->metadata
.raw_size
;
636 g_wim_data
.new_meta_align_len
= ventoy_align(g_wim_data
.new_meta_len
, 2048);
638 check_free(g_wim_data
.new_lookup_data
, grub_free
);
639 g_wim_data
.new_lookup_data
= (grub_uint8_t
*)lookup
;
640 g_wim_data
.new_lookup_len
= (grub_uint32_t
)head
->lookup
.raw_size
;
641 g_wim_data
.new_lookup_align_len
= ventoy_align(g_wim_data
.new_lookup_len
, 2048);
643 head
->metadata
.flags
= RESHDR_FLAG_METADATA
;
644 head
->metadata
.offset
= g_wim_data
.wim_align_size
+ g_wim_data
.bin_align_len
;
645 head
->metadata
.size_in_wim
= g_wim_data
.new_meta_len
;
646 head
->metadata
.raw_size
= g_wim_data
.new_meta_len
;
648 head
->lookup
.flags
= 0;
649 head
->lookup
.offset
= head
->metadata
.offset
+ g_wim_data
.new_meta_align_len
;
650 head
->lookup
.size_in_wim
= g_wim_data
.new_lookup_len
;
651 head
->lookup
.raw_size
= g_wim_data
.new_lookup_len
;
653 grub_file_close(file
);
655 debug("%s", "windows locate wim finish\n");
656 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
659 static grub_uint32_t
ventoy_get_override_chunk_num(void)
661 /* 1: block count in Partition Descriptor */
662 /* 2: file_size in file_entry or extend_file_entry */
663 /* 3: data_size and position in extend data short ad */
664 /* 4: new wim file header */
668 static void ventoy_windows_fill_override_data( grub_uint64_t isosize
, void *override
)
670 grub_uint32_t data32
;
671 grub_uint64_t data64
;
672 grub_uint64_t sector
;
673 grub_uint32_t new_wim_size
;
674 ventoy_override_chunk
*cur
;
676 sector
= (isosize
+ 2047) / 2048;
678 cur
= (ventoy_override_chunk
*)override
;
680 new_wim_size
= g_wim_data
.wim_align_size
+ g_wim_data
.bin_align_len
+
681 g_wim_data
.new_meta_align_len
+ g_wim_data
.new_lookup_align_len
;
683 if (g_wim_data
.iso_type
== 0)
685 ventoy_iso9660_override
*dirent
= (ventoy_iso9660_override
*)g_wim_data
.override_data
;
687 dirent
->first_sector
= (grub_uint32_t
)sector
;
688 dirent
->size
= new_wim_size
;
689 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
690 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
694 ventoy_udf_override
*udf
= (ventoy_udf_override
*)g_wim_data
.override_data
;
695 udf
->length
= new_wim_size
;
696 udf
->position
= (grub_uint32_t
)sector
- g_wim_data
.udf_start_block
;
699 //override 1: sector number in pd data
700 cur
->img_offset
= grub_udf_get_last_pd_size_offset();
701 cur
->override_size
= 4;
702 data32
= sector
- g_wim_data
.udf_start_block
+ (new_wim_size
/ 2048);
703 grub_memcpy(cur
->override_data
, &(data32
), 4);
705 //override 2: filesize in file_entry
707 cur
->img_offset
= g_wim_data
.fe_entry_size_offset
;
708 cur
->override_size
= 8;
709 data64
= new_wim_size
;
710 grub_memcpy(cur
->override_data
, &(data64
), 8);
712 /* override 3: position and length in extend data */
714 cur
->img_offset
= g_wim_data
.override_offset
;
715 cur
->override_size
= g_wim_data
.override_len
;
716 grub_memcpy(cur
->override_data
, g_wim_data
.override_data
, cur
->override_size
);
718 /* override 4: new wim file header */
720 cur
->img_offset
= g_wim_data
.file_offset
;
721 cur
->override_size
= sizeof(wim_header
);
722 grub_memcpy(cur
->override_data
, &(g_wim_data
.wim_header
), cur
->override_size
);
727 static void ventoy_windows_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
729 grub_uint64_t sector
;
730 grub_uint32_t offset
;
731 grub_uint32_t wim_secs
;
732 grub_uint32_t mem_secs
;
733 char *override
= NULL
;
734 ventoy_virt_chunk
*cur
= NULL
;
736 sector
= (isosize
+ 2047) / 2048;
737 offset
= sizeof(ventoy_virt_chunk
);
739 wim_secs
= g_wim_data
.wim_align_size
/ 2048;
740 mem_secs
= (g_wim_data
.bin_align_len
+ g_wim_data
.new_meta_align_len
+ g_wim_data
.new_lookup_align_len
) / 2048;
742 override
= (char *)chain
+ chain
->virt_chunk_offset
;
743 cur
= (ventoy_virt_chunk
*)override
;
745 cur
->remap_sector_start
= sector
;
746 cur
->remap_sector_end
= cur
->remap_sector_start
+ wim_secs
;
747 cur
->org_sector_start
= (grub_uint32_t
)(g_wim_data
.file_offset
/ 2048);
749 cur
->mem_sector_start
= cur
->remap_sector_end
;
750 cur
->mem_sector_end
= cur
->mem_sector_start
+ mem_secs
;
751 cur
->mem_sector_offset
= offset
;
753 grub_memcpy(override
+ offset
, g_wim_data
.jump_bin_data
, g_wim_data
.bin_raw_len
);
754 offset
+= g_wim_data
.bin_align_len
;
756 grub_memcpy(override
+ offset
, g_wim_data
.new_meta_data
, g_wim_data
.new_meta_len
);
757 offset
+= g_wim_data
.new_meta_align_len
;
759 grub_memcpy(override
+ offset
, g_wim_data
.new_lookup_data
, g_wim_data
.new_lookup_len
);
760 offset
+= g_wim_data
.new_lookup_align_len
;
762 chain
->virt_img_size_in_bytes
+= g_wim_data
.wim_align_size
+
763 g_wim_data
.bin_align_len
+
764 g_wim_data
.new_meta_align_len
+
765 g_wim_data
.new_lookup_align_len
;
769 static int ventoy_windows_drive_map(ventoy_chain_head
*chain
)
773 debug("drive map begin <%p> ...\n", chain
);
775 if (chain
->disk_drive
== 0x80)
777 disk
= grub_disk_open("hd1");
780 grub_disk_close(disk
);
781 debug("drive map needed %p\n", disk
);
782 chain
->drive_map
= 0x81;
786 debug("failed to open disk %s\n", "hd1");
791 debug("no need to map 0x%x\n", chain
->disk_drive
);
797 grub_err_t
ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
799 int unknown_image
= 0;
800 int ventoy_compatible
= 0;
801 grub_uint32_t size
= 0;
802 grub_uint64_t isosize
= 0;
803 grub_uint32_t boot_catlog
= 0;
804 grub_uint32_t img_chunk_size
= 0;
805 grub_uint32_t override_size
= 0;
806 grub_uint32_t virt_chunk_size
= 0;
809 const char *pLastChain
= NULL
;
810 const char *compatible
;
811 ventoy_chain_head
*chain
;
817 debug("chain data begin <%s> ...\n", args
[0]);
819 compatible
= grub_env_get("ventoy_compatible");
820 if (compatible
&& compatible
[0] == 'Y')
822 ventoy_compatible
= 1;
825 if (NULL
== g_img_chunk_list
.chunk
)
827 grub_printf("ventoy not ready\n");
831 if (0 == ventoy_compatible
&& g_wim_data
.new_meta_data
== NULL
)
834 debug("Warning: %s was not recognized by Ventoy\n", args
[0]);
837 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
843 isosize
= file
->size
;
845 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
848 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
850 grub_env_set("LoadIsoEfiDriver", "on");
855 if (ventoy_is_efi_os())
857 grub_env_set("LoadIsoEfiDriver", "on");
861 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
865 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
867 if (ventoy_compatible
|| unknown_image
)
869 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
873 override_size
= ventoy_get_override_chunk_num() * sizeof(ventoy_override_chunk
);
874 virt_chunk_size
= sizeof(ventoy_virt_chunk
) + g_wim_data
.bin_align_len
+
875 g_wim_data
.new_meta_align_len
+ g_wim_data
.new_lookup_align_len
;;
876 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
879 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
882 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
885 debug("free last chain memory %p\n", chain
);
890 chain
= grub_malloc(size
);
893 grub_printf("Failed to alloc chain memory size %u\n", size
);
894 grub_file_close(file
);
898 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
899 grub_env_set("vtoy_chain_mem_addr", envbuf
);
900 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
901 grub_env_set("vtoy_chain_mem_size", envbuf
);
903 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
905 /* part 1: os parameter */
906 ventoy_fill_os_param(file
, &(chain
->os_param
));
908 if (g_wim_data
.jump_bin_data
&& g_wim_data
.new_meta_data
)
910 ventoy_update_before_chain(&(chain
->os_param
), args
[0]);
913 /* part 2: chain head */
914 disk
= file
->device
->disk
;
915 chain
->disk_drive
= disk
->id
;
916 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
917 chain
->real_img_size_in_bytes
= file
->size
;
918 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
919 chain
->boot_catalog
= boot_catlog
;
921 if (!ventoy_is_efi_os())
923 grub_file_seek(file
, boot_catlog
* 2048);
924 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
927 /* part 3: image chunk */
928 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
929 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
930 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
932 if (ventoy_compatible
|| unknown_image
)
937 if (g_wim_data
.new_meta_data
== NULL
)
942 /* part 4: override chunk */
943 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
944 chain
->override_chunk_num
= ventoy_get_override_chunk_num();
945 ventoy_windows_fill_override_data(isosize
, (char *)chain
+ chain
->override_chunk_offset
);
947 /* part 5: virt chunk */
948 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
949 chain
->virt_chunk_num
= 1;
950 ventoy_windows_fill_virt_data(isosize
, chain
);
952 if (ventoy_is_efi_os() == 0)
954 ventoy_windows_drive_map(chain
);
957 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);