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