]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_unix.c
0eac9e41d5b9ad4a53c0cbab94a81da5a7d5e6e5
[Ventoy.git] / GRUB2 / MOD_SRC / grub-2.04 / grub-core / ventoy / ventoy_unix.c
1 /******************************************************************************
2 * ventoy_unix.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 #include <grub/types.h>
21 #include <grub/misc.h>
22 #include <grub/mm.h>
23 #include <grub/err.h>
24 #include <grub/dl.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>
34 #include <grub/net.h>
35 #include <grub/time.h>
36 #include <grub/elf.h>
37 #include <grub/elfload.h>
38 #include <grub/ventoy.h>
39 #include "ventoy_def.h"
40
41 GRUB_MOD_LICENSE ("GPLv3+");
42
43 char g_ko_mod_path[256];
44 int g_conf_new_len = 0;
45 char *g_conf_new_data = NULL;
46
47 int g_mod_new_len = 0;
48 char *g_mod_new_data = NULL;
49
50 int g_mod_search_magic = 0;
51
52 int g_ko_fillmap_len = 0;
53 char *g_ko_fillmap_data = NULL;
54
55 grub_uint64_t g_mod_override_offset = 0;
56 grub_uint64_t g_conf_override_offset = 0;
57
58 static int ventoy_get_file_override(const char *filename, grub_uint64_t *offset)
59 {
60 grub_file_t file;
61
62 *offset = 0;
63
64 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", filename);
65 if (!file)
66 {
67 return 1;
68 }
69
70 *offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
71
72 grub_file_close(file);
73
74 return 0;
75 }
76
77 static grub_uint32_t ventoy_unix_get_override_chunk_count(void)
78 {
79 grub_uint32_t count = 0;
80
81 if (g_conf_new_len > 0)
82 {
83 count++;
84 }
85
86 if (g_mod_new_len > 0)
87 {
88 count++;
89 }
90
91 if (g_ko_fillmap_len > 0)
92 {
93 count += (g_ko_fillmap_len / 512);
94 if ((g_ko_fillmap_len % 512) > 0)
95 {
96 count++;
97 }
98 }
99
100 return count;
101 }
102
103 static grub_uint32_t ventoy_unix_get_virt_chunk_count(void)
104 {
105 grub_uint32_t count = 0;
106
107 if (g_conf_new_len > 0)
108 {
109 count++;
110 }
111
112 if (g_mod_new_len > 0)
113 {
114 count++;
115 }
116
117 return count;
118 }
119 static grub_uint32_t ventoy_unix_get_virt_chunk_size(void)
120 {
121 grub_uint32_t size;
122
123 size = sizeof(ventoy_virt_chunk) * ventoy_unix_get_virt_chunk_count();
124
125 if (g_conf_new_len > 0)
126 {
127 size += ventoy_align_2k(g_conf_new_len);
128 }
129
130 if (g_mod_new_len > 0)
131 {
132 size += ventoy_align_2k(g_mod_new_len);
133 }
134
135 return size;
136 }
137
138 static void ventoy_unix_fill_map_data(ventoy_chain_head *chain, struct g_ventoy_map *map)
139 {
140 grub_uint32_t i;
141 ventoy_img_chunk *chunk = NULL;
142
143 debug("Fill unix map data: <%llu> <%u>\n", (unsigned long long)chain->os_param.vtoy_disk_size, g_img_chunk_list.cur_chunk);
144
145 map->magic1[0] = map->magic2[0] = map->magic3[0] = VENTOY_UNIX_SEG_MAGIC0;
146 map->magic1[1] = map->magic2[1] = map->magic3[1] = VENTOY_UNIX_SEG_MAGIC1;
147 map->magic1[2] = map->magic2[2] = map->magic3[2] = VENTOY_UNIX_SEG_MAGIC2;
148 map->magic1[3] = map->magic2[3] = map->magic3[3] = VENTOY_UNIX_SEG_MAGIC3;
149
150 map->disksize = chain->os_param.vtoy_disk_size;
151 grub_memcpy(map->diskuuid, chain->os_param.vtoy_disk_guid, 16);
152
153 map->segnum = g_img_chunk_list.cur_chunk;
154 if (g_img_chunk_list.cur_chunk > VENTOY_UNIX_MAX_SEGNUM)
155 {
156 debug("####[FAIL] Too many segments for the ISO file %u\n", g_img_chunk_list.cur_chunk);
157 map->segnum = VENTOY_UNIX_MAX_SEGNUM;
158 }
159
160 for (i = 0; i < (grub_uint32_t)(map->segnum); i++)
161 {
162 chunk = g_img_chunk_list.chunk + i;
163 map->seglist[i].seg_start_bytes = chunk->disk_start_sector * 512ULL;
164 map->seglist[i].seg_end_bytes = (chunk->disk_end_sector + 1) * 512ULL;
165 }
166 }
167
168 static void ventoy_unix_fill_override_data( grub_uint64_t isosize, ventoy_chain_head *chain)
169 {
170 int i;
171 int left;
172 char *data = NULL;
173 grub_uint64_t offset;
174 grub_uint64_t sector;
175 ventoy_override_chunk *cur;
176 ventoy_iso9660_override *dirent;
177
178 sector = (isosize + 2047) / 2048;
179
180 cur = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset);
181
182 if (g_conf_new_len > 0)
183 {
184 /* loader.conf */
185 cur->img_offset = g_conf_override_offset;
186 cur->override_size = sizeof(ventoy_iso9660_override);
187 dirent = (ventoy_iso9660_override *)cur->override_data;
188 dirent->first_sector = (grub_uint32_t)sector;
189 dirent->size = (grub_uint32_t)g_conf_new_len;
190 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
191 dirent->size_be = grub_swap_bytes32(dirent->size);
192 sector += (dirent->size + 2047) / 2048;
193 }
194
195 if (g_mod_new_len > 0)
196 {
197 /* mod.ko */
198 cur++;
199 cur->img_offset = g_mod_override_offset;
200 cur->override_size = sizeof(ventoy_iso9660_override);
201 dirent = (ventoy_iso9660_override *)cur->override_data;
202 dirent->first_sector = (grub_uint32_t)sector;
203 dirent->size = (grub_uint32_t)g_mod_new_len;
204 dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
205 dirent->size_be = grub_swap_bytes32(dirent->size);
206 sector += (dirent->size + 2047) / 2048;
207 }
208
209 if (g_ko_fillmap_len > 0)
210 {
211 data = g_ko_fillmap_data;
212 offset = g_mod_override_offset;
213
214 ventoy_unix_fill_map_data(chain, (struct g_ventoy_map *)data);
215
216 for (i = 0; i < g_ko_fillmap_len / 512; i++)
217 {
218 cur++;
219 cur->img_offset = offset;
220 cur->override_size = 512;
221 grub_memcpy(cur->override_data, data, 512);
222
223 offset += 512;
224 data += 512;
225 }
226
227 left = (g_ko_fillmap_len % 512);
228 if (left > 0)
229 {
230 cur++;
231 cur->img_offset = offset;
232 cur->override_size = left;
233 grub_memcpy(cur->override_data, data, left);
234 offset += left;
235 }
236 }
237
238 return;
239 }
240
241 static void ventoy_unix_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
242 {
243 grub_uint64_t sector;
244 grub_uint32_t offset;
245 grub_uint32_t data_secs;
246 char *override;
247 ventoy_virt_chunk *cur;
248
249 override = (char *)chain + chain->virt_chunk_offset;
250 cur = (ventoy_virt_chunk *)override;
251
252 sector = (isosize + 2047) / 2048;
253 offset = 2 * sizeof(ventoy_virt_chunk);
254
255 if (g_conf_new_len > 0)
256 {
257 ventoy_unix_fill_virt(g_conf_new_data, g_conf_new_len);
258 }
259
260 if (g_mod_new_len > 0)
261 {
262 if (g_mod_search_magic > 0)
263 {
264 ventoy_unix_fill_map_data(chain, (struct g_ventoy_map *)(g_mod_new_data + g_mod_search_magic));
265 }
266
267 ventoy_unix_fill_virt(g_mod_new_data, g_mod_new_len);
268 }
269
270 return;
271 }
272
273 static int ventoy_freebsd_append_conf(char *buf, const char *isopath)
274 {
275 int pos = 0;
276 grub_uint32_t i;
277 grub_disk_t disk;
278 grub_file_t isofile;
279 char uuid[64] = {0};
280 ventoy_img_chunk *chunk;
281 grub_uint8_t disk_sig[4];
282 grub_uint8_t disk_guid[16];
283
284 debug("ventoy_freebsd_append_conf %s\n", isopath);
285
286 isofile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", isopath);
287 if (!isofile)
288 {
289 return 1;
290 }
291
292 vtoy_ssprintf(buf, pos, "ventoy_load=\"%s\"\n", "YES");
293 vtoy_ssprintf(buf, pos, "ventoy_name=\"%s\"\n", g_ko_mod_path);
294
295 if (g_mod_search_magic)
296 {
297 debug("hint.ventoy NO need\n");
298 goto out;
299 }
300
301 disk = isofile->device->disk;
302
303 ventoy_get_disk_guid(isofile->name, disk_guid, disk_sig);
304
305 for (i = 0; i < 16; i++)
306 {
307 grub_snprintf(uuid + i * 2, sizeof(uuid), "%02x", disk_guid[i]);
308 }
309
310 vtoy_ssprintf(buf, pos, "hint.ventoy.0.disksize=%llu\n", (ulonglong)(disk->total_sectors * (1 << disk->log_sector_size)));
311 vtoy_ssprintf(buf, pos, "hint.ventoy.0.diskuuid=\"%s\"\n", uuid);
312 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]);
313 vtoy_ssprintf(buf, pos, "hint.ventoy.0.segnum=%u\n", g_img_chunk_list.cur_chunk);
314
315 for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
316 {
317 chunk = g_img_chunk_list.chunk + i;
318 vtoy_ssprintf(buf, pos, "hint.ventoy.%u.seg=\"0x%llx@0x%llx\"\n",
319 i, (ulonglong)(chunk->disk_start_sector * 512),
320 (ulonglong)((chunk->disk_end_sector + 1) * 512));
321 }
322
323 out:
324 grub_file_close(isofile);
325 return pos;
326 }
327
328 static int ventoy_dragonfly_append_conf(char *buf, const char *isopath)
329 {
330 int pos = 0;
331
332 debug("ventoy_dragonfly_append_conf %s\n", isopath);
333
334 vtoy_ssprintf(buf, pos, "tmpfs_load=\"%s\"\n", "YES");
335 vtoy_ssprintf(buf, pos, "dm_target_linear_load=\"%s\"\n", "YES");
336 vtoy_ssprintf(buf, pos, "initrd.img_load=\"%s\"\n", "YES");
337 vtoy_ssprintf(buf, pos, "initrd.img_type=\"%s\"\n", "md_image");
338 vtoy_ssprintf(buf, pos, "vfs.root.mountfrom=\"%s\"\n", "ufs:md0s0");
339
340 return pos;
341 }
342
343 grub_err_t ventoy_cmd_unix_reset(grub_extcmd_context_t ctxt, int argc, char **args)
344 {
345 (void)ctxt;
346 (void)argc;
347 (void)args;
348
349 g_mod_search_magic = 0;
350 g_conf_new_len = 0;
351 g_mod_new_len = 0;
352 g_mod_override_offset = 0;
353 g_conf_override_offset = 0;
354 g_ko_fillmap_len = 0;
355
356 check_free(g_mod_new_data, grub_free);
357 check_free(g_conf_new_data, grub_free);
358 check_free(g_ko_fillmap_data, grub_free);
359
360 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
361 }
362
363 grub_err_t ventoy_cmd_parse_freenas_ver(grub_extcmd_context_t ctxt, int argc, char **args)
364 {
365 grub_file_t file;
366 const char *ver = NULL;
367 char *buf = NULL;
368 VTOY_JSON *json = NULL;
369
370 (void)ctxt;
371 (void)argc;
372
373 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
374 if (!file)
375 {
376 debug("Failed to open file %s\n", args[0]);
377 return 1;
378 }
379
380 buf = grub_malloc(file->size + 2);
381 if (!buf)
382 {
383 grub_file_close(file);
384 return 0;
385 }
386 grub_file_read(file, buf, file->size);
387 buf[file->size] = 0;
388
389 json = vtoy_json_create();
390 if (!json)
391 {
392 goto end;
393 }
394
395 if (vtoy_json_parse(json, buf))
396 {
397 goto end;
398 }
399
400 ver = vtoy_json_get_string_ex(json->pstChild, "Version");
401 if (ver)
402 {
403 debug("freenas version:<%s>\n", ver);
404 ventoy_set_env(args[1], ver);
405 }
406 else
407 {
408 debug("freenas version:<%s>\n", "NOT FOUND");
409 grub_env_unset(args[1]);
410 }
411
412 end:
413 grub_check_free(buf);
414 check_free(json, vtoy_json_destroy);
415 grub_file_close(file);
416
417 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
418 }
419
420 grub_err_t ventoy_cmd_unix_freebsd_ver(grub_extcmd_context_t ctxt, int argc, char **args)
421 {
422 grub_file_t file;
423 char *buf;
424 char *start = NULL;
425 char *nextline = NULL;
426
427 (void)ctxt;
428 (void)argc;
429 (void)args;
430
431 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
432 if (!file)
433 {
434 debug("Failed to open file %s\n", args[0]);
435 return 1;
436 }
437
438 buf = grub_zalloc(file->size + 2);
439 if (!buf)
440 {
441 grub_file_close(file);
442 return 0;
443 }
444 grub_file_read(file, buf, file->size);
445
446 for (start = buf; start; start = nextline)
447 {
448 if (grub_strncmp(start, "USERLAND_VERSION", 16) == 0)
449 {
450 nextline = start;
451 while (*nextline && *nextline != '\r' && *nextline != '\n')
452 {
453 nextline++;
454 }
455
456 *nextline = 0;
457 break;
458 }
459 nextline = ventoy_get_line(start);
460 }
461
462 if (start)
463 {
464 debug("freebsd version:<%s>\n", start);
465 ventoy_set_env(args[1], start);
466 }
467 else
468 {
469 debug("freebsd version:<%s>\n", "NOT FOUND");
470 grub_env_unset(args[1]);
471 }
472
473 grub_free(buf);
474 grub_file_close(file);
475
476 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
477 }
478
479 grub_err_t ventoy_cmd_unix_freebsd_ver_elf(grub_extcmd_context_t ctxt, int argc, char **args)
480 {
481 int j;
482 int k;
483 grub_elf_t elf = NULL;
484 grub_off_t offset = 0;
485 grub_uint32_t len = 0;
486 char *str = NULL;
487 char *data = NULL;
488 void *hdr = NULL;
489 char ver[64] = {0};
490
491 (void)ctxt;
492 (void)argc;
493 (void)args;
494
495 if (argc != 3)
496 {
497 debug("Invalid argc %d\n", argc);
498 return 1;
499 }
500
501 data = grub_zalloc(8192);
502 if (!data)
503 {
504 goto out;
505 }
506
507 elf = grub_elf_open(args[0], GRUB_FILE_TYPE_LINUX_INITRD);
508 if (!elf)
509 {
510 debug("Failed to open file %s\n", args[0]);
511 goto out;
512 }
513
514 if (args[1][0] == '6')
515 {
516 Elf64_Ehdr *e = &(elf->ehdr.ehdr64);
517 Elf64_Shdr *h;
518 Elf64_Shdr *s;
519 Elf64_Shdr *t;
520 Elf64_Half i;
521
522 h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize);
523 if (!h)
524 {
525 goto out;
526 }
527
528 debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx);
529 grub_file_seek(elf->file, e->e_shoff);
530 grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize);
531
532 s = (Elf64_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize);
533 str = grub_malloc(s->sh_size + 1);
534 if (!str)
535 {
536 goto out;
537 }
538 str[s->sh_size] = 0;
539
540 debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size);
541 grub_file_seek(elf->file, s->sh_offset);
542 grub_file_read(elf->file, str, s->sh_size);
543
544 for (t = h, i = 0; i < e->e_shnum; i++)
545 {
546 if (grub_strcmp(str + t->sh_name, ".data") == 0)
547 {
548 offset = t->sh_offset;
549 len = t->sh_size;
550 debug("find .data section at %u %u\n", (grub_uint32_t)offset, len);
551 break;
552 }
553 t = (Elf64_Shdr *)((char *)t + e->e_shentsize);
554 }
555 }
556 else
557 {
558 Elf32_Ehdr *e = &(elf->ehdr.ehdr32);
559 Elf32_Shdr *h;
560 Elf32_Shdr *s;
561 Elf32_Shdr *t;
562 Elf32_Half i;
563
564 h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize);
565 if (!h)
566 {
567 goto out;
568 }
569
570 debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx);
571 grub_file_seek(elf->file, e->e_shoff);
572 grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize);
573
574 s = (Elf32_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize);
575 str = grub_malloc(s->sh_size + 1);
576 if (!str)
577 {
578 goto out;
579 }
580 str[s->sh_size] = 0;
581
582 debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size);
583 grub_file_seek(elf->file, s->sh_offset);
584 grub_file_read(elf->file, str, s->sh_size);
585
586 for (t = h, i = 0; i < e->e_shnum; i++)
587 {
588 if (grub_strcmp(str + t->sh_name, ".data") == 0)
589 {
590 offset = t->sh_offset;
591 len = t->sh_size;
592 debug("find .data section at %u %u\n", (grub_uint32_t)offset, len);
593 break;
594 }
595 t = (Elf32_Shdr *)((char *)t + e->e_shentsize);
596 }
597 }
598
599 if (offset == 0 || len == 0)
600 {
601 debug(".data section not found %s\n", args[0]);
602 goto out;
603 }
604
605 grub_file_seek(elf->file, offset + len - 8192);
606 grub_file_read(elf->file, data, 8192);
607
608 for (j = 0; j < 8192 - 12; j++)
609 {
610 if (grub_strncmp(data + j, "@(#)FreeBSD ", 12) == 0)
611 {
612 for (k = j + 12; k < 8192; k++)
613 {
614 if (0 == grub_isdigit(data[k]) && data[k] != '.')
615 {
616 data[k] = 0;
617 break;
618 }
619 }
620
621 grub_snprintf(ver, sizeof(ver), "%s", data + j + 12);
622 break;
623 }
624 }
625
626 if (ver[0])
627 {
628 k = (int)grub_strtoul(ver, NULL, 10);
629 debug("freebsd version:<%s> <%d.x>\n", ver, k);
630 grub_snprintf(ver, sizeof(ver), "%d.x", k);
631 ventoy_set_env(args[2], ver);
632 }
633 else
634 {
635 debug("freebsd version:<%s>\n", "NOT FOUND");
636 }
637
638 out:
639 grub_check_free(str);
640 grub_check_free(hdr);
641 grub_check_free(data);
642 check_free(elf, grub_elf_close);
643
644 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
645 }
646
647 grub_err_t ventoy_cmd_unix_replace_conf(grub_extcmd_context_t ctxt, int argc, char **args)
648 {
649 grub_uint32_t i;
650 char *data;
651 grub_uint64_t offset;
652 grub_file_t file;
653 const char *confile = NULL;
654 const char * loader_conf[] =
655 {
656 "/boot/loader.conf",
657 "/boot/defaults/loader.conf",
658 };
659
660 (void)ctxt;
661
662 if (argc != 2)
663 {
664 debug("Replace conf invalid argc %d\n", argc);
665 return 1;
666 }
667
668 for (i = 0; i < sizeof(loader_conf) / sizeof(loader_conf[0]); i++)
669 {
670 if (ventoy_get_file_override(loader_conf[i], &offset) == 0)
671 {
672 confile = loader_conf[i];
673 g_conf_override_offset = offset;
674 break;
675 }
676 }
677
678 if (confile == NULL)
679 {
680 debug("Can't find loader.conf file from %u locations\n", i);
681 return 1;
682 }
683
684 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(loop)/%s", confile);
685 if (!file)
686 {
687 debug("Failed to open %s \n", confile);
688 return 1;
689 }
690
691 debug("old conf file size:%d\n", (int)file->size);
692
693 data = grub_malloc(VTOY_MAX_SCRIPT_BUF);
694 if (!data)
695 {
696 grub_file_close(file);
697 return 1;
698 }
699
700 grub_file_read(file, data, file->size);
701 grub_file_close(file);
702
703 g_conf_new_data = data;
704 g_conf_new_len = (int)file->size;
705
706 if (grub_strcmp(args[0], "FreeBSD") == 0)
707 {
708 g_conf_new_len += ventoy_freebsd_append_conf(data + file->size, args[1]);
709 }
710 else if (grub_strcmp(args[0], "DragonFly") == 0)
711 {
712 g_conf_new_len += ventoy_dragonfly_append_conf(data + file->size, args[1]);
713 }
714
715 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
716 }
717
718 static int ventoy_unix_search_magic(char *data, int len)
719 {
720 int i;
721 grub_uint32_t *magic = NULL;
722
723 for (i = 0; i < len; i += 65536)
724 {
725 magic = (grub_uint32_t *)(data + i);
726 if (magic[0] == VENTOY_UNIX_SEG_MAGIC0 && magic[1] == VENTOY_UNIX_SEG_MAGIC1 &&
727 magic[2] == VENTOY_UNIX_SEG_MAGIC2 && magic[3] == VENTOY_UNIX_SEG_MAGIC3)
728 {
729 debug("unix find search magic at 0x%x loop:%d\n", i, (i >> 16));
730 g_mod_search_magic = i;
731 return 0;
732 }
733 }
734
735 debug("unix can not find search magic\n");
736 return 1;
737 }
738
739 grub_err_t ventoy_cmd_unix_replace_ko(grub_extcmd_context_t ctxt, int argc, char **args)
740 {
741 char *data;
742 grub_uint64_t offset;
743 grub_file_t file;
744
745 (void)ctxt;
746
747 if (argc != 2)
748 {
749 debug("Replace ko invalid argc %d\n", argc);
750 return 1;
751 }
752
753 debug("replace ko %s\n", args[0]);
754
755 if (ventoy_get_file_override(args[0], &offset) == 0)
756 {
757 grub_snprintf(g_ko_mod_path, sizeof(g_ko_mod_path), "%s", args[0]);
758 g_mod_override_offset = offset;
759 }
760 else
761 {
762 debug("Can't find replace ko file from %s\n", args[0]);
763 return 1;
764 }
765
766 file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[1]);
767 if (!file)
768 {
769 debug("Failed to open %s \n", args[1]);
770 return 1;
771 }
772
773 debug("new ko file size:%d\n", (int)file->size);
774
775 data = grub_malloc(file->size);
776 if (!data)
777 {
778 debug("Failed to alloc memory for new ko %d\n", (int)file->size);
779 grub_file_close(file);
780 return 1;
781 }
782
783 grub_file_read(file, data, file->size);
784 grub_file_close(file);
785
786 g_mod_new_data = data;
787 g_mod_new_len = (int)file->size;
788
789 ventoy_unix_search_magic(g_mod_new_data, g_mod_new_len);
790
791 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
792 }
793
794 grub_err_t ventoy_cmd_unix_ko_fillmap(grub_extcmd_context_t ctxt, int argc, char **args)
795 {
796 int i;
797 grub_file_t file;
798 grub_uint32_t magic[4];
799 grub_uint32_t len;
800
801 (void)ctxt;
802
803 if (argc != 1)
804 {
805 debug("Fillmap ko invalid argc %d\n", argc);
806 return 1;
807 }
808
809 debug("Fillmap ko %s\n", args[0]);
810
811 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", args[0]);
812 if (file)
813 {
814 g_mod_override_offset = grub_iso9660_get_last_read_pos(file);
815 }
816 else
817 {
818 debug("Can't find replace ko file from %s\n", args[0]);
819 return 1;
820 }
821
822 for (i = 0; i < (int)(file->size); i += 65536)
823 {
824 magic[0] = 0;
825 grub_file_seek(file, i);
826 grub_file_read(file, magic, sizeof(magic));
827
828 if (magic[0] == VENTOY_UNIX_SEG_MAGIC0 && magic[1] == VENTOY_UNIX_SEG_MAGIC1 &&
829 magic[2] == VENTOY_UNIX_SEG_MAGIC2 && magic[3] == VENTOY_UNIX_SEG_MAGIC3)
830 {
831 debug("unix find search magic at 0x%x loop:%d\n", i, (i >> 16));
832 g_mod_override_offset += i;
833 break;
834 }
835 }
836
837 len = (grub_uint32_t)OFFSET_OF(struct g_ventoy_map, seglist) +
838 (sizeof(struct g_ventoy_seg) * g_img_chunk_list.cur_chunk);
839
840 g_ko_fillmap_len = (int)len;
841 g_ko_fillmap_data = grub_malloc(len);
842 if (!g_ko_fillmap_data)
843 {
844 g_ko_fillmap_len = 0;
845 debug("Failed to malloc fillmap data\n");
846 }
847
848 debug("Fillmap ko segnum:%u, override len:%d", g_img_chunk_list.cur_chunk, g_ko_fillmap_len);
849
850 grub_file_close(file);
851 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
852 }
853
854 grub_err_t ventoy_cmd_unix_fill_image_desc(grub_extcmd_context_t ctxt, int argc, char **args)
855 {
856 int i;
857 grub_uint8_t *byte;
858 grub_uint32_t memsize;
859 ventoy_image_desc *desc;
860 grub_uint8_t flag[32] = {
861 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
862 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
863 };
864
865 (void)ctxt;
866 (void)argc;
867 (void)args;
868
869 debug("ventoy_cmd_unix_fill_image_desc %p\n", g_mod_new_data);
870
871 if (!g_mod_new_data)
872 {
873 goto end;
874 }
875
876 byte = (grub_uint8_t *)g_mod_new_data;
877 for (i = 0; i < g_mod_new_len - 32; i += 16)
878 {
879 if (byte[i] == 0xFF && byte[i + 1] == 0xEE)
880 {
881 if (grub_memcmp(flag, byte + i, 32) == 0)
882 {
883 debug("Find position flag at %d(0x%x)\n", i, i);
884 break;
885 }
886 }
887 }
888
889 if (i >= g_mod_new_len - 32)
890 {
891 debug("Failed to find position flag %d\n", i);
892 goto end;
893 }
894
895 desc = (ventoy_image_desc *)(byte + i);
896 desc->disk_size = g_ventoy_disk_size;
897 desc->part1_size = g_ventoy_disk_part_size[0];
898 grub_memcpy(desc->disk_uuid, g_ventoy_part_info->MBR.BootCode + 0x180, 16);
899 grub_memcpy(desc->disk_signature, g_ventoy_part_info->MBR.BootCode + 0x1B8, 4);
900
901 desc->img_chunk_count = g_img_chunk_list.cur_chunk;
902 memsize = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
903
904 debug("image chunk count:%u memsize:%u\n", desc->img_chunk_count, memsize);
905
906 if (memsize >= VTOY_SIZE_1MB * 8)
907 {
908 grub_printf("image chunk count:%u memsize:%u too big\n", desc->img_chunk_count, memsize);
909 goto end;
910 }
911
912 grub_memcpy(desc + 1, g_img_chunk_list.chunk, memsize);
913
914 end:
915 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
916 }
917
918 grub_err_t ventoy_cmd_unix_gzip_newko(grub_extcmd_context_t ctxt, int argc, char **args)
919 {
920 int newlen;
921 grub_uint8_t *buf;
922
923 (void)ctxt;
924 (void)argc;
925 (void)args;
926
927 debug("ventoy_cmd_unix_gzip_newko %p\n", g_mod_new_data);
928
929 if (!g_mod_new_data)
930 {
931 goto end;
932 }
933
934 buf = grub_malloc(g_mod_new_len);
935 if (!buf)
936 {
937 goto end;
938 }
939
940 newlen = ventoy_gzip_compress(g_mod_new_data, g_mod_new_len, buf, g_mod_new_len);
941
942 grub_free(g_mod_new_data);
943
944 debug("gzip org len:%d newlen:%d\n", g_mod_new_len, newlen);
945
946 g_mod_new_data = (char *)buf;
947 g_mod_new_len = newlen;
948
949 end:
950 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
951 }
952
953 grub_err_t ventoy_cmd_unix_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
954 {
955 int ventoy_compatible = 0;
956 grub_uint32_t size = 0;
957 grub_uint64_t isosize = 0;
958 grub_uint32_t boot_catlog = 0;
959 grub_uint32_t img_chunk_size = 0;
960 grub_uint32_t override_count = 0;
961 grub_uint32_t override_size = 0;
962 grub_uint32_t virt_chunk_size = 0;
963 grub_file_t file;
964 grub_disk_t disk;
965 const char *pLastChain = NULL;
966 const char *compatible;
967 ventoy_chain_head *chain;
968 char envbuf[64];
969
970 (void)ctxt;
971 (void)argc;
972
973 compatible = grub_env_get("ventoy_compatible");
974 if (compatible && compatible[0] == 'Y')
975 {
976 ventoy_compatible = 1;
977 }
978
979 if (NULL == g_img_chunk_list.chunk)
980 {
981 grub_printf("ventoy not ready\n");
982 return 1;
983 }
984
985 file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
986 if (!file)
987 {
988 return 1;
989 }
990
991 isosize = file->size;
992
993 boot_catlog = ventoy_get_iso_boot_catlog(file);
994 if (boot_catlog)
995 {
996 if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
997 {
998 grub_env_set("LoadIsoEfiDriver", "on");
999 }
1000 }
1001 else
1002 {
1003 if (ventoy_is_efi_os())
1004 {
1005 grub_env_set("LoadIsoEfiDriver", "on");
1006 }
1007 else
1008 {
1009 return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
1010 }
1011 }
1012
1013 img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
1014
1015 if (ventoy_compatible)
1016 {
1017 size = sizeof(ventoy_chain_head) + img_chunk_size;
1018 }
1019 else
1020 {
1021 override_count = ventoy_unix_get_override_chunk_count();
1022 override_size = override_count * sizeof(ventoy_override_chunk);
1023
1024 virt_chunk_size = ventoy_unix_get_virt_chunk_size();
1025 size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
1026 }
1027
1028 pLastChain = grub_env_get("vtoy_chain_mem_addr");
1029 if (pLastChain)
1030 {
1031 chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
1032 if (chain)
1033 {
1034 debug("free last chain memory %p\n", chain);
1035 grub_free(chain);
1036 }
1037 }
1038
1039 chain = grub_malloc(size);
1040 if (!chain)
1041 {
1042 grub_printf("Failed to alloc chain memory size %u\n", size);
1043 grub_file_close(file);
1044 return 1;
1045 }
1046
1047 grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
1048 grub_env_set("vtoy_chain_mem_addr", envbuf);
1049 grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
1050 grub_env_set("vtoy_chain_mem_size", envbuf);
1051
1052 grub_memset(chain, 0, sizeof(ventoy_chain_head));
1053
1054 /* part 1: os parameter */
1055 g_ventoy_chain_type = ventoy_chain_linux;
1056 ventoy_fill_os_param(file, &(chain->os_param));
1057
1058 /* part 2: chain head */
1059 disk = file->device->disk;
1060 chain->disk_drive = disk->id;
1061 chain->disk_sector_size = (1 << disk->log_sector_size);
1062 chain->real_img_size_in_bytes = file->size;
1063 chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
1064 chain->boot_catalog = boot_catlog;
1065
1066 if (!ventoy_is_efi_os())
1067 {
1068 grub_file_seek(file, boot_catlog * 2048);
1069 grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
1070 }
1071
1072 /* part 3: image chunk */
1073 chain->img_chunk_offset = sizeof(ventoy_chain_head);
1074 chain->img_chunk_num = g_img_chunk_list.cur_chunk;
1075 grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
1076
1077 if (ventoy_compatible)
1078 {
1079 return 0;
1080 }
1081
1082 /* part 4: override chunk */
1083 chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
1084 chain->override_chunk_num = override_count;
1085 ventoy_unix_fill_override_data(isosize, chain);
1086
1087 /* part 5: virt chunk */
1088 chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
1089 chain->virt_chunk_num = ventoy_unix_get_virt_chunk_count();
1090 ventoy_unix_fill_virt_data(isosize, chain);
1091
1092 grub_file_close(file);
1093
1094 VENTOY_CMD_RETURN(GRUB_ERR_NONE);
1095 }
1096