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/>.
20 #include <grub/types.h>
21 #include <grub/misc.h>
25 #include <grub/disk.h>
26 #include <grub/device.h>
27 #include <grub/term.h>
28 #include <grub/partition.h>
29 #include <grub/file.h>
30 #include <grub/normal.h>
31 #include <grub/extcmd.h>
32 #include <grub/datetime.h>
33 #include <grub/i18n.h>
35 #include <grub/time.h>
37 #include <grub/elfload.h>
38 #include <grub/ventoy.h>
39 #include "ventoy_def.h"
41 GRUB_MOD_LICENSE ("GPLv3+");
43 char g_ko_mod_path
[256];
44 int g_conf_new_len
= 0;
45 char *g_conf_new_data
= NULL
;
47 int g_mod_new_len
= 0;
48 char *g_mod_new_data
= NULL
;
50 int g_mod_search_magic
= 0;
51 int g_unix_vlnk_boot
= 0;
53 int g_ko_fillmap_len
= 0;
54 char *g_ko_fillmap_data
= NULL
;
56 grub_uint64_t g_mod_override_offset
= 0;
57 grub_uint64_t g_conf_override_offset
= 0;
59 static int ventoy_get_file_override(const char *filename
, grub_uint64_t
*offset
)
65 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", filename
);
71 *offset
= grub_iso9660_get_last_file_dirent_pos(file
) + 2;
73 grub_file_close(file
);
78 static grub_uint32_t
ventoy_unix_get_override_chunk_count(void)
80 grub_uint32_t count
= 0;
82 if (g_conf_new_len
> 0)
87 if (g_mod_new_len
> 0)
92 if (g_ko_fillmap_len
> 0)
94 count
+= (g_ko_fillmap_len
/ 512);
95 if ((g_ko_fillmap_len
% 512) > 0)
104 static grub_uint32_t
ventoy_unix_get_virt_chunk_count(void)
106 grub_uint32_t count
= 0;
108 if (g_conf_new_len
> 0)
113 if (g_mod_new_len
> 0)
120 static grub_uint32_t
ventoy_unix_get_virt_chunk_size(void)
124 size
= sizeof(ventoy_virt_chunk
) * ventoy_unix_get_virt_chunk_count();
126 if (g_conf_new_len
> 0)
128 size
+= ventoy_align_2k(g_conf_new_len
);
131 if (g_mod_new_len
> 0)
133 size
+= ventoy_align_2k(g_mod_new_len
);
139 static void ventoy_unix_fill_map_data(ventoy_chain_head
*chain
, struct g_ventoy_map
*map
)
142 ventoy_img_chunk
*chunk
= NULL
;
144 debug("Fill unix map data: <%llu> <%u> %p\n",
145 (unsigned long long)chain
->os_param
.vtoy_disk_size
, g_img_chunk_list
.cur_chunk
, map
);
147 map
->magic1
[0] = map
->magic2
[0] = VENTOY_UNIX_SEG_MAGIC0
;
148 map
->magic1
[1] = map
->magic2
[1] = VENTOY_UNIX_SEG_MAGIC1
;
149 map
->magic1
[2] = map
->magic2
[2] = VENTOY_UNIX_SEG_MAGIC2
;
150 map
->magic1
[3] = map
->magic2
[3] = VENTOY_UNIX_SEG_MAGIC3
;
152 map
->disksize
= chain
->os_param
.vtoy_disk_size
;
153 grub_memcpy(map
->diskuuid
, chain
->os_param
.vtoy_disk_guid
, 16);
155 map
->segnum
= g_img_chunk_list
.cur_chunk
;
156 if (g_img_chunk_list
.cur_chunk
> VENTOY_UNIX_MAX_SEGNUM
)
158 debug("####[FAIL] Too many segments for the ISO file %u\n", g_img_chunk_list
.cur_chunk
);
159 map
->segnum
= VENTOY_UNIX_MAX_SEGNUM
;
162 for (i
= 0; i
< (grub_uint32_t
)(map
->segnum
); i
++)
164 chunk
= g_img_chunk_list
.chunk
+ i
;
165 map
->seglist
[i
].seg_start_bytes
= chunk
->disk_start_sector
* 512ULL;
166 map
->seglist
[i
].seg_end_bytes
= (chunk
->disk_end_sector
+ 1) * 512ULL;
170 static void ventoy_unix_fill_override_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
175 grub_uint64_t offset
;
176 grub_uint64_t sector
;
177 ventoy_override_chunk
*cur
;
178 ventoy_iso9660_override
*dirent
;
180 sector
= (isosize
+ 2047) / 2048;
182 cur
= (ventoy_override_chunk
*)((char *)chain
+ chain
->override_chunk_offset
);
184 if (g_conf_new_len
> 0)
187 cur
->img_offset
= g_conf_override_offset
;
188 cur
->override_size
= sizeof(ventoy_iso9660_override
);
189 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
190 dirent
->first_sector
= (grub_uint32_t
)sector
;
191 dirent
->size
= (grub_uint32_t
)g_conf_new_len
;
192 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
193 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
194 sector
+= (dirent
->size
+ 2047) / 2048;
198 if (g_mod_new_len
> 0)
201 cur
->img_offset
= g_mod_override_offset
;
202 cur
->override_size
= sizeof(ventoy_iso9660_override
);
203 dirent
= (ventoy_iso9660_override
*)cur
->override_data
;
204 dirent
->first_sector
= (grub_uint32_t
)sector
;
205 dirent
->size
= (grub_uint32_t
)g_mod_new_len
;
206 dirent
->first_sector_be
= grub_swap_bytes32(dirent
->first_sector
);
207 dirent
->size_be
= grub_swap_bytes32(dirent
->size
);
208 sector
+= (dirent
->size
+ 2047) / 2048;
212 if (g_ko_fillmap_len
> 0)
214 data
= g_ko_fillmap_data
;
215 offset
= g_mod_override_offset
;
217 ventoy_unix_fill_map_data(chain
, (struct g_ventoy_map
*)data
);
219 for (i
= 0; i
< g_ko_fillmap_len
/ 512; i
++)
221 cur
->img_offset
= offset
;
222 cur
->override_size
= 512;
223 grub_memcpy(cur
->override_data
, data
, 512);
230 left
= (g_ko_fillmap_len
% 512);
233 cur
->img_offset
= offset
;
234 cur
->override_size
= left
;
235 grub_memcpy(cur
->override_data
, data
, left
);
245 static void ventoy_unix_fill_virt_data( grub_uint64_t isosize
, ventoy_chain_head
*chain
)
247 grub_uint64_t sector
;
248 grub_uint32_t offset
;
249 grub_uint32_t data_secs
;
251 ventoy_virt_chunk
*cur
;
253 override
= (char *)chain
+ chain
->virt_chunk_offset
;
254 cur
= (ventoy_virt_chunk
*)override
;
256 sector
= (isosize
+ 2047) / 2048;
257 offset
= 2 * sizeof(ventoy_virt_chunk
);
259 if (g_conf_new_len
> 0)
261 ventoy_unix_fill_virt(g_conf_new_data
, g_conf_new_len
);
264 if (g_mod_new_len
> 0)
266 if (g_mod_search_magic
> 0)
268 ventoy_unix_fill_map_data(chain
, (struct g_ventoy_map
*)(g_mod_new_data
+ g_mod_search_magic
));
271 ventoy_unix_fill_virt(g_mod_new_data
, g_mod_new_len
);
277 static int ventoy_freebsd_append_conf(char *buf
, const char *isopath
, const char *alias
)
284 const char *val
= NULL
;
285 ventoy_img_chunk
*chunk
;
286 grub_uint8_t disk_sig
[4];
287 grub_uint8_t disk_guid
[16];
289 debug("ventoy_freebsd_append_conf %s\n", isopath
);
291 isofile
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", isopath
);
297 vtoy_ssprintf(buf
, pos
, "ventoy_load=\"%s\"\n", "YES");
298 vtoy_ssprintf(buf
, pos
, "ventoy_name=\"%s\"\n", g_ko_mod_path
);
302 vtoy_ssprintf(buf
, pos
, "hint.ventoy.0.alias=\"%s\"\n", alias
);
305 if (g_unix_vlnk_boot
)
307 vtoy_ssprintf(buf
, pos
, "hint.ventoy.0.vlnk=%d\n", 1);
310 val
= ventoy_get_env("VTOY_UNIX_REMOUNT");
311 if (val
&& val
[0] == '1' && val
[1] == 0)
313 vtoy_ssprintf(buf
, pos
, "hint.ventoy.0.remount=%d\n", 1);
316 if (g_mod_search_magic
)
318 debug("hint.ventoy NO need\n");
322 debug("Fill hint.ventoy info\n");
324 disk
= isofile
->device
->disk
;
326 ventoy_get_disk_guid(isofile
->name
, disk_guid
, disk_sig
);
328 for (i
= 0; i
< 16; i
++)
330 grub_snprintf(uuid
+ i
* 2, sizeof(uuid
), "%02x", disk_guid
[i
]);
333 vtoy_ssprintf(buf
, pos
, "hint.ventoy.0.disksize=%llu\n", (ulonglong
)(disk
->total_sectors
* (1 << disk
->log_sector_size
)));
334 vtoy_ssprintf(buf
, pos
, "hint.ventoy.0.diskuuid=\"%s\"\n", uuid
);
335 vtoy_ssprintf(buf
, pos
, "hint.ventoy.0.disksignature=%02x%02x%02x%02x\n", disk_sig
[0], disk_sig
[1], disk_sig
[2], disk_sig
[3]);
336 vtoy_ssprintf(buf
, pos
, "hint.ventoy.0.segnum=%u\n", g_img_chunk_list
.cur_chunk
);
338 for (i
= 0; i
< g_img_chunk_list
.cur_chunk
; i
++)
340 chunk
= g_img_chunk_list
.chunk
+ i
;
341 vtoy_ssprintf(buf
, pos
, "hint.ventoy.%u.seg=\"0x%llx@0x%llx\"\n",
342 i
, (ulonglong
)(chunk
->disk_start_sector
* 512),
343 (ulonglong
)((chunk
->disk_end_sector
+ 1) * 512));
347 grub_file_close(isofile
);
351 static int ventoy_dragonfly_append_conf(char *buf
, const char *isopath
)
355 debug("ventoy_dragonfly_append_conf %s\n", isopath
);
357 vtoy_ssprintf(buf
, pos
, "tmpfs_load=\"%s\"\n", "YES");
358 vtoy_ssprintf(buf
, pos
, "dm_target_linear_load=\"%s\"\n", "YES");
359 vtoy_ssprintf(buf
, pos
, "initrd.img_load=\"%s\"\n", "YES");
360 vtoy_ssprintf(buf
, pos
, "initrd.img_type=\"%s\"\n", "md_image");
361 vtoy_ssprintf(buf
, pos
, "vfs.root.mountfrom=\"%s\"\n", "ufs:md0s0");
366 grub_err_t
ventoy_cmd_unix_reset(grub_extcmd_context_t ctxt
, int argc
, char **args
)
372 g_unix_vlnk_boot
= 0;
373 g_mod_search_magic
= 0;
376 g_mod_override_offset
= 0;
377 g_conf_override_offset
= 0;
378 g_ko_fillmap_len
= 0;
380 check_free(g_mod_new_data
, grub_free
);
381 check_free(g_conf_new_data
, grub_free
);
382 check_free(g_ko_fillmap_data
, grub_free
);
384 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
387 grub_err_t
ventoy_cmd_unix_check_vlnk(grub_extcmd_context_t ctxt
, int argc
, char **args
)
398 file
= grub_file_open(args
[0], VENTOY_FILE_TYPE
);
401 g_unix_vlnk_boot
= file
->vlnk
;
402 grub_file_close(file
);
405 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
408 grub_err_t
ventoy_cmd_parse_freenas_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
411 const char *ver
= NULL
;
413 VTOY_JSON
*json
= NULL
;
418 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
421 debug("Failed to open file %s\n", args
[0]);
425 buf
= grub_malloc(file
->size
+ 2);
428 grub_file_close(file
);
431 grub_file_read(file
, buf
, file
->size
);
434 json
= vtoy_json_create();
440 if (vtoy_json_parse(json
, buf
))
445 ver
= vtoy_json_get_string_ex(json
->pstChild
, "Version");
448 debug("NAS version:<%s>\n", ver
);
449 if (grub_strncmp(ver
, "TrueNAS-", 8) == 0)
453 ventoy_set_env(args
[1], ver
);
457 debug("NAS version:<%s>\n", "NOT FOUND");
458 grub_env_unset(args
[1]);
462 grub_check_free(buf
);
463 check_free(json
, vtoy_json_destroy
);
464 grub_file_close(file
);
466 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
469 grub_err_t
ventoy_cmd_unix_freebsd_ver(grub_extcmd_context_t ctxt
, int argc
, char **args
)
474 char *nextline
= NULL
;
480 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[0]);
483 debug("Failed to open file %s\n", args
[0]);
487 buf
= grub_zalloc(file
->size
+ 2);
490 grub_file_close(file
);
493 grub_file_read(file
, buf
, file
->size
);
495 for (start
= buf
; start
; start
= nextline
)
497 if (grub_strncmp(start
, "USERLAND_VERSION", 16) == 0)
500 while (*nextline
&& *nextline
!= '\r' && *nextline
!= '\n')
508 nextline
= ventoy_get_line(start
);
513 debug("freebsd version:<%s>\n", start
);
514 ventoy_set_env(args
[1], start
);
518 debug("freebsd version:<%s>\n", "NOT FOUND");
519 grub_env_unset(args
[1]);
523 grub_file_close(file
);
525 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
528 grub_err_t
ventoy_cmd_unix_freebsd_ver_elf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
532 grub_elf_t elf
= NULL
;
533 grub_off_t offset
= 0;
534 grub_uint32_t len
= 0;
546 debug("Invalid argc %d\n", argc
);
550 data
= grub_zalloc(8192);
556 elf
= grub_elf_open(args
[0], GRUB_FILE_TYPE_LINUX_INITRD
);
559 debug("Failed to open file %s\n", args
[0]);
563 if (args
[1][0] == '6')
565 Elf64_Ehdr
*e
= &(elf
->ehdr
.ehdr64
);
571 h
= hdr
= grub_zalloc(e
->e_shnum
* e
->e_shentsize
);
577 debug("read section header %u %u %u\n", e
->e_shnum
, e
->e_shentsize
, e
->e_shstrndx
);
578 grub_file_seek(elf
->file
, e
->e_shoff
);
579 grub_file_read(elf
->file
, h
, e
->e_shnum
* e
->e_shentsize
);
581 s
= (Elf64_Shdr
*)((char *)h
+ e
->e_shstrndx
* e
->e_shentsize
);
582 str
= grub_malloc(s
->sh_size
+ 1);
589 debug("read string table %u %u\n", (grub_uint32_t
)s
->sh_offset
, (grub_uint32_t
)s
->sh_size
);
590 grub_file_seek(elf
->file
, s
->sh_offset
);
591 grub_file_read(elf
->file
, str
, s
->sh_size
);
593 for (t
= h
, i
= 0; i
< e
->e_shnum
; i
++)
595 if (grub_strcmp(str
+ t
->sh_name
, ".data") == 0)
597 offset
= t
->sh_offset
;
599 debug("find .data section at %u %u\n", (grub_uint32_t
)offset
, len
);
602 t
= (Elf64_Shdr
*)((char *)t
+ e
->e_shentsize
);
607 Elf32_Ehdr
*e
= &(elf
->ehdr
.ehdr32
);
613 h
= hdr
= grub_zalloc(e
->e_shnum
* e
->e_shentsize
);
619 debug("read section header %u %u %u\n", e
->e_shnum
, e
->e_shentsize
, e
->e_shstrndx
);
620 grub_file_seek(elf
->file
, e
->e_shoff
);
621 grub_file_read(elf
->file
, h
, e
->e_shnum
* e
->e_shentsize
);
623 s
= (Elf32_Shdr
*)((char *)h
+ e
->e_shstrndx
* e
->e_shentsize
);
624 str
= grub_malloc(s
->sh_size
+ 1);
631 debug("read string table %u %u\n", (grub_uint32_t
)s
->sh_offset
, (grub_uint32_t
)s
->sh_size
);
632 grub_file_seek(elf
->file
, s
->sh_offset
);
633 grub_file_read(elf
->file
, str
, s
->sh_size
);
635 for (t
= h
, i
= 0; i
< e
->e_shnum
; i
++)
637 if (grub_strcmp(str
+ t
->sh_name
, ".data") == 0)
639 offset
= t
->sh_offset
;
641 debug("find .data section at %u %u\n", (grub_uint32_t
)offset
, len
);
644 t
= (Elf32_Shdr
*)((char *)t
+ e
->e_shentsize
);
648 if (offset
== 0 || len
== 0)
650 debug(".data section not found %s\n", args
[0]);
654 grub_file_seek(elf
->file
, offset
+ len
- 8192);
655 grub_file_read(elf
->file
, data
, 8192);
657 for (j
= 0; j
< 8192 - 12; j
++)
659 if (grub_strncmp(data
+ j
, "@(#)FreeBSD ", 12) == 0)
661 for (k
= j
+ 12; k
< 8192; k
++)
663 if (0 == grub_isdigit(data
[k
]) && data
[k
] != '.')
670 grub_snprintf(ver
, sizeof(ver
), "%s", data
+ j
+ 12);
677 k
= (int)grub_strtoul(ver
, NULL
, 10);
678 debug("freebsd version:<%s> <%d.x>\n", ver
, k
);
679 grub_snprintf(ver
, sizeof(ver
), "%d.x", k
);
680 ventoy_set_env(args
[2], ver
);
684 debug("freebsd version:<%s>\n", "NOT FOUND");
688 grub_check_free(str
);
689 grub_check_free(hdr
);
690 grub_check_free(data
);
691 check_free(elf
, grub_elf_close
);
693 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
696 grub_err_t
ventoy_cmd_unix_replace_grub_conf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
702 const char *val
= NULL
;
703 grub_uint64_t offset
;
706 const char *confile
= NULL
;
707 const char * loader_conf
[] =
709 "/boot/grub/grub.cfg",
714 if (argc
!= 1 && argc
!= 2)
716 debug("Replace conf invalid argc %d\n", argc
);
720 for (i
= 0; i
< sizeof(loader_conf
) / sizeof(loader_conf
[0]); i
++)
722 if (ventoy_get_file_override(loader_conf
[i
], &offset
) == 0)
724 confile
= loader_conf
[i
];
725 g_conf_override_offset
= offset
;
732 debug("Can't find grub.cfg file from %u locations\n", i
);
736 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "(loop)/%s", confile
);
739 debug("Failed to open %s \n", confile
);
743 debug("old grub2 conf file size:%d\n", (int)file
->size
);
745 data
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
748 grub_file_close(file
);
752 grub_file_read(file
, data
, file
->size
);
753 grub_file_close(file
);
755 g_conf_new_data
= data
;
756 g_conf_new_len
= (int)file
->size
;
758 pos
= grub_strstr(data
, "kfreebsd /boot/kernel/kernel");
761 pos
+= grub_strlen("kfreebsd /boot/kernel/kernel");
762 if (grub_strncmp(pos
, ".gz", 3) == 0)
769 vtoy_ssprintf(extcfg
, len
, ";kfreebsd_module_elf %s; set kFreeBSD.hint.ventoy.0.alias=\"%s\"", args
[0], args
[1]);
773 vtoy_ssprintf(extcfg
, len
, ";kfreebsd_module_elf %s", args
[0]);
776 if (g_unix_vlnk_boot
)
778 vtoy_ssprintf(extcfg
, len
, ";set kFreeBSD.hint.ventoy.0.vlnk=%d", 1);
781 val
= ventoy_get_env("VTOY_UNIX_REMOUNT");
782 if (val
&& val
[0] == '1' && val
[1] == 0)
784 vtoy_ssprintf(extcfg
, len
, ";set kFreeBSD.hint.ventoy.0.remount=%d", 1);
787 grub_memmove(pos
+ len
, pos
, (int)(file
->size
- (pos
- data
)));
788 grub_memcpy(pos
, extcfg
, len
);
789 g_conf_new_len
+= len
;
793 debug("no kfreebsd found\n");
796 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
799 grub_err_t
ventoy_cmd_unix_replace_conf(grub_extcmd_context_t ctxt
, int argc
, char **args
)
803 grub_uint64_t offset
;
805 const char *confile
= NULL
;
806 const char * loader_conf
[] =
809 "/boot/defaults/loader.conf",
814 if (argc
!= 2 && argc
!= 3)
816 debug("Replace conf invalid argc %d\n", argc
);
820 for (i
= 0; i
< sizeof(loader_conf
) / sizeof(loader_conf
[0]); i
++)
822 if (ventoy_get_file_override(loader_conf
[i
], &offset
) == 0)
824 confile
= loader_conf
[i
];
825 g_conf_override_offset
= offset
;
832 debug("Can't find loader.conf file from %u locations\n", i
);
836 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "(loop)/%s", confile
);
839 debug("Failed to open %s \n", confile
);
843 debug("old conf file <%s> size:%d\n", confile
, (int)file
->size
);
845 data
= grub_malloc(VTOY_MAX_SCRIPT_BUF
);
848 grub_file_close(file
);
852 grub_file_read(file
, data
, file
->size
);
853 grub_file_close(file
);
855 g_conf_new_data
= data
;
856 g_conf_new_len
= (int)file
->size
;
858 if (grub_strcmp(args
[0], "FreeBSD") == 0)
860 g_conf_new_len
+= ventoy_freebsd_append_conf(data
+ file
->size
, args
[1], (argc
> 2) ? args
[2] : NULL
);
862 else if (grub_strcmp(args
[0], "DragonFly") == 0)
864 g_conf_new_len
+= ventoy_dragonfly_append_conf(data
+ file
->size
, args
[1]);
867 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
870 static int ventoy_unix_search_magic(char *data
, int len
)
873 grub_uint32_t
*magic
= NULL
;
875 for (i
= 0; i
< len
; i
+= 4096)
877 magic
= (grub_uint32_t
*)(data
+ i
);
878 if (magic
[0] == VENTOY_UNIX_SEG_MAGIC0
&& magic
[1] == VENTOY_UNIX_SEG_MAGIC1
&&
879 magic
[2] == VENTOY_UNIX_SEG_MAGIC2
&& magic
[3] == VENTOY_UNIX_SEG_MAGIC3
)
881 debug("unix find search magic at 0x%x loop:%d\n", i
, (i
>> 12));
882 g_mod_search_magic
= i
;
887 debug("unix can not find search magic\n");
891 grub_err_t
ventoy_cmd_unix_replace_ko(grub_extcmd_context_t ctxt
, int argc
, char **args
)
894 grub_uint64_t offset
;
901 debug("Replace ko invalid argc %d\n", argc
);
905 debug("replace ko %s\n", args
[0]);
907 if (ventoy_get_file_override(args
[0], &offset
) == 0)
909 grub_snprintf(g_ko_mod_path
, sizeof(g_ko_mod_path
), "%s", args
[0]);
910 g_mod_override_offset
= offset
;
914 debug("Can't find replace ko file from %s\n", args
[0]);
918 file
= ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD
, "%s", args
[1]);
921 debug("Failed to open %s \n", args
[1]);
925 debug("new ko file size:%d\n", (int)file
->size
);
927 data
= grub_malloc(file
->size
);
930 debug("Failed to alloc memory for new ko %d\n", (int)file
->size
);
931 grub_file_close(file
);
935 grub_file_read(file
, data
, file
->size
);
936 grub_file_close(file
);
938 g_mod_new_data
= data
;
939 g_mod_new_len
= (int)file
->size
;
941 ventoy_unix_search_magic(g_mod_new_data
, g_mod_new_len
);
943 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
946 grub_err_t
ventoy_cmd_unix_ko_fillmap(grub_extcmd_context_t ctxt
, int argc
, char **args
)
950 grub_uint32_t magic
[4];
957 debug("Fillmap ko invalid argc %d\n", argc
);
961 debug("Fillmap ko %s\n", args
[0]);
963 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "(loop)%s", args
[0]);
966 grub_file_read(file
, magic
, 4); /* read for trigger */
967 g_mod_override_offset
= grub_iso9660_get_last_read_pos(file
);
971 debug("Can't find replace ko file from %s\n", args
[0]);
975 for (i
= 0; i
< (int)(file
->size
); i
+= 65536)
978 grub_file_seek(file
, i
);
979 grub_file_read(file
, magic
, sizeof(magic
));
981 if (magic
[0] == VENTOY_UNIX_SEG_MAGIC0
&& magic
[1] == VENTOY_UNIX_SEG_MAGIC1
&&
982 magic
[2] == VENTOY_UNIX_SEG_MAGIC2
&& magic
[3] == VENTOY_UNIX_SEG_MAGIC3
)
984 debug("unix find search magic at 0x%x loop:%d\n", i
, (i
>> 16));
985 g_mod_override_offset
+= i
;
990 len
= (grub_uint32_t
)OFFSET_OF(struct g_ventoy_map
, seglist
) +
991 (sizeof(struct g_ventoy_seg
) * g_img_chunk_list
.cur_chunk
);
993 g_ko_fillmap_len
= (int)len
;
994 g_ko_fillmap_data
= grub_malloc(len
);
995 if (!g_ko_fillmap_data
)
997 g_ko_fillmap_len
= 0;
998 debug("Failed to malloc fillmap data\n");
1001 debug("Fillmap ko segnum:%u, override len:%u data:%p\n", g_img_chunk_list
.cur_chunk
, len
, g_ko_fillmap_data
);
1003 grub_file_close(file
);
1004 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1007 grub_err_t
ventoy_cmd_unix_fill_image_desc(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1011 grub_uint32_t memsize
;
1012 ventoy_image_desc
*desc
;
1013 grub_uint8_t flag
[32] = {
1014 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
1015 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
1022 debug("ventoy_cmd_unix_fill_image_desc %p\n", g_mod_new_data
);
1024 if (!g_mod_new_data
)
1029 byte
= (grub_uint8_t
*)g_mod_new_data
;
1030 for (i
= 0; i
< g_mod_new_len
- 32; i
+= 16)
1032 if (byte
[i
] == 0xFF && byte
[i
+ 1] == 0xEE)
1034 if (grub_memcmp(flag
, byte
+ i
, 32) == 0)
1036 debug("Find position flag at %d(0x%x)\n", i
, i
);
1042 if (i
>= g_mod_new_len
- 32)
1044 debug("Failed to find position flag %d\n", i
);
1048 desc
= (ventoy_image_desc
*)(byte
+ i
);
1049 desc
->disk_size
= g_ventoy_disk_size
;
1050 desc
->part1_size
= g_ventoy_disk_part_size
[0];
1051 grub_memcpy(desc
->disk_uuid
, g_ventoy_part_info
->MBR
.BootCode
+ 0x180, 16);
1052 grub_memcpy(desc
->disk_signature
, g_ventoy_part_info
->MBR
.BootCode
+ 0x1B8, 4);
1054 desc
->img_chunk_count
= g_img_chunk_list
.cur_chunk
;
1055 memsize
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1057 debug("image chunk count:%u memsize:%u\n", desc
->img_chunk_count
, memsize
);
1059 if (memsize
>= VTOY_SIZE_1MB
* 8)
1061 grub_printf("image chunk count:%u memsize:%u too big\n", desc
->img_chunk_count
, memsize
);
1065 grub_memcpy(desc
+ 1, g_img_chunk_list
.chunk
, memsize
);
1068 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1071 grub_err_t
ventoy_cmd_unix_gzip_newko(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1080 debug("ventoy_cmd_unix_gzip_newko %p\n", g_mod_new_data
);
1082 if (!g_mod_new_data
)
1087 buf
= grub_malloc(g_mod_new_len
);
1093 newlen
= ventoy_gzip_compress(g_mod_new_data
, g_mod_new_len
, buf
, g_mod_new_len
);
1095 grub_free(g_mod_new_data
);
1097 debug("gzip org len:%d newlen:%d\n", g_mod_new_len
, newlen
);
1099 g_mod_new_data
= (char *)buf
;
1100 g_mod_new_len
= newlen
;
1103 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);
1106 grub_err_t
ventoy_cmd_unix_chain_data(grub_extcmd_context_t ctxt
, int argc
, char **args
)
1108 int ventoy_compatible
= 0;
1109 grub_uint32_t size
= 0;
1110 grub_uint64_t isosize
= 0;
1111 grub_uint32_t boot_catlog
= 0;
1112 grub_uint32_t img_chunk_size
= 0;
1113 grub_uint32_t override_count
= 0;
1114 grub_uint32_t override_size
= 0;
1115 grub_uint32_t virt_chunk_size
= 0;
1118 const char *pLastChain
= NULL
;
1119 const char *compatible
;
1120 ventoy_chain_head
*chain
;
1126 compatible
= grub_env_get("ventoy_compatible");
1127 if (compatible
&& compatible
[0] == 'Y')
1129 ventoy_compatible
= 1;
1132 if (NULL
== g_img_chunk_list
.chunk
)
1134 grub_printf("ventoy not ready\n");
1138 file
= ventoy_grub_file_open(VENTOY_FILE_TYPE
, "%s", args
[0]);
1144 isosize
= file
->size
;
1146 boot_catlog
= ventoy_get_iso_boot_catlog(file
);
1149 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file
, boot_catlog
)))
1151 grub_env_set("LoadIsoEfiDriver", "on");
1156 if (ventoy_is_efi_os())
1158 grub_env_set("LoadIsoEfiDriver", "on");
1162 return grub_error(GRUB_ERR_BAD_ARGUMENT
, "File %s is not bootable", args
[0]);
1166 img_chunk_size
= g_img_chunk_list
.cur_chunk
* sizeof(ventoy_img_chunk
);
1168 if (ventoy_compatible
)
1170 size
= sizeof(ventoy_chain_head
) + img_chunk_size
;
1174 override_count
= ventoy_unix_get_override_chunk_count();
1175 override_size
= override_count
* sizeof(ventoy_override_chunk
);
1177 virt_chunk_size
= ventoy_unix_get_virt_chunk_size();
1178 size
= sizeof(ventoy_chain_head
) + img_chunk_size
+ override_size
+ virt_chunk_size
;
1181 pLastChain
= grub_env_get("vtoy_chain_mem_addr");
1184 chain
= (ventoy_chain_head
*)grub_strtoul(pLastChain
, NULL
, 16);
1187 debug("free last chain memory %p\n", chain
);
1192 chain
= ventoy_alloc_chain(size
);
1195 grub_printf("Failed to alloc chain unix memory size %u\n", size
);
1196 grub_file_close(file
);
1200 grub_snprintf(envbuf
, sizeof(envbuf
), "0x%lx", (unsigned long)chain
);
1201 grub_env_set("vtoy_chain_mem_addr", envbuf
);
1202 grub_snprintf(envbuf
, sizeof(envbuf
), "%u", size
);
1203 grub_env_set("vtoy_chain_mem_size", envbuf
);
1205 grub_memset(chain
, 0, sizeof(ventoy_chain_head
));
1207 /* part 1: os parameter */
1208 g_ventoy_chain_type
= ventoy_chain_linux
;
1209 ventoy_fill_os_param(file
, &(chain
->os_param
));
1211 /* part 2: chain head */
1212 disk
= file
->device
->disk
;
1213 chain
->disk_drive
= disk
->id
;
1214 chain
->disk_sector_size
= (1 << disk
->log_sector_size
);
1215 chain
->real_img_size_in_bytes
= file
->size
;
1216 chain
->virt_img_size_in_bytes
= (file
->size
+ 2047) / 2048 * 2048;
1217 chain
->boot_catalog
= boot_catlog
;
1219 if (!ventoy_is_efi_os())
1221 grub_file_seek(file
, boot_catlog
* 2048);
1222 grub_file_read(file
, chain
->boot_catalog_sector
, sizeof(chain
->boot_catalog_sector
));
1225 /* part 3: image chunk */
1226 chain
->img_chunk_offset
= sizeof(ventoy_chain_head
);
1227 chain
->img_chunk_num
= g_img_chunk_list
.cur_chunk
;
1228 grub_memcpy((char *)chain
+ chain
->img_chunk_offset
, g_img_chunk_list
.chunk
, img_chunk_size
);
1230 if (ventoy_compatible
)
1235 /* part 4: override chunk */
1236 chain
->override_chunk_offset
= chain
->img_chunk_offset
+ img_chunk_size
;
1237 chain
->override_chunk_num
= override_count
;
1238 ventoy_unix_fill_override_data(isosize
, chain
);
1240 /* part 5: virt chunk */
1241 chain
->virt_chunk_offset
= chain
->override_chunk_offset
+ override_size
;
1242 chain
->virt_chunk_num
= ventoy_unix_get_virt_chunk_count();
1243 ventoy_unix_fill_virt_data(isosize
, chain
);
1245 grub_file_close(file
);
1247 VENTOY_CMD_RETURN(GRUB_ERR_NONE
);