commit cd02c606e60463033e974b514b4b73d0a9066fb9 Author: Paravis Date: Sat Nov 7 20:37:46 2026 +0300 Ventoy 1.1.18 sources and Paravis patches diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..353946e --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Build output +build/ +out/ +dist/ +*.o +*.a +*.so +*.dylib +*.obj +*.exe +*.dll +*.efi +*.signed +*.img +*.iso +*.wim +*.esd +*.pf + +# Local toolchain, keys and certificates +keys/ +*.pem +*.key +*.pfx +*.p12 +*.cer +*.crt + +# Editors and logs +.vs/ +.idea/ +.vscode/ +*.log +*.tmp diff --git a/README.md b/README.md new file mode 100644 index 0000000..85c36f7 --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# Ventoy for PARAVIS Flash + +Ventoy 1.1.18 sources and Paravis changes used on the PARAVIS multiboot USB +flash. + +The PARAVIS flash uses a non-standard partition layout, so Ventoy has to be +patched to find the data (ISO) partition dynamically instead of assuming +partition 1: + +| # | Size | File system | Label | Purpose | +|---|------|-------------|-------|---------| +| 1 | 16 GB | FAT32 | `PARAVIS` | main boot partition (bootmgr / g4d) | +| 2 | 32 MB | FAT | `VTOYEFI` | Ventoy EFI partition | +| 3 | rest − 3 MB | exFAT | `DATA` | images and data | + +The data partition is detected by the marker file `/ISO/Ventoy/NOT.DEL`. + +## Repository layout + +``` +Ventoy-src/ upstream Ventoy 1.1.18 source tree (GPLv3) +paravis/ + patch_ventoy_layout.py GRUB2 source patches for the custom layout + patch_ventoy_grubcfg.py grub.cfg patch (marker-based data partition) + patch_ventoy_hook.py initramfs hook patch for non-partition-1 data + patch_vtoyjump.py vtoyjump32/64 MBr marker check bypass + patch-ventoy-lang.sh default menu language -> ru_RU + build-theme-main.py builds the GRUB theme from a PSD layout + theme/ GRUB theme assets and ventoy.json + ventoy_grub.cfg "return to main menu" entry + ventoy_grub-f7.cfg F7 entry back to the main Paravis GRUB menu +``` + +## Applying the patches + +The scripts take explicit paths, so they can be run from any checkout. + +```sh +# 1. GRUB2 sources (run inside the Ventoy build tree) +python3 paravis/patch_ventoy_layout.py GRUB2/SRC/grub-2.04/grub-core/ventoy + +# 2. VTOYEFI grub.cfg +python3 paravis/patch_ventoy_grubcfg.py vtoyefi/grub/grub.cfg + +# 3. initramfs hook +python3 paravis/patch_ventoy_hook.py ventoy.cpio ventoy.cpio + +# 4. vtoyjump32.exe / vtoyjump64.exe +python3 paravis/patch_vtoyjump.py + +# 5. default menu language +./paravis/patch-ventoy-lang.sh vtoyefi/grub/grub.cfg +``` + +`patch_vtoyjump.py` patches compiled binaries; it is safe to re-run and +skips files that are already patched. + +## Theme + +`paravis/theme/` contains `theme.txt`, `ventoy.json`, the background and +widget PNGs and `paravis.pf2` (Montserrat converted to GRUB format). + +`ventoy.json` refers to `tahoma20.pf2`, `tahoma16.pf2`, `tahoma-bold16.pf2` +and `tahoma-bold14.pf2`. Those files are **not** part of this repository +because they are derived from Microsoft fonts. Provide them locally when +deploying the theme, or generate replacements from a font you are allowed to +use: + +```sh +grub-mkfont -s 20 -o tahoma20.pf2 YourFont.ttf +``` + +`build-theme-main.py` renders the background and a preview from a layered +PSD file; it needs `psd-tools`, `Pillow` and the Montserrat font. + +## What is not included + +This is a source-only repository. It does not contain: + +- private keys, certificates or signed EFI binaries (`keys/`, `*.signed`); +- Microsoft-derived font files (`tahoma*.pf2`, `segoeui18.pf2`); +- built Ventoy releases and bootable images (`*.iso`, `*.img`, `*.wim`, + `*.esd`, `Data.pf`); +- `bootice.exe`, Total Commander and other third-party binaries; +- build output, logs or local machine paths. + +## License + +Ventoy itself is licensed under GPLv3; see +[`Ventoy-src/COPYING`](Ventoy-src/COPYING). The Paravis patches and theme are +released under the same terms as the project they modify. See +[`THIRD-PARTY.md`](THIRD-PARTY.md) for details. diff --git a/THIRD-PARTY.md b/THIRD-PARTY.md new file mode 100644 index 0000000..d5c6a9e --- /dev/null +++ b/THIRD-PARTY.md @@ -0,0 +1,41 @@ +# Third-party components + +## Ventoy + +`Ventoy-src/` is the upstream Ventoy 1.1.18 source tree. + +Ventoy is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +The full license text is in [`Ventoy-src/COPYING`](Ventoy-src/COPYING). +Upstream project: and +. + +## GRUB2 + +`Ventoy-src/GRUB2/` contains the GRUB 2.04 sources and Ventoy modules used +to build the bootloader. GRUB is licensed under GPLv3. + +## Montserrat + +`paravis/theme/paravis.pf2` is the Montserrat typeface converted to the GRUB +`.pf2` format. + +Copyright 2024 The Montserrat.Git Project Authors +(https://github.com/JulietaUla/Montserrat.git) + +Licensed under the SIL Open Font License, Version 1.1. +The full license text is in [`paravis/theme/OFL.txt`](paravis/theme/OFL.txt). + +## Not included + +For licensing reasons this repository does not contain: + +- Microsoft font derivatives (`tahoma20.pf2`, `tahoma16.pf2`, + `tahoma-bold16.pf2`, `tahoma-bold14.pf2`, `segoeui18.pf2`); +- private signing keys, certificates or signed EFI binaries; +- third-party binaries such as `bootice.exe` or Total Commander; +- bootable images and installation archives (`*.iso`, `*.img`, `*.wim`, + `*.esd`, `Data.pf`). diff --git a/Ventoy-src/BLOB_List.md b/Ventoy-src/BLOB_List.md new file mode 100644 index 0000000..6cfa5ee --- /dev/null +++ b/Ventoy-src/BLOB_List.md @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BLOBFile SourceDesc
./BUSYBOX/chmod/vtchmod32 build Build Instructions:
./BUSYBOX/chmod/build.sh
./BUSYBOX/chmod/vtchmod64
./BUSYBOX/chmod/vtchmod64_musl
./BUSYBOX/chmod/vtchmodaa64
./BUSYBOX/chmod/vtchmodm64e
./cryptsetup/veritysetup32 build Build Instructions:
./cryptsetup/cryptsetup-build.txt
./cryptsetup/veritysetup64
./DMSETUP/dmsetup32 build Build Instructions:
./DMSETUP/build.txt
./DMSETUP/dmsetup64
./DMSETUP/dmsetupaa64
./DMSETUP/dmsetupm64e
./FUSEISO/vtoy_fuse_iso_32 build Build Instructions:
./FUSEISO/build.sh
./FUSEISO/build_aarch64.sh
./FUSEISO/build_libfuse.sh
./FUSEISO/build_libfuse_aarch64.sh
./FUSEISO/vtoy_fuse_iso_64
./FUSEISO/vtoy_fuse_iso_aa64
./IMG/cpio_arm64/ventoy/busybox/a64 build Build Instructions:
./BUSYBOX/build.txt ash
./IMG/cpio_arm64/ventoy/busybox/vtchmodaa64 build Same with ./BUSYBOX/chmod/vtchmodaa64
Check the file hash to confirm
./IMG/cpio_arm64/ventoy/busybox/xzminidecaa64 build Build Instructions:
./DOC/BuildVentoyFromSource.txt 4.17
./IMG/cpio_arm64/ventoy/tool/lz4cataa64 build Same with ./LZIP/lz4cataa64
Check the file hash to confirm
./IMG/cpio_arm64/ventoy/tool/zstdcataa64 build Same with ./ZSTD/zstdcataa64
Check the file hash to confirm
./IMG/cpio_mips64/ventoy/busybox/m64 build Build Instructions:
./BUSYBOX/build.txt ash
./IMG/cpio_mips64/ventoy/busybox/vtchmodm64e build Same with ./BUSYBOX/chmod/vtchmodm64e
Check the file hash to confirm
./IMG/cpio_mips64/ventoy/busybox/xzminidecm64e build Build Instructions:
./DOC/BuildVentoyFromSource.txt 4.18
./IMG/cpio_mips64/ventoy/tool/lz4catm64e build Same with ./LZIP/lz4catm64e
Check the file hash to confirm
./IMG/cpio_x86/ventoy/busybox/64h build Build Instructions:
./BUSYBOX/build.txt ash
./IMG/cpio_x86/ventoy/busybox/ash upstream Download from BusyBox website.
URL & File Hash documented in
./DOC/BuildVentoyFromSource.txt 5.4
./IMG/cpio_x86/ventoy/busybox/vtchmod32 build Same with ./BUSYBOX/chmod/vtchmod32
Check the file hash to confirm
./IMG/cpio_x86/ventoy/busybox/vtchmod64 build Same with ./BUSYBOX/chmod/vtchmod64
Check the file hash to confirm
./IMG/cpio_x86/ventoy/busybox/vtchmod64_musl build Same with ./BUSYBOX/chmod/vtchmod64_musl
Check the file hash to confirm
./IMG/cpio_x86/ventoy/busybox/xzminidec32 build Build Instructions:
./DOC/BuildVentoyFromSource.txt 4.15
./IMG/cpio_x86/ventoy/busybox/xzminidec64 build Build Instructions:
./DOC/BuildVentoyFromSource.txt 4.16
./IMG/cpio_x86/ventoy/busybox/xzminidec64_musl build Build Instructions:
./DOC/BuildVentoyFromSource.txt 4.16
./IMG/cpio_x86/ventoy/tool/ar upstream Download from BusyBox website.
URL & File Hash documented in
./DOC/BuildVentoyFromSource.txt 5.2
./IMG/cpio_x86/ventoy/tool/inotifyd upstream Download from BusyBox website.
URL & File Hash documented in
./DOC/BuildVentoyFromSource.txt 5.3
./IMG/cpio_x86/ventoy/tool/lz4cat upstream URL & File Hash documented in
./DOC/BuildVentoyFromSource.txt 5.1
./IMG/cpio_x86/ventoy/tool/lz4cat64 build Build Instructions:
./LZIP/buildlz4.txt
./IMG/cpio_x86/ventoy/tool/zstdcat build Same with ./ZSTD/zstdcat
Check the file hash to confirm
./IMG/cpio_x86/ventoy/tool/zstdcat64 build Same with ./ZSTD/zstdcat64
Check the file hash to confirm
./INSTALL/EFI/BOOT/BOOTAA64.EFI build Build Instructions:
./DOC/BuildVentoyFromSource.txt 4.1-Build grub2
./INSTALL/EFI/BOOT/BOOTMIPS.EFI
./INSTALL/EFI/BOOT/grubia32_real.efi
./INSTALL/EFI/BOOT/grubx64_real.efi
./INSTALL/EFI/BOOT/BOOTIA32.EFI upstream https://github.com/ValdikSS/Super-UEFIinSecureBoot-Disk
./INSTALL/EFI/BOOT/grubia32.efi
./INSTALL/EFI/BOOT/mmia32.efi
./INSTALL/EFI/BOOT/BOOTX64.EFI upstream From Rocky Linux 9.8 x86_64 ISO file
Check the file hash to confirm
./INSTALL/EFI/BOOT/mmx64.efi
./INSTALL/tool/aarch64/ash build Build Instructions:
./DOC/BUSYBOX/build.txt
./INSTALL/tool/aarch64/hexdump
./INSTALL/tool/aarch64/xzcat
./INSTALL/tool/i386/ash
./INSTALL/tool/i386/hexdump
./INSTALL/tool/i386/xzcat
./INSTALL/tool/mips64el/ash
./INSTALL/tool/mips64el/hexdump
./INSTALL/tool/mips64el/xzcat
./INSTALL/tool/x86_64/ash
./INSTALL/tool/x86_64/hexdump
./INSTALL/tool/x86_64/xzcat
./INSTALL/tool/aarch64/Ventoy2Disk.gtk3 build Build Instructions:
./LinuxGUI/build_gtk.sh
./INSTALL/tool/i386/Ventoy2Disk.gtk3
./INSTALL/tool/i386/Ventoy2Disk.gtk2
./INSTALL/tool/mips64el/Ventoy2Disk.gtk3
./INSTALL/tool/x86_64/Ventoy2Disk.gtk3
./INSTALL/tool/x86_64/Ventoy2Disk.gtk2
./INSTALL/tool/aarch64/Ventoy2Disk.qt5 build Build Instructions:
./LinuxGUI/build_qt.sh
./INSTALL/tool/i386/Ventoy2Disk.qt5
./INSTALL/tool/mips64el/Ventoy2Disk.qt5
./INSTALL/tool/x86_64/Ventoy2Disk.qt5
./INSTALL/tool/aarch64/Plugson build Build Instructions:
./Plugson/build.sh
./INSTALL/tool/i386/Plugson
./INSTALL/tool/mips64el/Plugson
./INSTALL/tool/x86_64/Plugson
./INSTALL/tool/aarch64/V2DServer build Build Instructions:
./LinuxGUI/build.sh
./INSTALL/tool/i386/V2DServer
./INSTALL/tool/mips64el/V2DServer
./INSTALL/tool/x86_64/V2DServer
./INSTALL/tool/aarch64/mkexfatfs build Build Instructions:
./DOC/BuildVentoyFromSource.txt 4.9
./ExFAT/buidexfat.sh
./ExFAT/buidexfat_aarch64.sh
./ExFAT/buidlibfuse.sh
./ExFAT/buidlibfuse_aarch64.sh
./INSTALL/tool/aarch64/mount.exfat-fuse
./INSTALL/tool/i386/mkexfatfs
./INSTALL/tool/i386/mount.exfat-fuse
./INSTALL/tool/mips64el/mkexfatfs
./INSTALL/tool/mips64el/mount.exfat-fuse
./INSTALL/tool/x86_64/mkexfatfs
./INSTALL/tool/x86_64/mkexfatfs_static
./INSTALL/tool/x86_64/mount.exfat-fuse
./INSTALL/tool/aarch64/vlnk build Build Instructions:
./Vlnk/build.sh
./INSTALL/tool/i386/vlnk
./INSTALL/tool/mips64el/vlnk
./INSTALL/tool/x86_64/vlnk
./INSTALL/tool/aarch64/vtoycli build Build Instructions:
./vtoycli/build.sh
./INSTALL/tool/i386/vtoycli
./INSTALL/tool/mips64el/vtoycli
./INSTALL/tool/x86_64/vtoycli
./INSTALL/ventoy/imdisk/32/imdisk.cpl upstream Download from imdisk project.
URL & File Hash documented in
./DOC/BuildVentoyFromSource.txt 5.8
./INSTALL/ventoy/imdisk/32/imdisk.exe
./INSTALL/ventoy/imdisk/32/imdisk.sys
./INSTALL/ventoy/imdisk/64/imdisk.cpl
./INSTALL/ventoy/imdisk/64/imdisk.exe
./INSTALL/ventoy/imdisk/64/imdisk.sys
./INSTALL/ventoy/iso9660_aa64.efi build Build Instructions:
./DOC/BuildVentoyFromSource.txt 4.17
./INSTALL/ventoy/udf_aa64.efi
./INSTALL/ventoy/iso9660_ia32.efi
./INSTALL/ventoy/udf_ia32.efi
./INSTALL/ventoy/iso9660_x64.efi
./INSTALL/ventoy/udf_x64.efi
./INSTALL/VentoyGUI.aarch64 build Build Instructions:
./LinuxGUI/build_gtk.sh
./INSTALL/VentoyGUI.i386
./INSTALL/VentoyGUI.mips64el
./INSTALL/VentoyGUI.x86_64
./INSTALL/Ventoy2Disk.exe build Build Instructions:
./Ventoy2Disk/Ventoy2Disk.sln
./INSTALL/Ventoy2Disk_ARM.exe
./INSTALL/Ventoy2Disk_ARM64.exe
./INSTALL/Ventoy2Disk_X64.exe
./INSTALL/ventoy/vtoyjump32.exe build Build Instructions:
./vtoyjump/vtoyjump.sln
./INSTALL/ventoy/vtoyjump64.exe
./INSTALL/ventoy/ventoy_aa64.efi build Build Instructions:
./EDK2/buildedk.sh
./INSTALL/ventoy/ventoy_ia32.efi
./INSTALL/ventoy/ventoy_x64.efi
./INSTALL/ventoy/vtoyutil_aa64.efi
./INSTALL/ventoy/vtoyutil_ia32.efi
./INSTALL/ventoy/vtoyutil_x64.efi
./INSTALL/EFI/BOOT/fbx64.efi
./INSTALL/ventoy/ipxe.krn build Build Instructions:
./IPXE/buildipxe.sh
./INSTALL/ventoy/memdisk upstream Download from syslinux project.
URL & File Hash documented in
./DOC/BuildVentoyFromSource.txt 5.9
./LiveCD/ISO/EFI/boot/vmlinuz64 upstream Download from TinyLinux website.
URL & File Hash documented in
./DOC/BuildVentoyFromSource.txt 5.14
./LiveCDGUI/EXT/busybox-x86_64 build Same with ./IMG/cpio_x86/ventoy/busybox/busybox64
Check the file hash to confirm
./LiveCDGUI/GRUB/bootx64.efi build ./DOC/BuildVentoyFromSource.txt 4.1-Build grub2
./LiveCD/GRUB/bootx64.efi
./LZIP/lunzip32 build Build Instructions:
./DOC/BuildVentoyFromSource.txt 4.19
./LZIP/lunzip64
./LZIP/lunzipaa64
./LZIP/lz4cat64 build Build Instructions:
./LZIP/buildlz4.txt
./LZIP/lz4cataa64
./LZIP/lz4catm64e
./Plugson/vs/VentoyPlugson/Release/VentoyPlugson.exe build Build Instructions:
./Plugson/vs/VentoyPlugson/VentoyPlugson.sln
./Plugson/vs/VentoyPlugson/x64/Release/VentoyPlugson_X64.exe
./SQUASHFS/unsquashfs_32 build Build Instructions:
./SQUASHFS/build.sh
./SQUASHFS/unsquashfs_64
./SQUASHFS/unsquashfs_aa64
./Unix/ventoy_unix/DragonFly/sbin/dmsetup upstream Get from DragonFly ISO.
URL & File Hash documented in
./DOC/BuildVentoyFromSource.txt 5.13
./Unix/ventoy_unix/DragonFly/sbin/init build Build Instructions:
./Unix/ventoy_unix_src/DragonFly/build.sh
./VBLADE/vblade-master/vblade_32 build Build Instructions:
./VBLADE/vblade-master/build.sh
./VBLADE/vblade-master/vblade_64
./VBLADE/vblade-master/vblade_aa64
./Vlnk/vs/VentoyVlnk/Release/VentoyVlnk.exe build Build Instructions:
./Vlnk/vs/VentoyVlnk/VentoyVlnk.sln
./VtoyTool/vtoytool/00/vtoytool_32 build Build Instructions:
./VtoyTool/build.sh
./VtoyTool/vtoytool/00/vtoytool_64
./VtoyTool/vtoytool/00/vtoytool_aa64
./VtoyTool/vtoytool/00/vtoytool_m64e
./VtoyTool/vtoytool/01/vtoytool_64
./VtoyTool/vtoytool/02/vtoytool_64
./ZSTD/zstdcat build Build Instructions:
./ZSTD/build.txt
./ZSTD/zstdcat64
./ZSTD/zstdcataa64
./IMG/cpio_x86/ventoy/busybox/busybox32 build Build Instructions:
./BUSYBOX/build.txt full busybox
./IMG/cpio_x86/ventoy/busybox/busybox64
./IMG/cpio_x86/ventoy/busybox/xzcat32_musl
./IMG/cpio_x86/ventoy/busybox/xzcat64_musl
./IMG/cpio_arm64/ventoy/busybox/busyboxaa64
./IMG/cpio_mips64/ventoy/busybox/busyboxm64e
ISNTALL/ventoy/7z/64/7za.exe upstream Download from 7z project.
URL & File Hash documented in
./DOC/BuildVentoyFromSource.txt 5.12
ISNTALL/ventoy/7z/32/7za.exe
./INSTALL/ventoy/wimboot.i386.efi build Build Instructions:
./wimboot/build.sh
./INSTALL/ventoy/wimboot.x86_64
./Unix/ventoy_unix/ClonOS/geom_ventoy_ko/13.x/64/geom_ventoy.ko build Build Instructions:
./Unix/BuildUnixKmod.txt
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/10.x/32/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/10.x/64/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/11.x/32/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/11.x/64/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/12.x/32/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/12.x/64/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/13.x/32/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/13.x/64/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/14.x/32/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/14.x/64/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/9.x/32/geom_ventoy.ko
./Unix/ventoy_unix/FreeBSD/geom_ventoy_ko/9.x/64/geom_ventoy.ko
./Unix/ventoy_unix/MidnightBSD/geom_ventoy_ko/11.x/32/geom_ventoy.ko
./Unix/ventoy_unix/MidnightBSD/geom_ventoy_ko/11.x/64/geom_ventoy.ko
./Unix/ventoy_unix/MidnightBSD/geom_ventoy_ko/2.x/32/geom_ventoy.ko
./Unix/ventoy_unix/MidnightBSD/geom_ventoy_ko/2.x/64/geom_ventoy.ko
./Unix/ventoy_unix/pfSense/geom_ventoy_ko/14.x/64/geom_ventoy.ko
diff --git a/Ventoy-src/COPYING b/Ventoy-src/COPYING new file mode 100644 index 0000000..3877ae0 --- /dev/null +++ b/Ventoy-src/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Ventoy-src/Dockerfile b/Ventoy-src/Dockerfile new file mode 100644 index 0000000..550eead --- /dev/null +++ b/Ventoy-src/Dockerfile @@ -0,0 +1,15 @@ +FROM centos:7 + +RUN sed -i \ + -e 's/^mirrorlist/#mirrorlist/' \ + -e 's/^#baseurl/baseurl/' \ + -e 's/mirror\.centos\.org/vault.centos.org/' \ + /etc/yum.repos.d/*.repo && \ + yum -y -q install \ + libXpm net-tools bzip2 wget vim gcc gcc-c++ samba dos2unix glibc-devel glibc.i686 glibc-devel.i686 \ + mpfr.i686 mpfr-devel.i686 rsync autogen autoconf automake libtool gettext* bison binutils \ + flex device-mapper-devel SDL libpciaccess libusb freetype freetype-devel gnu-free-* qemu-* virt-* \ + libvirt* vte* NetworkManager-bluetooth brlapi fuse-devel dejavu* gnu-efi* pesign shim \ + iscsi-initiator-utils grub2-tools zip nasm acpica-tools glibc-static zlib-static xorriso lz4 squashfs-tools + +CMD cd /ventoy/INSTALL && ls -la && sh docker_ci_build.sh diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/configure.ac b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/configure.ac new file mode 100644 index 0000000..78b63e8 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/configure.ac @@ -0,0 +1,2123 @@ +# -*- autoconf -*- + +# Process this file with autoconf to produce a configure script. + +# Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# This configure.ac is free software; the author +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +dnl This configure script is complicated, because GRUB needs to deal +dnl with three potentially different types: +dnl +dnl build -- the environment for building GRUB +dnl host -- the environment for running utilities +dnl target -- the environment for running GRUB +dnl +dnl In addition, GRUB needs to deal with a platform specification +dnl which specifies the system running GRUB, such as firmware. +dnl This is necessary because the target type in autoconf does not +dnl describe such a system very well. +dnl +dnl The current strategy is to use variables with no prefix (such as +dnl CC, CFLAGS, etc.) for the host type, variables with prefix "BUILD_" +dnl (such as BUILD_CC, BUILD_CFLAGS, etc.) for the build type and variables +dnl with the prefix "TARGET_" (such as TARGET_CC, TARGET_CFLAGS, etc.) are +dnl used for the target type. See INSTALL for full list of variables. + +AC_INIT([GRUB],[2.04],[bug-grub@gnu.org]) + +AC_CONFIG_AUX_DIR([build-aux]) + +# We don't want -g -O2 by default in CFLAGS +: ${CFLAGS=""} + +# Checks for build, host and target systems. +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +save_program_prefix="${program_prefix}" +AC_CANONICAL_TARGET +program_prefix="${save_program_prefix}" + +AM_INIT_AUTOMAKE([1.11]) +AC_PREREQ(2.63) +AC_CONFIG_SRCDIR([include/grub/dl.h]) +AC_CONFIG_HEADER([config-util.h]) + +# Explicitly check for pkg-config early on, since otherwise conditional +# calls are problematic. +PKG_PROG_PKG_CONFIG + +# Program name transformations +AC_ARG_PROGRAM +grub_TRANSFORM([grub-bios-setup]) +grub_TRANSFORM([grub-editenv]) +grub_TRANSFORM([grub-install]) +grub_TRANSFORM([grub-mkconfig]) +grub_TRANSFORM([grub-mkfont]) +grub_TRANSFORM([grub-mkimage]) +grub_TRANSFORM([grub-glue-efi]) +grub_TRANSFORM([grub-mklayout]) +grub_TRANSFORM([grub-mkpasswd-pbkdf2]) +grub_TRANSFORM([grub-mkrelpath]) +grub_TRANSFORM([grub-mkrescue]) +grub_TRANSFORM([grub-probe]) +grub_TRANSFORM([grub-reboot]) +grub_TRANSFORM([grub-script-check]) +grub_TRANSFORM([grub-set-default]) +grub_TRANSFORM([grub-sparc64-setup]) +grub_TRANSFORM([grub-render-label]) +grub_TRANSFORM([grub-file]) + +# Optimization flag. Allow user to override. +if test "x$TARGET_CFLAGS" = x; then + TARGET_CFLAGS="$TARGET_CFLAGS -Os" +fi + +# Default HOST_CPPFLAGS +HOST_CPPFLAGS="$HOST_CPPFLAGS -Wall -W" +HOST_CPPFLAGS="$HOST_CPPFLAGS -DGRUB_UTIL=1" + +TARGET_CPPFLAGS="$TARGET_CPPFLAGS -Wall -W" + +case "$target_cpu" in + i[[3456]]86) target_cpu=i386 ;; + amd64) target_cpu=x86_64 ;; + sparc) target_cpu=sparc64 ;; + mips64el) + target_cpu=mips64el + machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPS64EL=1" + ;; + mipsel) + target_cpu=mipsel + machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPSEL=1" + ;; + mips|mips64) + target_cpu=mips + machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPS=1" + ;; + arm*) + target_cpu=arm + ;; + aarch64*) + target_cpu=arm64 + ;; + riscv32*) + target_cpu=riscv32 + ;; + riscv64*) + target_cpu=riscv64 + ;; +esac + +# Specify the platform (such as firmware). +AC_ARG_WITH([platform], + AS_HELP_STRING([--with-platform=PLATFORM], + [select the host platform [[guessed]]])) + +# Guess the platform if not specified. +if test "x$with_platform" = x; then + case "$target_cpu"-"$target_vendor" in + i386-apple) platform=efi ;; + i386-*) platform=pc ;; + x86_64-apple) platform=efi ;; + x86_64-*) platform=pc ;; + powerpc-*) platform=ieee1275 ;; + powerpc64-*) platform=ieee1275 ;; + powerpc64le-*) platform=ieee1275 ;; + sparc64-*) platform=ieee1275 ;; + mips64el-*) platform=efi;; + mipsel-*) platform=loongson ;; + mips-*) platform=arc ;; + ia64-*) platform=efi ;; + arm-*) platform=uboot ;; + arm64-*) platform=efi ;; + riscv32-*) platform=efi ;; + riscv64-*) platform=efi ;; + *) + AC_MSG_WARN([unsupported CPU: "$target_cpu" - only building utilities]) + platform=none + ;; + esac +else + platform="$with_platform" +fi + +case "$target_cpu"-"$platform" in + x86_64-efi) ;; + x86_64-emu) ;; + x86_64-xen) ;; + x86_64-none) ;; + x86_64-*) target_cpu=i386 ;; + powerpc64-ieee1275) target_cpu=powerpc ;; + powerpc64le-ieee1275) target_cpu=powerpc ;; +esac + +# Check if the platform is supported, make final adjustments. +case "$target_cpu"-"$platform" in + i386-efi) ;; + x86_64-efi) ;; + i386-xen) ;; + i386-xen_pvh) ;; + x86_64-xen) ;; + i386-pc) ;; + i386-multiboot) ;; + i386-coreboot) ;; + i386-linuxbios) platform=coreboot ;; + i386-ieee1275) ;; + i386-qemu) ;; + powerpc-ieee1275) ;; + sparc64-ieee1275) ;; + ia64-efi) ;; + mips-qemu_mips) ;; + mips-qemu-mips) platform=qemu_mips;; + mips-arc) ;; + mipsel-arc) ;; + mipsel-qemu_mips) ;; + mipsel-qemu-mips) platform=qemu_mips;; + mipsel-yeeloong) platform=loongson ;; + mipsel-fuloong) platform=loongson ;; + mipsel-loongson) ;; + mips64el-efi) ;; + arm-uboot) ;; + arm-coreboot) ;; + arm-efi) ;; + arm64-efi) ;; + riscv32-efi) ;; + riscv64-efi) ;; + *-emu) ;; + *-none) ;; + *) AC_MSG_ERROR([platform "$platform" is not supported for target CPU "$target_cpu"]) ;; +esac + +if test x$platform != xemu ; then + case "$target_cpu" in + i386 | powerpc) target_m32=1 ;; + x86_64 | sparc64) target_m64=1 ;; + esac +fi + +if test x"$target_cpu-$platform" = xsparc64-emu ; then + target_m64=1 +fi + +case "$target_os" in + windows* | mingw32*) target_os=cygwin ;; +esac + +# This normalizes the names, and creates a new variable ("host_kernel") +# while at it, since the mapping is not always 1:1 (e.g. different OSes +# using the same kernel type). +case "$host_os" in + gnu*) host_kernel=hurd ;; + linux*) host_kernel=linux ;; + freebsd* | kfreebsd*-gnu) host_kernel=kfreebsd ;; + netbsd*) host_kernel=netbsd ;; + solaris*) host_kernel=illumos ;; + darwin*) host_kernel=xnu ;; + cygwin | windows* | mingw32*) host_kernel=windows ;; +esac + +case "$host_os" in + cygwin) have_exec=y ;; + windows* | mingw32*) have_exec=n ;; + aros*) have_exec=n ;; + *) have_exec=y;; +esac + +case "$platform" in + coreboot) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_COREBOOT=1" ;; + multiboot) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MULTIBOOT=1" ;; + efi) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EFI=1" ;; + xen) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_XEN=1" ;; + xen_pvh) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_XEN_PVH=1" ;; + ieee1275) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_IEEE1275=1" ;; + uboot) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_UBOOT=1" ;; + qemu) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_QEMU=1" ;; + pc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_PCBIOS=1" ;; + emu) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EMU=1" ;; + loongson) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_LOONGSON=1" ;; + qemu_mips) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_QEMU_MIPS=1" ;; + arc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARC=1" ;; +esac +if test x${target_cpu} = xmipsel ; then + machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE=`echo mips_$platform | sed y,abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ,`" +else + machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE=`echo ${target_cpu}_$platform | sed y,abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ,`" +fi + +case "${target_cpu}-$platform" in + mips-arc) + TARGET_LINK_ADDR=0x88200000 + TARGET_DECOMPRESSOR_LINK_ADDR=0x88100000 + ;; + mipsel-arc) + TARGET_LINK_ADDR=0x80700000 + TARGET_DECOMPRESSOR_LINK_ADDR=0x80600000 + ;; + mips*-qemu_mips | mips*-loongson) + TARGET_DECOMPRESSOR_LINK_ADDR=0x80100000 + ;; +esac + +AC_SUBST(TARGET_LINK_ADDR) +AC_SUBST(TARGET_DECOMPRESSOR_LINK_ADDR) + +TARGET_CPPFLAGS="$TARGET_CPPFLAGS $machine_CPPFLAGS" + +AC_SUBST(host_cpu) +AC_SUBST(host_os) +AC_SUBST(host_kernel) + +AC_SUBST(target_cpu) +AC_SUBST(platform) + +# Define default variables + +have_with_bootdir=n +AC_ARG_WITH([bootdir], + AS_HELP_STRING([--with-bootdir=DIR], + [set the name of /boot directory [[guessed]]]), + [have_with_bootdir=y], + [have_with_bootdir=n]) +if test x$have_with_bootdir = xy; then + bootdirname="$with_bootdir" +else + case "$host_os" in + netbsd* | openbsd*) + # Because /boot is used for the boot block in NetBSD and OpenBSD, + bootdirname='' ;; + *) bootdirname='boot' ;; + esac +fi + +AC_SUBST(bootdirname) +AC_DEFINE_UNQUOTED(GRUB_BOOT_DIR_NAME, "$bootdirname", + [Default boot directory name]) + +AC_ARG_WITH([grubdir], + AS_HELP_STRING([--with-grubdir=DIR], + [set the name of grub directory [[guessed]]]), + [grubdirname="$with_grubdir"], + [grubdirname="$PACKAGE"]) + +AC_SUBST(grubdirname) +AC_DEFINE_UNQUOTED(GRUB_DIR_NAME, "$grubdirname", + [Default grub directory name]) + +# +# Checks for build programs. +# + +# Although cmp is listed in the GNU Coding Standards as a command which +# can used directly, OpenBSD lacks cmp in the default installation. +AC_CHECK_PROGS([CMP], [cmp]) +if test "x$CMP" = x; then + AC_MSG_ERROR([cmp is not found]) +fi + +AC_CHECK_PROGS([YACC], [bison]) +if test "x$YACC" = x; then + AC_MSG_ERROR([bison is not found]) +fi + +AC_PROG_RANLIB +AC_PROG_INSTALL +AC_PROG_AWK +AC_PROG_LEX +AC_PROG_YACC +AC_PROG_MAKE_SET +AC_PROG_MKDIR_P +AC_PROG_LN_S + +if test "x$LEX" = "x:"; then + AC_MSG_ERROR([flex is not found]) +else + version=`$LEX --version | $AWK '{ split($2,x,"."); print x[[1]]*10000+x[[2]]*100+x[[3]]; }'` + if test -n "$version" -a "$version" -ge 20535; then + : + else + AC_MSG_ERROR([flex is too old. GRUB requires 2.5.35 or above]) + fi +fi + +# These are not a "must". +AC_PATH_PROGS(MAKEINFO, makeinfo true) + +# +# Checks for host programs. +# + +AC_PROG_CC +gl_EARLY +AC_PROG_CXX +AM_PROG_CC_C_O +AM_PROG_AS +AM_PATH_PYTHON([2.6]) + +# Must be GCC. +test "x$GCC" = xyes || AC_MSG_ERROR([GCC is required]) + +AC_CHECK_PROG(HAVE_CXX, $CXX, yes, no) + +AC_GNU_SOURCE +AM_GNU_GETTEXT([external]) +AM_GNU_GETTEXT_VERSION([0.18.3]) +AC_SYS_LARGEFILE + +# Identify characteristics of the host architecture. +unset ac_cv_c_bigendian + +if test x"$target_cpu-$platform" = xsparc64-emu ; then + CFLAGS="$CFLAGS -m64" + HOST_CFLAGS="$HOST_CFLAGS -m64" +fi + +CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64" +HOST_CPPFLAGS="$HOST_CPPFLAGS -D_FILE_OFFSET_BITS=64" + +AC_C_BIGENDIAN +AC_CHECK_SIZEOF(void *) +AC_CHECK_SIZEOF(long) + +case "$host_os" in + cygwin | windows* | mingw32*) + HOST_CPPFLAGS="$HOST_CPPFLAGS -DUNICODE=1 -D_WIN32_WINNT=0x0500" + CPPFLAGS="$CPPFLAGS -DUNICODE=1 -D_WIN32_WINNT=0x0500" + AC_CHECK_SIZEOF(TCHAR,,[#include ]) + ;; +esac + +case "$host_os" in + cygwin | windows* | mingw32* | aros*) + ;; + *) + AC_CHECK_SIZEOF(off_t) + if test x"$ac_cv_sizeof_off_t" != x8 ; then + AC_CHECK_SIZEOF(off64_t) + test x"$ac_cv_sizeof_off64_t" = x8 || AC_MSG_ERROR([Large file support is required]) + fi;; +esac + +if test x$USE_NLS = xno; then + HOST_CFLAGS="$HOST_CFLAGS -fno-builtin-gettext" +fi + +if test "x$cross_compiling" = xyes; then + AC_MSG_WARN([cannot generate manual pages while cross compiling]) +else + AC_PATH_PROG(HELP2MAN, help2man) +fi + +# Check for functions and headers. +AC_CHECK_FUNCS(posix_memalign memalign getextmntent) +AC_CHECK_HEADERS(sys/param.h sys/mount.h sys/mnttab.h limits.h) + +# glibc 2.25 still includes sys/sysmacros.h in sys/types.h but emits deprecation +# warning which causes compilation failure later with -Werror. So use -Werror here +# as well to force proper sys/sysmacros.h detection. +SAVED_CFLAGS="$CFLAGS" +CFLAGS="$HOST_CFLAGS -Werror" +AC_HEADER_MAJOR +CFLAGS="$SAVED_CFLAGS" + +AC_CHECK_MEMBERS([struct statfs.f_fstypename],,,[$ac_includes_default +#include +#include ]) + +AC_CHECK_MEMBERS([struct statfs.f_mntfromname],,,[$ac_includes_default +#include +#include ]) + +# For opendisk() and getrawpartition() on NetBSD. +# Used in util/deviceiter.c and in util/hostdisk.c. +AC_CHECK_HEADER([util.h], [ + AC_CHECK_LIB([util], [opendisk], [ + LIBUTIL="-lutil" + AC_DEFINE(HAVE_OPENDISK, 1, [Define if opendisk() in -lutil can be used]) + ]) + AC_CHECK_LIB([util], [getrawpartition], [ + LIBUTIL="-lutil" + AC_DEFINE(HAVE_GETRAWPARTITION, 1, [Define if getrawpartition() in -lutil can be used]) + ]) +]) +AC_SUBST([LIBUTIL]) + +AC_CACHE_CHECK([whether -Wtrampolines work], [grub_cv_host_cc_wtrampolines], [ + SAVED_CFLAGS="$CFLAGS" + CFLAGS="$HOST_CFLAGS -Wtrampolines -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +int va_arg_func (int fixed, va_list args);]], [[]])], + [grub_cv_host_cc_wtrampolines=yes], + [grub_cv_host_cc_wtrampolines=no]) + CFLAGS="$SAVED_CFLAGS" +]) + +if test x"$grub_host_cv_cc_wtrampolines" = xyes ; then + HOST_CFLAGS="$HOST_CFLAGS -Wtrampolines" +fi + +# +# Check for host and build compilers. +# +HOST_CC=$CC +AC_CHECK_PROGS(BUILD_CC, [gcc egcs cc]) +test -z "$BUILD_CC" && AC_MSG_ERROR([none of gcc, egcs and cc is found. set BUILD_CC manually.]) +BUILD_CPP="$BUILD_CC -E" + +case "$build_os" in + haiku*) BUILD_LIBM= ;; + *) BUILD_LIBM=-lm ;; +esac + +dnl FIXME proper test seems to require too deep dive into Autoconf internals. +dnl For now just list known platforms that we support. + +case "$build_os" in + cygwin*|mingw32*|mingw64*) BUILD_EXEEXT=.exe ;; + *) BUILD_EXEEXT= ;; +esac +AC_SUBST(BUILD_EXEEXT) + +# In some build environments like termux /bin/sh is not a valid +# shebang. Use $SHELL instead if it's executable and /bin/sh isn't +BUILD_SHEBANG=/bin/sh +for she in /bin/sh "$SHELL"; do + if test -x "$she" ; then + BUILD_SHEBANG="$she" + fi +done +AC_SUBST(BUILD_SHEBANG) + +# For gnulib. +gl_INIT + +WARN_FLAGS="-Wall -W -Wshadow -Wpointer-arith -Wundef -Wchar-subscripts -Wcomment -Wdeprecated-declarations -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Wformat-extra-args -Wformat-security -Wformat-y2k -Wimplicit -Wimplicit-function-declaration -Wimplicit-int -Wmain -Wmissing-braces -Wmissing-format-attribute -Wmultichar -Wparentheses -Wreturn-type -Wsequence-point -Wshadow -Wsign-compare -Wswitch -Wtrigraphs -Wunknown-pragmas -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wwrite-strings -Wnested-externs -Wstrict-prototypes" +EXTRA_WARN_FLAGS="-Wextra -Wattributes -Wendif-labels -Winit-self -Wint-to-pointer-cast -Winvalid-pch -Wmissing-field-initializers -Wnonnull -Woverflow -Wvla -Wpointer-to-int-cast -Wstrict-aliasing -Wvariadic-macros -Wvolatile-register-var -Wpointer-sign -Wmissing-include-dirs -Wmissing-prototypes -Wmissing-declarations -Wformat=2" + +HOST_CFLAGS="$HOST_CFLAGS $WARN_FLAGS -Wcast-align" + +AC_CACHE_CHECK([which extra warnings work], [grub_cv_cc_w_extra_flags], [ + SAVED_CFLAGS="$CFLAGS" + grub_cv_cc_w_extra_flags= + for x in $EXTRA_WARN_FLAGS; do + CFLAGS="$HOST_CFLAGS $x -Werror" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [flag=1], [flag=0]) + if test x$flag = x1 ; then + grub_cv_cc_w_extra_flags="$grub_cv_cc_w_extra_flags $x" + fi + done + CFLAGS="$SAVED_CFLAGS" +]) + +HOST_CFLAGS="$HOST_CFLAGS $grub_cv_cc_w_extra_flags" + +# +# Check for target programs. +# + +# Find tools for the target. +if test "x$target_alias" != x && test "x$host_alias" != "x$target_alias"; then + tmp_ac_tool_prefix="$ac_tool_prefix" + ac_tool_prefix=$target_alias- + + AC_CHECK_TOOLS(TARGET_CC, [gcc egcs cc], + [AC_MSG_ERROR([none of gcc, egcs and cc is found. set TARGET_CC manually.])]) + AC_CHECK_TOOL(TARGET_OBJCOPY, objcopy) + AC_CHECK_TOOL(TARGET_STRIP, strip) + AC_CHECK_TOOL(TARGET_NM, nm) + AC_CHECK_TOOL(TARGET_RANLIB, ranlib) + + ac_tool_prefix="$tmp_ac_tool_prefix" +else + if test "x$TARGET_CC" = x; then + TARGET_CC=$CC + fi + AC_CHECK_TOOL(TARGET_OBJCOPY, objcopy) + AC_CHECK_TOOL(TARGET_STRIP, strip) + AC_CHECK_TOOL(TARGET_NM, nm) + AC_CHECK_TOOL(TARGET_RANLIB, ranlib) +fi + +AC_SUBST(HOST_CC) +AC_SUBST(BUILD_CC) +AC_SUBST(BUILD_CFLAGS) +AC_SUBST(BUILD_CPPFLAGS) +AC_SUBST(BUILD_LDFLAGS) +AC_SUBST(TARGET_CC) +AC_SUBST(TARGET_NM) +AC_SUBST(TARGET_RANLIB) +AC_SUBST(TARGET_STRIP) +AC_SUBST(TARGET_OBJCOPY) + +# Test the C compiler for the target environment. +tmp_CC="$CC" +tmp_CFLAGS="$CFLAGS" +tmp_LDFLAGS="$LDFLAGS" +tmp_CPPFLAGS="$CPPFLAGS" +tmp_LIBS="$LIBS" +CC="$TARGET_CC" +CFLAGS="$TARGET_CFLAGS" +CPPFLAGS="$TARGET_CPPFLAGS" +LDFLAGS="$TARGET_LDFLAGS" +LIBS="" + +# debug flags. +TARGET_CFLAGS="$TARGET_CFLAGS $WARN_FLAGS -g -Wredundant-decls -Wmissing-prototypes -Wmissing-declarations" +TARGET_CCASFLAGS="$TARGET_CCASFLAGS -g" + +if test "x$target_cpu" != xi386 && test "x$target_cpu" != xx86_64; then +TARGET_CFLAGS="$TARGET_CFLAGS -Wcast-align" +fi + +TARGET_CC_VERSION="$(LC_ALL=C $TARGET_CC --version | head -n1)" + +AC_CACHE_CHECK([which extra warnings work], [grub_cv_target_cc_w_extra_flags], [ + LDFLAGS="$TARGET_LDFLAGS -nostdlib -static" + + grub_cv_target_cc_w_extra_flags= + for x in $EXTRA_WARN_FLAGS; do + CFLAGS="$TARGET_CFLAGS $x -Werror" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +asm (".globl start; start:"); +void __main (void); +void __main (void) {} +int main (void); +]], [[]])], [flag=1], [flag=0]) + if test x$flag = x1 ; then + grub_cv_target_cc_w_extra_flags="$grub_cv_target_cc_w_extra_flags $x" + fi + done +]) + +TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_w_extra_flags" + +AC_CACHE_CHECK([if compiling with clang], [grub_cv_cc_target_clang], +[ +CFLAGS="$TARGET_CFLAGS" +AC_COMPILE_IFELSE( +[AC_LANG_PROGRAM([], [[ +#ifdef __clang__ +#error "is clang" +#endif +]])], +[grub_cv_cc_target_clang=no], [grub_cv_cc_target_clang=yes])]) + +if test x$target_cpu = xpowerpc -o x$target_cpu = xmips; then + AC_CACHE_CHECK([for options to get big-endian compilation], grub_cv_target_cc_big_endian, [ + grub_cv_target_cc_big_endian=no + for cand in "-target $target_cpu -Wl,-EB" "-target $target_cpu" \ + "-target $target_cpu-linux-gnu -Wl,-EB" "-target $target_cpu-linux-gnu" \ + "-EB" "-mbig-endian"; do + if test x"$grub_cv_target_cc_big_endian" != xno ; then + break + fi + CFLAGS="$TARGET_CFLAGS $cand -Werror" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__ORDER_BIG_ENDIAN__ != __BYTE_ORDER__) +#error still little endian +#endif +asm (".globl start; start:"); +asm (".globl _start; _start:"); +asm (".globl __start; __start:"); +void __main (void); +void __main (void) {} +int main (void); +]], [[]])], + [grub_cv_target_cc_big_endian="$cand"], []) + done + ]) + + if test x"$grub_cv_target_cc_big_endian" = xno ; then + AC_MSG_ERROR([could not force big-endian]) + fi + + skip_linkflags="$(echo "$grub_cv_target_cc_big_endian"|sed 's@-Wl,-EB@@')" + + TARGET_CFLAGS="$TARGET_CFLAGS $skip_linkflags" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS $skip_linkflags" + TARGET_CCASFLAGS="$TARGET_CCASFLAGS $skip_linkflags" + TARGET_LDFLAGS="$TARGET_LDFLAGS $grub_cv_target_cc_big_endian" +elif test x$target_cpu = xmipsel; then + AC_CACHE_CHECK([for options to get little-endian compilation], grub_cv_target_cc_little_endian, [ + grub_cv_target_cc_little_endian=no + for cand in "-target $target_cpu -Wl,-EL" "-target $target_cpu" \ + "-target $target_cpu-linux-gnu -Wl,-EL" "-target $target_cpu-linux-gnu" \ + "-EL"; do + if test x"$grub_cv_target_cc_little_endian" != xno ; then + break + fi + CFLAGS="$TARGET_CFLAGS $cand -Werror" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__ORDER_BIG_ENDIAN__ == __BYTE_ORDER__) +#error still big endian +#endif +asm (".globl start; start:"); +asm (".globl _start; _start:"); +asm (".globl __start; __start:"); +void __main (void); +void __main (void) {} +int main (void); +]], [[]])], + [grub_cv_target_cc_little_endian="$cand"], []) + done + ]) + + if test x"$grub_cv_target_cc_little_endian" = xno ; then + AC_MSG_ERROR([could not force little-endian]) + fi + + skip_linkflags="$(echo "$grub_cv_target_cc_little_endian"|sed 's@-Wl,-EL@@')" + + TARGET_CFLAGS="$TARGET_CFLAGS $skip_linkflags" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS $skip_linkflags" + TARGET_CCASFLAGS="$TARGET_CCASFLAGS $skip_linkflags" + TARGET_LDFLAGS="$TARGET_LDFLAGS $grub_cv_target_cc_little_endian" +fi + +# GRUB code is N32-compliant but it's experimental and we would prefer to +# avoid having too much variety when it doesn't result in any real improvement. +# Moreover N64 isn't supported. +if test "x$target_cpu" = xmips || test "x$target_cpu" = xmipsel ; then + AC_CACHE_CHECK([for options to force MIPS o32 ABI], grub_cv_target_cc_mips_o32_abi, [ + grub_cv_target_cc_mips_o32_abi=no + for arg in "" "-mabi=32" "-target $target_cpu -mabi=32" ; do + if test x"$grub_cv_target_cc_mips_o32_abi" != xno ; then + break + fi + CFLAGS="$TARGET_CFLAGS $arg -Werror" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#if !defined(_ABIO32) || !defined(_MIPS_SIM) || (_MIPS_SIM != _ABIO32) +#error not o32 ABI +#endif +asm (".globl start; start:"); +asm (".globl _start; _start:"); +asm (".globl __start; __start:"); +void __main (void); +void __main (void) {} +int main (void); +]], [[]])], + [grub_cv_target_cc_mips_o32_abi="$arg"], []) + done + ]) + + if test x"$grub_cv_target_cc_mips_o32_abi" = xno ; then + AC_MSG_ERROR([could not force MIPS o32 ABI]) + fi + + TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_mips_o32_abi" + TARGET_CCASFLAGS="$TARGET_CCASFLAGS $grub_cv_target_cc_mips_o32_abi" +fi + +AC_CACHE_CHECK([for options to compile assembly], [grub_cv_cc_target_asm_compile], [ +test_program= +case "x$target_cpu-$platform" in + xmips-* | xmipsel-*) + test_program=mips + ;; + xi386-pc) + test_program=i386-pc + ;; + xi386-* | xx86_64-*) + test_program=i386 + ;; + xpowerpc-* | xsparc64-* | xarm-*) + test_program=$target_cpu + ;; +esac +if test x"$test_program" = x ; then + grub_cv_cc_target_asm_compile= +else + found=no + for arg in "" "-no-integrated-as"; do + cmdline="$TARGET_CC -c -o /dev/null $TARGET_CCASFLAGS $arg $TARGET_CPPFLAGS $srcdir/asm-tests/$test_program.S" + echo "Running $cmdline" >&AS_MESSAGE_LOG_FD + if $cmdline >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then + grub_cv_cc_target_asm_compile="$arg" + found=yes + break + fi + done + if test x"$found" = xno ; then + AC_MSG_ERROR([could not compile assembly]) + fi +fi +]) + +TARGET_CCASFLAGS="$TARGET_CCASFLAGS $grub_cv_cc_target_asm_compile" + +if test "x$target_cpu" = xi386 && test "x$platform" != xemu; then + TARGET_CFLAGS="$TARGET_CFLAGS -march=i386" +fi + +if test "x$target_m32" = x1; then + # Force 32-bit mode. + TARGET_CFLAGS="$TARGET_CFLAGS -m32" + TARGET_CCASFLAGS="$TARGET_CCASFLAGS -m32" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -m32" + TARGET_LDFLAGS="$TARGET_LDFLAGS -m32" + TARGET_MODULE_FORMAT="elf32" +fi + +if test "x$target_m64" = x1; then + # Force 64-bit mode. + TARGET_CFLAGS="$TARGET_CFLAGS -m64" + TARGET_CCASFLAGS="$TARGET_CCASFLAGS -m64" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -m64" + TARGET_LDFLAGS="$TARGET_LDFLAGS -m64" + TARGET_MODULE_FORMAT="elf64" +fi + +if test "x$grub_cv_cc_target_clang" = xno && test "x$target_cpu" = xi386 && test "x$platform" != xemu && test "x$platform" != xefi; then + TARGET_CFLAGS="$TARGET_CFLAGS -mrtd -mregparm=3" +fi + +# on mips redirect cache flushing function to non-existant one. +if test "x$target_cpu" = xmips || test "x$target_cpu" = xmipsel ; then + AC_CACHE_CHECK([whether -mflush-func=grub_red_herring works], [grub_cv_cc_mflush_func], [ + CFLAGS="$TARGET_CFLAGS -mflush-func=grub_red_herring -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_mflush_func=yes], + [grub_cv_cc_mflush_func=no]) + ]) + + if test "x$grub_cv_cc_mflush_func" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -mflush-func=grub_red_herring" + fi +fi + + +# Force no alignment to save space on i386. +if test "x$target_cpu" = xi386; then + AC_CACHE_CHECK([whether -falign-loops works], [grub_cv_cc_falign_loop], [ + CFLAGS="$TARGET_CFLAGS -falign-loops=1 -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_falign_loop=yes], + [grub_cv_cc_falign_loop=no]) + ]) + + AC_CACHE_CHECK([whether -malign-loops works], [grub_cv_cc_malign_loop], [ + CFLAGS="$TARGET_CFLAGS -malign-loops=1 -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_malign_loop=yes], + [grub_cv_cc_malign_loop=no]) + ]) + + if test "x$grub_cv_cc_falign_loop" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -falign-jumps=1 -falign-loops=1 -falign-functions=1" + elif test "x$grub_cv_cc_malign_loop" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -malign-jumps=1 -malign-loops=1 -malign-functions=1" + fi +fi + +AC_CACHE_CHECK([whether -freg-struct-return works], [grub_cv_cc_freg_struct_return], [ + CFLAGS="$TARGET_CFLAGS -freg-struct-return -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_freg_struct_return=yes], + [grub_cv_cc_freg_struct_return=no]) +]) + +if test "x$grub_cv_cc_freg_struct_return" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -freg-struct-return" +fi + +if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$platform" != xemu; then + # Some toolchains enable these features by default, but they need + # registers that aren't set up properly in GRUB. + TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow" +fi + +# GRUB doesn't use float or doubles at all. Yet some toolchains may decide +# that floats are a good fit to run instead of what's written in the code. +# Given that floating point unit is disabled (if present to begin with) +# when GRUB is running which may result in various hard crashes. +#if test x"$platform" != xemu ; then +if ( test x"$platform" != xemu && x"$platform" != mips64el-efi ) ; then + AC_CACHE_CHECK([for options to get soft-float], grub_cv_target_cc_soft_float, [ + grub_cv_target_cc_soft_float=no + if test "x$target_cpu" = xarm64; then + CFLAGS="$TARGET_CFLAGS -mgeneral-regs-only -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_soft_float="-mgeneral-regs-only"], []) + fi + if test "x$target_cpu" = xriscv32; then + CFLAGS="$TARGET_CFLAGS -march=rv32imac -mabi=ilp32 -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_soft_float="-march=rv32imac -mabi=ilp32"], []) + fi + if test "x$target_cpu" = xriscv64; then + CFLAGS="$TARGET_CFLAGS -march=rv64imac -mabi=lp64 -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_soft_float="-march=rv64imac -mabi=lp64"], []) + fi + if test "x$target_cpu" = xia64; then + CFLAGS="$TARGET_CFLAGS -mno-inline-float-divide -mno-inline-sqrt -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_soft_float="-mno-inline-float-divide -mno-inline-sqrt"], []) + fi + for cand in "-msoft-float -Xclang -msoft-float -Xclang -no-implicit-float" \ + "-Xclang -msoft-float -Xclang -no-implicit-float" \ + "-Xclang -msoft-float" "-msoft-float"; do + if test x"$grub_cv_target_cc_soft_float" != xno ; then + break + fi + CFLAGS="$TARGET_CFLAGS $cand -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_soft_float="$cand"], []) + done + ]) + + if test x"$grub_cv_target_cc_soft_float" = xno ; then + AC_MSG_ERROR([could not force soft-float]) + fi + + case x"$grub_cv_target_cc_soft_float" in + x*"-Xclang"*) + # A trick so that clang doesn't see it on link stаge + TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_soft_float" + ;; + *) + TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_soft_float" + ;; + esac + TARGET_CCASFLAGS="$TARGET_CCASFLAGS $grub_cv_target_cc_soft_float" + +fi + +if test x"$target_cpu" = xsparc64 ; then + AC_CACHE_CHECK([for options to reserve application registers], grub_cv_target_cc_mno_app_regs, [ + grub_cv_target_cc_mno_app_regs=no + for cand in "-mllvm -sparc-reserve-app-registers" \ + "-mno-app-regs"; do + if test x"$grub_cv_target_cc_mno_app_regs" != xno ; then + break + fi + CFLAGS="$TARGET_CFLAGS $cand -Werror" + CPPFLAGS="$TARGET_CPPFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_mno_app_regs="$cand"], []) + done + ]) + + if test x"$grub_cv_target_cc_mno_app_regs" = xno ; then + AC_MSG_ERROR([could not reserve application registers]) + fi + if test x"$grub_cv_target_cc_mno_app_regs" = x"-mllvm -sparc-reserve-app-registers" ; then + # A trick so that clang doesn't see it on link stаge + TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_app_regs" + else + TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_mno_app_regs" + fi + + AC_CACHE_CHECK([for no-relax options], grub_cv_target_cc_mno_relax, [ + grub_cv_target_cc_mno_relax=no + for cand in "-mno-relax" "-Wl,--no-relax"; do + if test x"$grub_cv_target_cc_mno_relax" != xno ; then + break + fi + LDFLAGS="$TARGET_LDFLAGS $cand -nostdlib -static" + CFLAGS="$TARGET_CFLAGS -Werror" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + asm (".globl start; start:"); + void __main (void); + void __main (void) {} + int main (void); + ]], [[]])], [grub_cv_target_cc_mno_relax="$cand"], []) + done + ]) + LDFLAGS="$TARGET_LDFLAGS" + CFLAGS="$TARGET_CFLAGS" + + if test x"$grub_cv_target_cc_mno_relax" = xno ; then + AC_MSG_ERROR([could not find no-relax options]) + fi + TARGET_LDFLAGS="$TARGET_LDFLAGS $grub_cv_target_cc_mno_relax" +fi + +# By default, GCC 4.4 generates .eh_frame sections containing unwind +# information in some cases where it previously did not. GRUB doesn't need +# these and they just use up vital space. Restore the old compiler +# behaviour. +AC_CACHE_CHECK([whether -fno-dwarf2-cfi-asm works], [grub_cv_cc_fno_dwarf2_cfi_asm], [ + CFLAGS="$TARGET_CFLAGS -fno-dwarf2-cfi-asm" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_fno_dwarf2_cfi_asm=yes], + [grub_cv_cc_fno_dwarf2_cfi_asm=no]) +]) + +if test "x$grub_cv_cc_fno_dwarf2_cfi_asm" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -fno-dwarf2-cfi-asm" +fi + +if test x"$target_os" = xcygwin; then + AC_CACHE_CHECK([whether option -fno-reorder-functions works], grub_cv_cc_no_reorder_functions, [ + CFLAGS="$TARGET_CFLAGS -fno-reorder-functions" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_no_reorder_functions=yes], + [grub_cv_cc_no_reorder_functions=no]) + ]) +fi + +if test x"$target_os" = xcygwin && test "x$grub_cv_cc_no_reorder_functions" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -fno-reorder-functions" +fi + +AC_CACHE_CHECK([whether -mno-stack-arg-probe works], [grub_cv_cc_mno_stack_arg_probe], [ + CFLAGS="$TARGET_CFLAGS -mno-stack-arg-probe" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_mno_stack_arg_probe=yes], + [grub_cv_cc_mno_stack_arg_probe=no]) +]) + +if test "x$grub_cv_cc_mno_stack_arg_probe" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -mno-stack-arg-probe" +fi + + +# By default, GCC 4.6 generates .eh_frame sections containing unwind +# information in some cases where it previously did not. GRUB doesn't need +# these and they just use up vital space. Restore the old compiler +# behaviour. +AC_CACHE_CHECK([whether -fno-asynchronous-unwind-tables works], [grub_cv_cc_fno_asynchronous_unwind_tables], [ + CFLAGS="$TARGET_CFLAGS -fno-asynchronous-unwind-tables" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_fno_asynchronous_unwind_tables=yes], + [grub_cv_cc_fno_asynchronous_unwind_tables=no]) +]) + +if test "x$grub_cv_cc_fno_asynchronous_unwind_tables" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -fno-asynchronous-unwind-tables" +fi + +AC_CACHE_CHECK([whether -fno-unwind-tables works], [grub_cv_cc_fno_unwind_tables], [ + CFLAGS="$TARGET_CFLAGS -fno-unwind-tables" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_fno_unwind_tables=yes], + [grub_cv_cc_fno_unwind_tables=no]) +]) + +if test "x$grub_cv_cc_fno_unwind_tables" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -fno-unwind-tables" +fi + + +CFLAGS="$TARGET_CFLAGS" + + +if test x"$platform" = xemu ; then + TARGET_OBJ2ELF= + grub_cv_target_cc_link_format= + case "$host_os" in + *darwin* | *mac*) + grub_cv_target_cc_link_format="-arch,${target_cpu}" + TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,$grub_cv_target_cc_link_format" + ;; + *windows* | *cygwin* | *mingw*) + if test x${target_cpu} = xi386 ; then + grub_cv_target_cc_link_format=-mi386pe + TARGET_OBJ2ELF='./build-grub-pe2elf$(BUILD_EXEEXT)' + fi + if test x${target_cpu} = xx86_64 ; then + grub_cv_target_cc_link_format=-mi386pep + TARGET_OBJ2ELF='./build-grub-pep2elf$(BUILD_EXEEXT)' + fi + TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,$grub_cv_target_cc_link_format" + ;; + esac +elif test x"$target_cpu" = xi386 || test x"$target_cpu" = xx86_64; then + AC_CACHE_CHECK([for target linking format], [grub_cv_target_cc_link_format], [ + grub_cv_target_cc_link_format=unknown + for format in -melf_${target_cpu} -melf_${target_cpu}_fbsd -melf_${target_cpu}_obsd -melf_${target_cpu}_haiku -mi386pe -mi386pep -arch,${target_cpu}; do + if test x${target_cpu} != xi386 && test x$format = x-mi386pe; then + continue + fi + if test x${target_cpu} != xx86_64 && test x$format = x-mi386pep; then + continue + fi + CFLAGS="$TARGET_CFLAGS" + LDFLAGS="$TARGET_LDFLAGS -Wl,$format -nostdlib -static" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + asm (".globl start; start:"); + asm (".globl _start; _start:"); + asm (".globl __start; __start:"); + void __main (void); + void __main (void) {} + ]], [[]])], [flag=1], [flag=0]) + if test x"$flag" = x1; then + grub_cv_target_cc_link_format="$format" + break + fi + done]) + if test x"$grub_cv_target_cc_link_format" = xunknown; then + AC_MSG_ERROR([no suitable link format found]) + fi + TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,$grub_cv_target_cc_link_format" + if test x"$grub_cv_target_cc_link_format" = x-mi386pe ; then + TARGET_OBJ2ELF='./build-grub-pe2elf$(BUILD_EXEEXT)' + fi + if test x"$grub_cv_target_cc_link_format" = x-mi386pep ; then + TARGET_OBJ2ELF='./build-grub-pep2elf$(BUILD_EXEEXT)' + fi +fi + +if test x$grub_cv_target_cc_link_format = x-arch,i386 || test x$grub_cv_target_cc_link_format = x-arch,x86_64; then + TARGET_APPLE_LINKER=1 + AC_CHECK_PROG([TARGET_OBJCONV], [objconv], [objconv], []) + if test "x$TARGET_OBJCONV" = x ; then + AC_CHECK_PROG([TARGET_OBJCONV], [objconv], [./objconv], [], [.]) + fi + if test "x$TARGET_OBJCONV" = x ; then + AC_MSG_ERROR([objconv not found which is required when building with apple compiler]) + fi + TARGET_IMG_LDSCRIPT= + TARGET_IMG_CFLAGS="-static" + TARGET_IMG_LDFLAGS='-nostdlib -static -Wl,-preload -Wl,-segalign,20' + TARGET_IMG_LDFLAGS_AC='-nostdlib -static -Wl,-preload -Wl,-segalign,20' + TARGET_IMG_BASE_LDOPT="-Wl,-image_base" + TARGET_LDFLAGS_OLDMAGIC="" +elif test x$grub_cv_target_cc_link_format = x-mi386pe || test x$grub_cv_target_cc_link_format = x-mi386pep ; then + TARGET_APPLE_LINKER=0 + TARGET_LDFLAGS_OLDMAGIC="-Wl,-N" + TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/${grub_coredir}/conf/i386-cygwin-img-ld.sc" + TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}" + TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/${grub_coredir}/conf/i386-cygwin-img-ld.sc" + TARGET_IMG_BASE_LDOPT="-Wl,-Ttext" + TARGET_IMG_CFLAGS= +else + TARGET_APPLE_LINKER=0 + TARGET_LDFLAGS_OLDMAGIC="-Wl,-N" + TARGET_IMG_LDSCRIPT= + TARGET_IMG_LDFLAGS='-Wl,-N' + TARGET_IMG_LDFLAGS_AC='-Wl,-N' + TARGET_IMG_BASE_LDOPT="-Wl,-Ttext" + TARGET_IMG_CFLAGS= +fi + +CFLAGS="$TARGET_CFLAGS" + +AC_ARG_ENABLE([efiemu], + [AS_HELP_STRING([--enable-efiemu], + [build and install the efiemu runtimes (default=guessed)])]) +if test x"$enable_efiemu" = xno ; then + efiemu_excuse="explicitly disabled" +fi + +if test x"$grub_cv_target_cc_link_format" = x-mi386pe || test x"$grub_cv_target_cc_link_format" = x-mi386pep ; then + efiemu_excuse="not available on cygwin" +fi +if test x"$target_cpu" != xi386 ; then + efiemu_excuse="only available on i386" +fi +if test x"$platform" = xefi ; then + efiemu_excuse="not available on efi" +fi + +if test x"$efiemu_excuse" = x ; then + AC_CACHE_CHECK([whether options required for efiemu work], grub_cv_cc_efiemu, [ + CFLAGS="-m64 -nostdlib -O2 -mcmodel=large -mno-red-zone" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_efiemu=yes], + [grub_cv_cc_efiemu=no]) + ]) + if test x$grub_cv_cc_efiemu = xno; then + efiemu_excuse="cannot compile with -m64 -mcmodel=large -mno-red-zone -nostdlib" + fi +fi +if test x"$efiemu_excuse" = x ; then + AC_CACHE_CHECK([for efiemu64 linking format], [grub_cv_target_cc_efiemu64_link_format], [ + grub_cv_target_cc_efiemu64_link_format=unknown + for format in -melf_x86_64 -melf_x86_64_fbsd -melf_x86_64_obsd -melf_x86_64_haiku -arch,x86_64; do + CFLAGS="-m64 -nostdlib -O2 -mcmodel=large -mno-red-zone" + LDFLAGS="-m64 -Wl,$format -nostdlib -static" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ + asm (".globl start; start:"); + asm (".globl _start; _start:"); + asm (".globl __start; __start:"); + void __main (void); + void __main (void) {} + ]], [[]])], [flag=1], [flag=0]) + if test x"$flag" = x1; then + grub_cv_target_cc_efiemu64_link_format="$format" + break + fi + done]) + if test x"$grub_cv_target_cc_efiemu64_link_format" = xunknown; then + efiemu_excuse="no suitable link format for efiemu64 found" + else + EFIEMU64_LINK_FORMAT="-Wl,$grub_cv_target_cc_efiemu64_link_format" + fi +fi +if test x"$enable_efiemu" = xyes && test x"$efiemu_excuse" != x ; then + AC_MSG_ERROR([efiemu runtime was explicitly requested but can't be compiled ($efiemu_excuse)]) +fi +if test x"$efiemu_excuse" = x ; then +enable_efiemu=yes +else +enable_efiemu=no +fi +AC_SUBST([enable_efiemu]) +AC_SUBST([EFIEMU64_LINK_FORMAT]) + +CFLAGS="$TARGET_CFLAGS" + +AC_SUBST(TARGET_LDFLAGS_OLDMAGIC) + + +LDFLAGS="$TARGET_LDFLAGS" + +if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64 ; then + # Use large model to support 4G memory + AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [ + CFLAGS="$TARGET_CFLAGS -mcmodel=large" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_mcmodel=yes], + [grub_cv_cc_mcmodel=no]) + ]) + if test "x$grub_cv_cc_mcmodel" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=large" + elif test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64; then + TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany" + fi +fi + +if test "$target_cpu"-"$platform" = x86_64-efi; then + # EFI writes to stack below %rsp, we must not use the red zone + AC_CACHE_CHECK([whether option -mno-red-zone works], grub_cv_cc_no_red_zone, [ + CFLAGS="$TARGET_CFLAGS -mno-red-zone" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_no_red_zone=yes], + [grub_cv_cc_no_red_zone=no]) + ]) + if test "x$grub_cv_cc_no_red_zone" = xno; then + AC_MSG_ERROR([-mno-red-zone not supported, upgrade your gcc]) + fi + + TARGET_CFLAGS="$TARGET_CFLAGS -mno-red-zone" +fi + +if test "x$target_cpu" = xarm; then + AC_CACHE_CHECK([for options to disable movt and movw], grub_cv_target_cc_mno_movt, [ + grub_cv_target_cc_mno_movt=no + for cand in "-mno-movt" \ + "-mllvm -arm-use-movt=0"; do + if test x"$grub_cv_target_cc_mno_movt" != xno ; then + break + fi + CFLAGS="$TARGET_CFLAGS $cand -Werror" + CPPFLAGS="$TARGET_CPPFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_mno_movt="$cand"], []) + done + ]) + + if test x"$grub_cv_target_cc_mno_movt" != xno ; then + # A trick so that clang doesn't see it on link stage + TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_movt" + fi + AC_CACHE_CHECK([whether option -mthumb-interwork works], grub_cv_cc_mthumb_interwork, [ + CFLAGS="$TARGET_CFLAGS -mthumb-interwork -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_mthumb_interwork=yes], + [grub_cv_cc_mthumb_interwork=no]) + ]) + if test "x$grub_cv_cc_mthumb_interwork" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -mthumb-interwork" + # Clang defaults to thumb interworking + elif test "x$grub_cv_cc_target_clang" = xno ; then + AC_MSG_ERROR([your compiler doesn't support -mthumb-interwork]) + fi +fi + +AC_CACHE_CHECK([whether option -Qn works], grub_cv_target_cc_qn, [ + CFLAGS="$TARGET_CFLAGS -Qn -Qunused-arguments -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_target_cc_qn=yes], + [grub_cv_target_cc_qn=no])]) +if test "x$grub_cv_target_cc_qn" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -Qn -Qunused-arguments" +fi + +# +# Compiler features. +# + +CFLAGS="$TARGET_CFLAGS" + +# Position independent executable. +grub_CHECK_PIE +grub_CHECK_NO_PIE +grub_CHECK_NO_PIE_ONEWORD +grub_CHECK_LINK_PIE +[# Need that, because some distributions ship compilers that include +# `-fPIE' or '-fpie' and '-pie' in the default specs. +if [ x"$pie_possible" = xyes ]; then + TARGET_CFLAGS="$TARGET_CFLAGS -fno-PIE -fno-pie" +fi + +if [ x"$link_nopie_needed" = xyes ] || [ x"$pie_possible" = xyes ]; then + if [ x"$nopie_possible" = xyes ]; then + TARGET_LDFLAGS="$TARGET_LDFLAGS -no-pie" + fi + if [ x"$nopie_oneword_possible" = xyes ]; then + TARGET_LDFLAGS="$TARGET_LDFLAGS -nopie" + fi +fi] + +CFLAGS="$TARGET_CFLAGS" +LDFLAGS="$TARGET_LDFLAGS" + +# Position independent executable. +grub_CHECK_PIC +[# On most platforms we don't want PIC as it only makes relocations harder +# and code less efficient. On mips we want to have one got table per module +# and reload $gp in every function. +# GCC implements it using symbol __gnu_local_gp in non-PIC as well. +# However with clang we need PIC for this reloading to happen. +# With arm64 we need relocations that are in some way representable in +# PE as we need to support arm64-efi. Without -fPIC clang generates +# movk's which aren't representable. +# Since default varies across dictributions use either -fPIC or -fno-PIC +# explicitly. +if ( test x$target_cpu = xmips || test x$target_cpu = xmipsel || test x$target_cpu = xarm64 || test x$target_cpu = xmips64el ) && test "x$grub_cv_cc_target_clang" = xyes ; then + TARGET_CFLAGS="$TARGET_CFLAGS -fPIC" +elif [ x"$pic_possible" = xyes ]; then + TARGET_CFLAGS="$TARGET_CFLAGS -fno-PIC" +fi +# Don't generate SVR4-style position-independent code for MIPS64. +if test x$target_cpu = xmips64el ; then + TARGET_CFLAGS="$TARGET_CFLAGS -mno-abicalls" + TARGET_CCASFLAGS="$TARGET_CCASFLAGS -mno-abicalls" +fi] + +CFLAGS="$TARGET_CFLAGS" + +# Smashing stack protector. +grub_CHECK_STACK_PROTECTOR +# Need that, because some distributions ship compilers that include +# `-fstack-protector' in the default specs. +if test "x$ssp_possible" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -fno-stack-protector" +fi + +CFLAGS="$TARGET_CFLAGS" + +grub_CHECK_STACK_ARG_PROBE +# Cygwin's GCC uses alloca() to probe the stackframe on static +# stack allocations above some threshold. +if test x"$sap_possible" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -mno-stack-arg-probe" +fi + +CFLAGS="$TARGET_CFLAGS" + +# -mno-unaligned-access -mstrict-align +if test "$target_cpu" = arm; then + AC_CACHE_CHECK([for compile options to get strict alignment], [grub_cv_target_cc_strict_align], [ + grub_cv_target_cc_strict_align= + for arg in -mno-unaligned-access "-Xclang -mstrict-align" -mstrict-align; do + CFLAGS="$TARGET_CFLAGS $arg -Werror" + LDFLAGS="$TARGET_LDFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [flag=1], [flag=0]) + if test x"$flag" = x1; then + grub_cv_target_cc_strict_align="$arg" + break + fi + done]) + + TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_strict_align" + if test x"$grub_cv_target_cc_strict_align" = x"-Xclang -mstrict-align"; then + TARGET_LDFLAGS="$TARGET_LDFLAGS -Qunused-arguments" + fi + AC_CACHE_CHECK([if compiler generates unaligned accesses], [grub_cv_cc_target_emits_unaligned], + [CFLAGS="$TARGET_CFLAGS" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[ +#ifdef __ARM_FEATURE_UNALIGNED +#error "unaligned" +#endif + ]])], + [grub_cv_cc_target_emits_unaligned=no], [grub_cv_cc_target_emits_unaligned=yes])]) + if test x$grub_cv_cc_target_emits_unaligned = xyes; then + AC_MSG_ERROR([compiler generates unaligned accesses]) + fi +fi + +# Set them to their new values for the tests below. +CC="$TARGET_CC" +if test x"$platform" = xemu ; then +CFLAGS="$TARGET_CFLAGS -Wno-error" +elif test "x$TARGET_APPLE_LINKER" = x1 ; then +CFLAGS="$TARGET_CFLAGS -nostdlib -static -Wno-error" +else +CFLAGS="$TARGET_CFLAGS -nostdlib -Wno-error" +fi +CPPFLAGS="$TARGET_CPPFLAGS" + +grub_ASM_USCORE +if test "x$TARGET_APPLE_LINKER" = x0 && test x"$platform" != xemu; then +if test x$grub_cv_asm_uscore = xyes; then +DEFSYM="-Wl,--defsym,_abort=_main -Wl,--defsym,__main=_main" +else +DEFSYM="-Wl,--defsym,abort=main -Wl,--defsym,_main=main -Wl,--defsym,__main=main" +fi +CFLAGS="$TARGET_CFLAGS -nostdlib $DEFSYM" +fi + +# Check for libgcc symbols +if test x"$platform" = xemu; then +AC_CHECK_FUNCS(__udivsi3 __umodsi3 __divsi3 __modsi3 __divdi3 __moddi3 __udivdi3 __umoddi3 __ctzdi2 __ctzsi2 __aeabi_uidiv __aeabi_uidivmod __aeabi_idiv __aeabi_idivmod __aeabi_ulcmp __muldi3 __aeabi_lmul __aeabi_memcpy __aeabi_memcpy4 __aeabi_memcpy8 __aeabi_memclr __aeabi_memclr4 __aeabi_memclr8 __aeabi_memset __aeabi_lasr __aeabi_llsl __aeabi_llsr _restgpr_14_x __ucmpdi2 __ashldi3 __ashrdi3 __lshrdi3 __bswapsi2 __bswapdi2 __bzero __register_frame_info __deregister_frame_info ___chkstk_ms __chkstk_ms) +fi + +if test "x$TARGET_APPLE_LINKER" = x1 ; then +CFLAGS="$TARGET_CFLAGS -nostdlib -static" +else +CFLAGS="$TARGET_CFLAGS -nostdlib" +fi +LIBS="" + +# Defined in aclocal.m4. +grub_PROG_TARGET_CC +if test "x$TARGET_APPLE_LINKER" != x1 ; then +grub_PROG_OBJCOPY_ABSOLUTE +fi +grub_PROG_LD_BUILD_ID_NONE +if test "x$target_cpu" = xi386; then + if test "$platform" != emu && test "x$TARGET_APPLE_LINKER" != x1 ; then + if test ! -z "$TARGET_IMG_LDSCRIPT"; then + # Check symbols provided by linker script. + CFLAGS="$TARGET_CFLAGS -nostdlib ${TARGET_IMG_LDFLAGS_AC} ${TARGET_IMG_BASE_LDOPT},0x8000" + fi + grub_CHECK_BSS_START_SYMBOL + grub_CHECK_END_SYMBOL + fi + CFLAGS="$TARGET_CFLAGS" +fi + +grub_PROG_NM_WORKS +grub_PROG_NM_MINUS_P +grub_PROG_NM_DEFINED_ONLY +AC_SUBST(TARGET_NMFLAGS_MINUS_P) +AC_SUBST(TARGET_NMFLAGS_DEFINED_ONLY) + +if test "$platform" != emu; then +AC_CACHE_CHECK([whether -nostdinc -isystem works], [grub_cv_cc_isystem], [ + SAVED_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$TARGET_CPPFLAGS -nostdlib -nostdinc -isystem `$TARGET_CC -print-file-name=include`" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +#include +int va_arg_func (int fixed, va_list args);]], [[]])], + [grub_cv_cc_isystem=yes], + [grub_cv_cc_isystem=no]) + CPPFLAGS="$SAVED_CPPFLAGS" +]) + +if test x"$grub_cv_cc_isystem" = xyes ; then + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -nostdinc -isystem `$TARGET_CC -print-file-name=include`" +fi +fi + +AC_CACHE_CHECK([whether -Wtrampolines work], [grub_cv_cc_wtrampolines], [ + CFLAGS="$TARGET_CFLAGS -Wtrampolines -Werror" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include +int va_arg_func (int fixed, va_list args);]], [[]])], + [grub_cv_cc_wtrampolines=yes], + [grub_cv_cc_wtrampolines=no]) +]) + +if test x"$grub_cv_cc_wtrampolines" = xyes ; then + TARGET_CFLAGS="$TARGET_CFLAGS -Wtrampolines" +fi + +# Restore the flags. +CC="$tmp_CC" +CFLAGS="$tmp_CFLAGS" +CPPFLAGS="$tmp_CPPFLAGS" +LDFLAGS="$tmp_LDFLAGS" +LIBS="$tmp_LIBS" + +# +# Check for options. +# + +# Memory manager debugging. +AC_ARG_ENABLE([mm-debug], + AS_HELP_STRING([--enable-mm-debug], + [include memory manager debugging]), + [AC_DEFINE([MM_DEBUG], [1], + [Define to 1 if you enable memory manager debugging.])]) + +AC_ARG_ENABLE([cache-stats], + AS_HELP_STRING([--enable-cache-stats], + [enable disk cache statistics collection])) + +if test x$enable_cache_stats = xyes; then + DISK_CACHE_STATS=1 +else + DISK_CACHE_STATS=0 +fi +AC_SUBST([DISK_CACHE_STATS]) + +AC_ARG_ENABLE([boot-time], + AS_HELP_STRING([--enable-boot-time], + [enable boot time statistics collection])) + +if test x$enable_boot_time = xyes; then + BOOT_TIME_STATS=1 +else + BOOT_TIME_STATS=0 +fi +AC_SUBST([BOOT_TIME_STATS]) + +AC_ARG_ENABLE([grub-emu-sdl], + [AS_HELP_STRING([--enable-grub-emu-sdl], + [build and install the `grub-emu' debugging utility with SDL support (default=guessed)])]) + +AC_ARG_ENABLE([grub-emu-pci], + [AS_HELP_STRING([--enable-grub-emu-pci], + [build and install the `grub-emu' debugging utility with PCI support (potentially dangerous) (default=no)])]) + +if test "$platform" = emu; then + +if test x"$enable_grub_emu_sdl" = xno ; then + grub_emu_sdl_excuse="explicitly disabled" +fi +[if [ x"$grub_emu_sdl_excuse" = x ]; then + # Check for libSDL libraries.] +AC_CHECK_LIB([SDL], [SDL_Init], [LIBSDL="-lSDL"], + [grub_emu_sdl_excuse=["libSDL libraries are required to build \`grub-emu' with SDL support"]]) + AC_SUBST([LIBSDL]) +[fi] + +[if [ x"$grub_emu_sdl_excuse" = x ]; then + # Check for headers.] + AC_CHECK_HEADERS([SDL/SDL.h], [], + [grub_emu_sdl_excuse=["libSDL header file is required to build \`grub-emu' with SDL support"]]) +[fi] + +if test x"enable_grub_emu_sdl" = xyes && test x"$grub_emu_sdl_excuse" != x ; then + AC_MSG_ERROR([SDL support for grub-emu was explicitly requested but can't be compiled ($grub_emu_sdl_excuse)]) +fi +if test x"$grub_emu_sdl_excuse" = x ; then +enable_grub_emu_sdl=yes +else +enable_grub_emu_sdl=no +fi + +if test x"$enable_grub_emu_pci" != xyes ; then + grub_emu_pci_excuse="not enabled" +fi + +[if [ x"$grub_emu_pci_excuse" = x ]; then + # Check for libpci libraries.] + AC_CHECK_LIB([pciaccess], [pci_system_init], [LIBPCIACCESS="-lpciaccess"], + [grub_emu_pci_excuse=["need libpciaccess library"]]) + AC_SUBST([LIBPCIACCESS]) +[fi] +[if [ x"$grub_emu_pci_excuse" = x ]; then + # Check for headers.] + AC_CHECK_HEADERS([pciaccess.h], [], + [grub_emu_pci_excuse=["need libpciaccess headers"]]) +[fi] + +if test x"$grub_emu_pci_excuse" = x ; then +enable_grub_emu_pci=yes +else + +enable_grub_emu_pci=no +fi + +AC_SUBST([enable_grub_emu_sdl]) +AC_SUBST([enable_grub_emu_pci]) + +else + +# Ignore --enable-emu-* if platform is not emu +enable_grub_emu_sdl=no +enable_grub_emu_pci=no +fi + +AC_ARG_ENABLE([grub-mkfont], + [AS_HELP_STRING([--enable-grub-mkfont], + [build and install the `grub-mkfont' utility (default=guessed)])]) +if test x"$enable_grub_mkfont" = xno ; then + grub_mkfont_excuse="explicitly disabled" +fi + +unset ac_cv_header_ft2build_h + +if test x"$grub_mkfont_excuse" = x ; then + # Check for freetype libraries. + PKG_CHECK_MODULES([FREETYPE], [freetype2], [ + SAVED_CPPFLAGS="$CPPFLAGS" + SAVED_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $FREETYPE_CFLAGS" + LIBS="$LIBS $FREETYPE_LIBS" + AC_CHECK_HEADERS([ft2build.h], [], + [grub_mkfont_excuse=["need freetype2 headers"]]) + AC_LINK_IFELSE([AC_LANG_CALL([], [FT_Load_Glyph])], [], + [grub_mkfont_excuse=["freetype2 library unusable"]]) + CPPFLAGS="$SAVED_CPPFLAGS" + LIBS="$SAVED_LIBS" + ], [grub_mkfont_excuse=["need freetype2 library"]]) +fi + +if test x"$enable_grub_mkfont" = xyes && test x"$grub_mkfont_excuse" != x ; then + AC_MSG_ERROR([grub-mkfont was explicitly requested but can't be compiled ($grub_mkfont_excuse)]) +fi +if test x"$grub_mkfont_excuse" = x ; then +enable_grub_mkfont=yes +else +enable_grub_mkfont=no +fi +AC_SUBST([enable_grub_mkfont]) + +SAVED_CC="$CC" +SAVED_CPP="$CPP" +SAVED_CFLAGS="$CFLAGS" +SAVED_CPPFLAGS="$CPPFLAGS" +SAVED_LDFLAGS="$LDFLAGS" +CC="$BUILD_CC" +CPP="$BUILD_CPP" +CFLAGS="$BUILD_CFLAGS" +CPPFLAGS="$BUILD_CPPFLAGS" +LDFLAGS="$BUILD_LDFAGS" + +unset ac_cv_c_bigendian +unset ac_cv_header_ft2build_h + +AC_COMPUTE_INT([BUILD_SIZEOF_VOID_P], [sizeof (void *)]) +AC_COMPUTE_INT([BUILD_SIZEOF_LONG], [sizeof (long)]) +AC_C_BIGENDIAN([BUILD_WORDS_BIGENDIAN=1], [BUILD_WORDS_BIGENDIAN=0], [BUILD_WORDS_BIGENDIAN=err], [BUILD_WORDS_BIGENDIAN=err]) + +if test x$BUILD_WORDS_BIGENDIAN = xerr ; then + AC_MSG_ERROR([couldnt determine build endianness]) +fi + +AC_SUBST([BUILD_SIZEOF_LONG]) +AC_SUBST([BUILD_SIZEOF_VOID_P]) +AC_SUBST([BUILD_WORDS_BIGENDIAN]) + +if test x"$grub_build_mkfont_excuse" = x ; then + # Check for freetype libraries. + SAVED_PKG_CONFIG="$PKG_CONFIG" + test -z "$BUILD_PKG_CONFIG" || PKG_CONFIG="$BUILD_PKG_CONFIG" + PKG_CHECK_MODULES([BUILD_FREETYPE], [freetype2], [ + SAVED_CPPFLAGS_2="$CPPFLAGS" + SAVED_LIBS="$LIBS" + CPPFLAGS="$CPPFLAGS $BUILD_FREETYPE_CFLAGS" + LIBS="$LIBS $BUILD_FREETYPE_LIBS" + AC_CHECK_HEADERS([ft2build.h], [], + [grub_build_mkfont_excuse=["need freetype2 headers"]]) + AC_LINK_IFELSE([AC_LANG_CALL([], [FT_Load_Glyph])], [], + [grub_build_mkfont_excuse=["freetype2 library unusable"]]) + LIBS="$SAVED_LIBS" + CPPFLAGS="$SAVED_CPPFLAGS_2" + ], [grub_build_mkfont_excuse=["need freetype2 library"]]) + PKG_CONFIG="$SAVED_PKG_CONFIG" +fi + +if test x"$enable_build_grub_mkfont" = xyes && test x"$grub_build_mkfont_excuse" != x ; then + AC_MSG_ERROR([build-grub-mkfont was explicitly requested but can't be compiled ($grub_build_mkfont_excuse)]) +fi +if test x"$grub_build_mkfont_excuse" = x ; then + enable_build_grub_mkfont=yes +else + enable_build_grub_mkfont=no +fi +if test x"$enable_build_grub_mkfont" = xno && ( test "x$platform" = xqemu || test "x$platform" = xloongson || test "x$platform" = xqemu_mips || test "x$platform" = xcoreboot ); then + if test x"$grub_build_mkfont_excuse" = x ; then + AC_MSG_ERROR([qemu, coreboot and loongson ports need build-time grub-mkfont]) + else + AC_MSG_ERROR([qemu, coreboot and loongson ports need build-time grub-mkfont ($grub_build_mkfont_excuse)]) + fi +fi + +CC="$SAVED_CC" +CPP="$SAVED_CPP" +CFLAGS="$SAVED_CFLAGS" +CPPFLAGS="$SAVED_CPPFLAGS" +LDFLAGS="$SAVED_LDFLAGS" + + +DJVU_FONT_SOURCE= + +starfield_excuse= + +AC_ARG_ENABLE([grub-themes], + [AS_HELP_STRING([--enable-grub-themes], + [build and install GRUB themes (default=guessed)])]) +if test x"$enable_grub_themes" = xno ; then + starfield_excuse="explicitly disabled" +fi + +if test x"$starfield_excuse" = x && test x"$enable_build_grub_mkfont" = xno ; then + starfield_excuse="No build-time grub-mkfont" +fi + +if test x"$starfield_excuse" = x; then + for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do + for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype; do + if test -f "$dir/DejaVuSans.$ext"; then + DJVU_FONT_SOURCE="$dir/DejaVuSans.$ext" + break 2 + fi + done + done + + if test "x$DJVU_FONT_SOURCE" = x; then + starfield_excuse="No DejaVu found" + fi +fi + +if test x"$enable_grub_themes" = xyes && test x"$starfield_excuse" != x; then + AC_MSG_ERROR([themes were explicitly requested but requirements are not satisfied ($starfield_excuse)]) +fi + +AC_SUBST([DJVU_FONT_SOURCE]) + +FONT_SOURCE= + +for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do + for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/unifont /usr/share/fonts/uni /usr/share/fonts/truetype/unifont /usr/share/fonts/misc; do + if test -f "$dir/unifont.$ext"; then + md5="$(md5sum "$dir/unifont.$ext"|awk '{ print $1; }')" + # PCF and BDF from version 6.3 isn't hanled properly by libfreetype. + if test "$md5" = 0a54834d2788c83886a3e1785a6a1e61 || test "$md5" = 28f2565c7a41d8d407e2551159385edb || test "$md5" = dae5e588461b3b92b87b6ffee734f936 || test "$md5" = 4a3d687aa5bb329ed05f4263a1016791 ; then + continue + fi + FONT_SOURCE="$dir/unifont.$ext" + break 2 + fi + done +done + +if test x"$enable_build_grub_mkfont" = xno ; then + FONT_SOURCE= +fi + +if test "x$FONT_SOURCE" = x && ( test "x$platform" = xqemu || test "x$platform" = xloongson || test "x$platform" = xqemu_mips || test "x$platform" = xcoreboot ); then + if test x"$grub_build_mkfont_excuse" = x ; then + AC_MSG_ERROR([qemu, coreboot and loongson ports need unifont]) + else + AC_MSG_ERROR([qemu, coreboot and loongson ports need unifont ($grub_build_mkfont_excuse)]) + fi +fi + +AC_SUBST([FONT_SOURCE]) + +if test x"$FONT_SOURCE" = x && test x"$DJVU_FONT_SOURCE" = x && test x"$grub_build_mkfont_excuse" = x; then + grub_build_mkfont_excuse="no fonts" +fi + + +AC_ARG_ENABLE([grub-mount], + [AS_HELP_STRING([--enable-grub-mount], + [build and install the `grub-mount' utility (default=guessed)])]) +if test x"$enable_grub_mount" = xno ; then + grub_mount_excuse="explicitly disabled" +fi + +if test x"$grub_mount_excuse" = x ; then + AC_CHECK_LIB([fuse], [fuse_main_real], [], + [grub_mount_excuse="need FUSE library"]) +fi + +if test x"$grub_mount_excuse" = x ; then + # Check for fuse headers. + SAVED_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -DFUSE_USE_VERSION=26" + AC_CHECK_HEADERS([fuse/fuse.h], [], + [grub_mount_excuse=["need FUSE headers"]]) + CPPFLAGS="$SAVED_CPPFLAGS" +fi + +if test x"$enable_grub_mount" = xyes && test x"$grub_mount_excuse" != x ; then + AC_MSG_ERROR([grub-mount was explicitly requested but can't be compiled ($grub_mount_excuse)]) +fi +if test x"$grub_mount_excuse" = x ; then +enable_grub_mount=yes +else +enable_grub_mount=no +fi +AC_SUBST([enable_grub_mount]) + +AC_ARG_ENABLE([device-mapper], + [AS_HELP_STRING([--enable-device-mapper], + [enable Linux device-mapper support (default=guessed)])]) +if test x"$enable_device_mapper" = xno ; then + device_mapper_excuse="explicitly disabled" +fi + +if test x"$device_mapper_excuse" = x ; then + # Check for device-mapper header. + AC_CHECK_HEADER([libdevmapper.h], [], + [device_mapper_excuse="need libdevmapper header"]) +fi + +if test x"$device_mapper_excuse" = x ; then + # Check for device-mapper library. + AC_CHECK_LIB([devmapper], [dm_task_create], [], + [device_mapper_excuse="need devmapper library"]) +fi + +if test x"$device_mapper_excuse" = x ; then + # Check for device-mapper library. + AC_CHECK_LIB([devmapper], [dm_log_with_errno_init], + [], + [device_mapper_excuse="need devmapper library"]) +fi + +if test x"$device_mapper_excuse" = x ; then + LIBDEVMAPPER="-ldevmapper" + AC_DEFINE([HAVE_DEVICE_MAPPER], [1], + [Define to 1 if you have the devmapper library.]) +fi + +AC_SUBST([LIBDEVMAPPER]) + +LIBGEOM= +if test x$host_kernel = xkfreebsd; then + AC_CHECK_LIB([geom], [geom_gettree], [], + [AC_MSG_ERROR([Your platform requires libgeom])]) + LIBGEOM="-lgeom" +fi + +AC_SUBST([LIBGEOM]) + +AC_ARG_ENABLE([liblzma], + [AS_HELP_STRING([--enable-liblzma], + [enable liblzma integration (default=guessed)])]) +if test x"$enable_liblzma" = xno ; then + liblzma_excuse="explicitly disabled" +fi + +if test x"$liblzma_excuse" = x ; then +AC_CHECK_LIB([lzma], [lzma_code], + [],[liblzma_excuse="need lzma library"]) +fi +if test x"$liblzma_excuse" = x ; then +AC_CHECK_HEADER([lzma.h], [], [liblzma_excuse="need lzma header"]) +fi + +if test x"$enable_liblzma" = xyes && test x"$liblzma_excuse" != x ; then + AC_MSG_ERROR([liblzma support was explicitly requested but requirements are not satisfied ($liblzma_excuse)]) +fi + + +if test x"$liblzma_excuse" = x ; then + LIBLZMA="-llzma" + AC_DEFINE([USE_LIBLZMA], [1], + [Define to 1 if you have the LZMA library.]) +fi + +AC_SUBST([LIBLZMA]) + +AC_ARG_ENABLE([libzfs], + [AS_HELP_STRING([--enable-libzfs], + [enable libzfs integration (default=guessed)])]) +if test x"$enable_libzfs" = xno ; then + libzfs_excuse="explicitly disabled" +fi + +if test x"$libzfs_excuse" = x ; then + # Only check for system headers if libzfs support has not been disabled. + AC_CHECK_HEADERS(libzfs.h libnvpair.h) +fi + +if test x"$libzfs_excuse" = x ; then + AC_CHECK_LIB([zfs], [libzfs_init], + [], + [libzfs_excuse="need zfs library"]) +fi + +if test x"$libzfs_excuse" = x ; then + AC_CHECK_LIB([nvpair], [nvlist_lookup_string], + [], + [libzfs_excuse="need nvpair library"]) +fi + +if test x"$enable_libzfs" = xyes && test x"$libzfs_excuse" != x ; then + AC_MSG_ERROR([libzfs support was explicitly requested but requirements are not satisfied ($libzfs_excuse)]) +fi + +if test x"$libzfs_excuse" = x ; then + # We need both libzfs and libnvpair for a successful build. + LIBZFS="-lzfs" + AC_DEFINE([HAVE_LIBZFS], [1], + [Define to 1 if you have the ZFS library.]) + LIBNVPAIR="-lnvpair" + AC_DEFINE([HAVE_LIBNVPAIR], [1], + [Define to 1 if you have the NVPAIR library.]) +fi + +AC_SUBST([LIBZFS]) +AC_SUBST([LIBNVPAIR]) + +LIBS="" + +AC_SUBST([FONT_SOURCE]) +AS_IF([test x$target_cpu = xi386 -a x$platform = xqemu], + [AC_SUBST([GRUB_BOOT_MACHINE_LINK_ADDR], 0xffe00)]) + +AC_SUBST(HAVE_ASM_USCORE) +AC_SUBST(BSS_START_SYMBOL) +AC_SUBST(END_SYMBOL) +AC_SUBST(PACKAGE) +AC_SUBST(VERSION) + +AC_ARG_ENABLE([werror], + [AS_HELP_STRING([--disable-werror], + [do not use -Werror when building GRUB])]) +if test x"$enable_werror" != xno ; then + TARGET_CFLAGS="$TARGET_CFLAGS -Werror" + HOST_CFLAGS="$HOST_CFLAGS -Werror" +fi + +TARGET_CPP="$TARGET_CC -E" +TARGET_CCAS=$TARGET_CC + +# Includes which include make-time substitutions. They must come last +# as to avoid executing top_builddir in shell. +HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include" +TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include" +TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_builddir)/include" + +GRUB_TARGET_CPU="${target_cpu}" +GRUB_PLATFORM="${platform}" + +AC_SUBST(GRUB_TARGET_CPU) +AC_SUBST(GRUB_PLATFORM) + +AC_SUBST(TARGET_OBJCONV) +AC_SUBST(TARGET_CPP) +AC_SUBST(TARGET_CCAS) +AC_SUBST(TARGET_OBJ2ELF) +AC_SUBST(TARGET_MODULE_FORMAT) +AC_SUBST(TARGET_CC_VERSION) + +AC_SUBST(TARGET_CFLAGS) +AC_SUBST(TARGET_LDFLAGS) +AC_SUBST(TARGET_CPPFLAGS) +AC_SUBST(TARGET_CCASFLAGS) + +AC_SUBST(TARGET_IMG_LDFLAGS) +AC_SUBST(TARGET_IMG_CFLAGS) +AC_SUBST(TARGET_IMG_BASE_LDOPT) +AC_SUBST(TARGET_APPLE_LINKER) + +AC_SUBST(HOST_CFLAGS) +AC_SUBST(HOST_LDFLAGS) +AC_SUBST(HOST_CPPFLAGS) +AC_SUBST(HOST_CCASFLAGS) + +AC_SUBST(BUILD_LIBM) + +# +# Automake conditionals +# + +AM_CONDITIONAL([COND_real_platform], [test x$platform != xnone]) +AM_CONDITIONAL([COND_emu], [test x$platform = xemu]) +AM_CONDITIONAL([COND_i386_pc], [test x$target_cpu = xi386 -a x$platform = xpc]) +AM_CONDITIONAL([COND_i386_efi], [test x$target_cpu = xi386 -a x$platform = xefi]) +AM_CONDITIONAL([COND_ia64_efi], [test x$target_cpu = xia64 -a x$platform = xefi]) +AM_CONDITIONAL([COND_i386_qemu], [test x$target_cpu = xi386 -a x$platform = xqemu]) +AM_CONDITIONAL([COND_i386_ieee1275], [test x$target_cpu = xi386 -a x$platform = xieee1275]) +AM_CONDITIONAL([COND_i386_coreboot], [test x$target_cpu = xi386 -a x$platform = xcoreboot]) +AM_CONDITIONAL([COND_i386_multiboot], [test x$target_cpu = xi386 -a x$platform = xmultiboot]) +AM_CONDITIONAL([COND_x86_64_efi], [test x$target_cpu = xx86_64 -a x$platform = xefi]) +AM_CONDITIONAL([COND_i386_xen], [test x$target_cpu = xi386 -a x$platform = xxen]) +AM_CONDITIONAL([COND_i386_xen_pvh], [test x$target_cpu = xi386 -a x$platform = xxen_pvh]) +AM_CONDITIONAL([COND_x86_64_xen], [test x$target_cpu = xx86_64 -a x$platform = xxen]) +AM_CONDITIONAL([COND_mips64_efi], [test x$target_cpu = xmips64el -a x$platform = xefi]) +AM_CONDITIONAL([COND_mips_loongson], [test x$target_cpu = xmipsel -a x$platform = xloongson]) +AM_CONDITIONAL([COND_mips_qemu_mips], [test "(" x$target_cpu = xmips -o x$target_cpu = xmipsel ")" -a x$platform = xqemu_mips]) +AM_CONDITIONAL([COND_mips_arc], [test "(" x$target_cpu = xmips -o x$target_cpu = xmipsel ")" -a x$platform = xarc]) +AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platform = xieee1275]) +AM_CONDITIONAL([COND_sparc64_emu], [test x$target_cpu = xsparc64 -a x$platform = xemu]) +AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platform = xieee1275]) +AM_CONDITIONAL([COND_mips64el], [test x$target_cpu = xmips64el]) +AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips -o x$target_cpu = xmipsel]) +AM_CONDITIONAL([COND_mipsel], [test x$target_cpu = xmipsel]) +AM_CONDITIONAL([COND_mipseb], [test x$target_cpu = xmips]) +AM_CONDITIONAL([COND_arm], [test x$target_cpu = xarm ]) +AM_CONDITIONAL([COND_arm_uboot], [test x$target_cpu = xarm -a x$platform = xuboot]) +AM_CONDITIONAL([COND_arm_coreboot], [test x$target_cpu = xarm -a x$platform = xcoreboot]) +AM_CONDITIONAL([COND_arm_efi], [test x$target_cpu = xarm -a x$platform = xefi]) +AM_CONDITIONAL([COND_arm64], [test x$target_cpu = xarm64 ]) +AM_CONDITIONAL([COND_arm64_efi], [test x$target_cpu = xarm64 -a x$platform = xefi]) +AM_CONDITIONAL([COND_riscv32], [test x$target_cpu = xriscv32 ]) +AM_CONDITIONAL([COND_riscv64], [test x$target_cpu = xriscv64 ]) +AM_CONDITIONAL([COND_riscv32_efi], [test x$target_cpu = xriscv32 -a x$platform = xefi]) +AM_CONDITIONAL([COND_riscv64_efi], [test x$target_cpu = xriscv64 -a x$platform = xefi]) + +AM_CONDITIONAL([COND_HOST_HURD], [test x$host_kernel = xhurd]) +AM_CONDITIONAL([COND_HOST_LINUX], [test x$host_kernel = xlinux]) +AM_CONDITIONAL([COND_HOST_NETBSD], [test x$host_kernel = xnetbsd]) +AM_CONDITIONAL([COND_HOST_WINDOWS], [test x$host_kernel = xwindows]) +AM_CONDITIONAL([COND_HOST_KFREEBSD], [test x$host_kernel = xkfreebsd]) +AM_CONDITIONAL([COND_HOST_XNU], [test x$host_kernel = xxnu]) +AM_CONDITIONAL([COND_HOST_ILLUMOS], [test x$host_kernel = xillumos]) + +AM_CONDITIONAL([COND_MAN_PAGES], [test x$cross_compiling = xno -a x$HELP2MAN != x]) +AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test x$enable_grub_emu_sdl = xyes]) +AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes]) +AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes]) +AM_CONDITIONAL([COND_GRUB_MOUNT], [test x$enable_grub_mount = xyes]) +AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x]) +if test x$FONT_SOURCE != x ; then + HAVE_FONT_SOURCE=1 +else + HAVE_FONT_SOURCE=0 +fi +AC_SUBST(HAVE_FONT_SOURCE) +AM_CONDITIONAL([COND_APPLE_LINKER], [test x$TARGET_APPLE_LINKER = x1]) +AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes]) +AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1]) +AM_CONDITIONAL([COND_ENABLE_BOOT_TIME_STATS], [test x$BOOT_TIME_STATS = x1]) + +AM_CONDITIONAL([COND_HAVE_CXX], [test x$HAVE_CXX = xyes]) + +AM_CONDITIONAL([COND_HAVE_ASM_USCORE], [test x$HAVE_ASM_USCORE = x1]) +AM_CONDITIONAL([COND_STARFIELD], [test "x$starfield_excuse" = x]) +AM_CONDITIONAL([COND_HAVE_EXEC], [test "x$have_exec" = xy]) + +test "x$prefix" = xNONE && prefix="$ac_default_prefix" +test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" +datarootdir="$(eval echo "$datarootdir")" +grub_libdir="$(eval echo "$libdir")" +grub_localedir="$(eval echo "$localedir")" +grub_datadir="$(eval echo "$datadir")" +grub_sysconfdir="$(eval echo "$sysconfdir")" +AC_DEFINE_UNQUOTED(LOCALEDIR, "$grub_localedir", [Locale dir]) +AC_DEFINE_UNQUOTED(GRUB_LIBDIR, "$grub_libdir", [Library dir]) +AC_DEFINE_UNQUOTED(GRUB_DATADIR, "$grub_datadir", [Data dir]) +AC_DEFINE_UNQUOTED(GRUB_SYSCONFDIR, "$grub_sysconfdir", [Configuration dir]) + + +# Output files. +if test "$platform" != none; then + cpudir="${target_cpu}" + if test x${cpudir} = xmips64el; then + cpudir=mips64; + elif test x${cpudir} = xmipsel; then + cpudir=mips; + fi + grub_CHECK_LINK_DIR + if test x"$link_dir" = xyes ; then + AC_CONFIG_LINKS([include/grub/cpu:include/grub/$cpudir]) + if test "$platform" != emu ; then + AC_CONFIG_LINKS([include/grub/machine:include/grub/$cpudir/$platform]) + fi + else + mkdir -p include/grub 2>/dev/null + rm -rf include/grub/cpu + cp -rp $srcdir/include/grub/$cpudir include/grub/cpu 2>/dev/null + if test "$platform" != emu ; then + rm -rf include/grub/machine + cp -rp $srcdir/include/grub/$cpudir/$platform include/grub/machine 2>/dev/null + fi + fi +else + # Just enough to stop the compiler failing with -I$(srcdir)/include. + mkdir -p include 2>/dev/null + rm -rf include/grub/cpu include/grub/machine +fi + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([grub-core/Makefile]) +AC_CONFIG_FILES([grub-core/lib/gnulib/Makefile]) +AC_CONFIG_FILES([po/Makefile.in]) +AC_CONFIG_FILES([docs/Makefile]) +AC_CONFIG_FILES([util/bash-completion.d/Makefile]) +AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h]) +AC_CONFIG_FILES([config.h]) + +AC_OUTPUT +[ +echo "*******************************************************" +echo GRUB2 will be compiled with following components: +echo Platform: "$target_cpu"-"$platform" +if [ x"$platform" = xemu ]; then +if [ x"$grub_emu_sdl_excuse" = x ]; then +echo SDL support for grub-emu: Yes +else +echo SDL support for grub-emu: No "($grub_emu_sdl_excuse)" +fi +if [ x"$grub_emu_pci_excuse" = x ]; then +echo PCI support for grub-emu: Yes +else +echo PCI support for grub-emu: No "($grub_emu_pci_excuse)" +fi +fi +if test x"$device_mapper_excuse" = x ; then +echo With devmapper support: Yes +else +echo With devmapper support: No "($device_mapper_excuse)" +fi +if [ x"$enable_mm_debug" = xyes ]; then +echo With memory debugging: Yes +else +echo With memory debugging: No +fi +if [ x"$enable_cache_stats" = xyes ]; then +echo With disk cache statistics: Yes +else +echo With disk cache statistics: No +fi + +if [ x"$enable_boot_time" = xyes ]; then +echo With boot time statistics: Yes +else +echo With boot time statistics: No +fi + +if [ x"$efiemu_excuse" = x ]; then +echo efiemu runtime: Yes +else +echo efiemu runtime: No "($efiemu_excuse)" +fi +if [ x"$grub_mkfont_excuse" = x ]; then +echo grub-mkfont: Yes +else +echo grub-mkfont: No "($grub_mkfont_excuse)" +fi +if [ x"$grub_mount_excuse" = x ]; then +echo grub-mount: Yes +else +echo grub-mount: No "($grub_mount_excuse)" +fi +if [ x"$starfield_excuse" = x ]; then +echo starfield theme: Yes +echo With DejaVuSans font from $DJVU_FONT_SOURCE +else +echo starfield theme: No "($starfield_excuse)" +fi +if [ x"$libzfs_excuse" = x ]; then +echo With libzfs support: Yes +else +echo With libzfs support: No "($libzfs_excuse)" +fi +if [ x"$grub_build_mkfont_excuse" = x ]; then + echo Build-time grub-mkfont: Yes + if test "x$FONT_SOURCE" = x ; then + echo "Without unifont" + else + echo "With unifont from $FONT_SOURCE" + fi +else + echo Build-time grub-mkfont: No "($grub_build_mkfont_excuse)" + echo "Without unifont (no build-time grub-mkfont)" +fi +if test x"$liblzma_excuse" != x ; then +echo "Without liblzma (no support for XZ-compressed mips images) ($liblzma_excuse)" +else +echo "With liblzma from $LIBLZMA (support for XZ-compressed mips images)" +fi +echo "*******************************************************" +] diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/gentpl.py b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/gentpl.py new file mode 100644 index 0000000..d8d936d --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/gentpl.py @@ -0,0 +1,909 @@ +#! /usr/bin/python +# GRUB -- GRand Unified Bootloader +# Copyright (C) 2010,2011,2012,2013 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +from __future__ import print_function + +__metaclass__ = type + +from optparse import OptionParser +import re + +# +# This is the python script used to generate Makefile.*.am +# + +GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", + "i386_multiboot", "i386_ieee1275", "x86_64_efi", + "i386_xen", "x86_64_xen", "i386_xen_pvh", + "mips_loongson", "mips64_efi", "sparc64_ieee1275", + "powerpc_ieee1275", "mips_arc", "ia64_efi", + "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi", + "arm_coreboot", "riscv32_efi", "riscv64_efi" ] + +GROUPS = {} + +GROUPS["common"] = GRUB_PLATFORMS[:] + +# Groups based on CPU +GROUPS["i386"] = [ "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", "i386_multiboot", "i386_ieee1275" ] +GROUPS["x86_64"] = [ "x86_64_efi" ] +GROUPS["x86"] = GROUPS["i386"] + GROUPS["x86_64"] +GROUPS["mips"] = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ] +GROUPS["mips64"] = [ "mips64_efi" ] +GROUPS["sparc64"] = [ "sparc64_ieee1275" ] +GROUPS["powerpc"] = [ "powerpc_ieee1275" ] +GROUPS["arm"] = [ "arm_uboot", "arm_efi", "arm_coreboot" ] +GROUPS["arm64"] = [ "arm64_efi" ] +GROUPS["riscv32"] = [ "riscv32_efi" ] +GROUPS["riscv64"] = [ "riscv64_efi" ] + +# Groups based on firmware +GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi", "mips64_efi", + "riscv32_efi", "riscv64_efi" ] +GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] +GROUPS["uboot"] = [ "arm_uboot" ] +GROUPS["xen"] = [ "i386_xen", "x86_64_xen" ] +GROUPS["coreboot"] = [ "i386_coreboot", "arm_coreboot" ] + +# emu is a special case so many core functionality isn't needed on this platform +GROUPS["noemu"] = GRUB_PLATFORMS[:]; GROUPS["noemu"].remove("emu") + +# Groups based on hardware features +GROUPS["cmos"] = GROUPS["x86"][:] + ["mips_loongson", "mips_qemu_mips", + "sparc64_ieee1275", "powerpc_ieee1275"] +GROUPS["cmos"].remove("i386_efi"); GROUPS["cmos"].remove("x86_64_efi"); +GROUPS["pci"] = GROUPS["x86"] + ["mips_loongson"] +GROUPS["usb"] = GROUPS["pci"] + ["arm_coreboot"] + +# If gfxterm is main output console integrate it into kernel +GROUPS["videoinkernel"] = ["mips_loongson", "i386_coreboot", "arm_coreboot" ] +GROUPS["videomodules"] = GRUB_PLATFORMS[:]; +for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i) + +# Similar for terminfo +GROUPS["terminfoinkernel"] = [ "emu", "mips_loongson", "mips_arc", "mips_qemu_mips", "i386_xen_pvh" ] + GROUPS["xen"] + GROUPS["ieee1275"] + GROUPS["uboot"]; +GROUPS["terminfomodule"] = GRUB_PLATFORMS[:]; +for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i) + +# Flattened Device Trees (FDT) +GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi", "riscv32_efi", "riscv64_efi" ] + +# Needs software helpers for division +# Must match GRUB_DIVISION_IN_SOFTWARE in misc.h +GROUPS["softdiv"] = GROUPS["arm"] + ["ia64_efi"] + GROUPS["riscv32"] +GROUPS["no_softdiv"] = GRUB_PLATFORMS[:] +for i in GROUPS["softdiv"]: GROUPS["no_softdiv"].remove(i) + +# Miscellaneous groups scheduled to disappear in future +GROUPS["i386_coreboot_multiboot_qemu"] = ["i386_coreboot", "i386_multiboot", "i386_qemu"] +GROUPS["nopc"] = GRUB_PLATFORMS[:]; GROUPS["nopc"].remove("i386_pc") + +# +# Create platform => groups reverse map, where groups covering that +# platform are ordered by their sizes +# +RMAP = {} +for platform in GRUB_PLATFORMS: + # initialize with platform itself as a group + RMAP[platform] = [ platform ] + + for k in GROUPS.keys(): + v = GROUPS[k] + # skip groups that don't cover this platform + if platform not in v: continue + + bigger = [] + smaller = [] + # partition currently known groups based on their size + for group in RMAP[platform]: + if group in GRUB_PLATFORMS: smaller.append(group) + elif len(GROUPS[group]) < len(v): smaller.append(group) + else: bigger.append(group) + # insert in the middle + RMAP[platform] = smaller + [ k ] + bigger + +# +# Input +# + +# We support a subset of the AutoGen definitions file syntax. Specifically, +# compound names are disallowed; some preprocessing directives are +# disallowed (though #if/#endif are allowed; note that, like AutoGen, #if +# skips everything to the next #endif regardless of the value of the +# conditional); and shell-generated strings, Scheme-generated strings, and +# here strings are disallowed. + +class AutogenToken: + (autogen, definitions, eof, var_name, other_name, string, number, + semicolon, equals, comma, lbrace, rbrace, lbracket, rbracket) = range(14) + +class AutogenState: + (init, need_def, need_tpl, need_semi, need_name, have_name, need_value, + need_idx, need_rbracket, indx_name, have_value, done) = range(12) + +class AutogenParseError(Exception): + def __init__(self, message, path, line): + super(AutogenParseError, self).__init__(message) + self.path = path + self.line = line + + def __str__(self): + return ( + super(AutogenParseError, self).__str__() + + " at file %s line %d" % (self.path, self.line)) + +class AutogenDefinition(list): + def __getitem__(self, key): + try: + return super(AutogenDefinition, self).__getitem__(key) + except TypeError: + for name, value in self: + if name == key: + return value + + def __contains__(self, key): + for name, value in self: + if name == key: + return True + return False + + def get(self, key, default): + for name, value in self: + if name == key: + return value + else: + return default + + def find_all(self, key): + for name, value in self: + if name == key: + yield value + +class AutogenParser: + def __init__(self): + self.definitions = AutogenDefinition() + self.def_stack = [("", self.definitions)] + self.curdef = None + self.new_name = None + self.cur_path = None + self.cur_line = 0 + + @staticmethod + def is_unquotable_char(c): + return (ord(c) in range(ord("!"), ord("~") + 1) and + c not in "#,;<=>[\\]`{}?*'\"()") + + @staticmethod + def is_value_name_char(c): + return c in ":^-_" or c.isalnum() + + def error(self, message): + raise AutogenParseError(message, self.cur_file, self.cur_line) + + def read_tokens(self, f): + data = f.read() + end = len(data) + offset = 0 + while offset < end: + while offset < end and data[offset].isspace(): + if data[offset] == "\n": + self.cur_line += 1 + offset += 1 + if offset >= end: + break + c = data[offset] + if c == "#": + offset += 1 + try: + end_directive = data.index("\n", offset) + directive = data[offset:end_directive] + offset = end_directive + except ValueError: + directive = data[offset:] + offset = end + name, value = directive.split(None, 1) + if name == "if": + try: + end_if = data.index("\n#endif", offset) + new_offset = end_if + len("\n#endif") + self.cur_line += data[offset:new_offset].count("\n") + offset = new_offset + except ValueError: + self.error("#if without matching #endif") + else: + self.error("Unhandled directive '#%s'" % name) + elif c == "{": + yield AutogenToken.lbrace, c + offset += 1 + elif c == "=": + yield AutogenToken.equals, c + offset += 1 + elif c == "}": + yield AutogenToken.rbrace, c + offset += 1 + elif c == "[": + yield AutogenToken.lbracket, c + offset += 1 + elif c == "]": + yield AutogenToken.rbracket, c + offset += 1 + elif c == ";": + yield AutogenToken.semicolon, c + offset += 1 + elif c == ",": + yield AutogenToken.comma, c + offset += 1 + elif c in ("'", '"'): + s = [] + while True: + offset += 1 + if offset >= end: + self.error("EOF in quoted string") + if data[offset] == "\n": + self.cur_line += 1 + if data[offset] == "\\": + offset += 1 + if offset >= end: + self.error("EOF in quoted string") + if data[offset] == "\n": + self.cur_line += 1 + # Proper escaping unimplemented; this can be filled + # out if needed. + s.append("\\") + s.append(data[offset]) + elif data[offset] == c: + offset += 1 + break + else: + s.append(data[offset]) + yield AutogenToken.string, "".join(s) + elif c == "/": + offset += 1 + if data[offset] == "*": + offset += 1 + try: + end_comment = data.index("*/", offset) + new_offset = end_comment + len("*/") + self.cur_line += data[offset:new_offset].count("\n") + offset = new_offset + except ValueError: + self.error("/* without matching */") + elif data[offset] == "/": + try: + offset = data.index("\n", offset) + except ValueError: + pass + elif (c.isdigit() or + (c == "-" and offset < end - 1 and + data[offset + 1].isdigit())): + end_number = offset + 1 + while end_number < end and data[end_number].isdigit(): + end_number += 1 + yield AutogenToken.number, data[offset:end_number] + offset = end_number + elif self.is_unquotable_char(c): + end_name = offset + while (end_name < end and + self.is_value_name_char(data[end_name])): + end_name += 1 + if end_name < end and self.is_unquotable_char(data[end_name]): + while (end_name < end and + self.is_unquotable_char(data[end_name])): + end_name += 1 + yield AutogenToken.other_name, data[offset:end_name] + offset = end_name + else: + s = data[offset:end_name] + if s.lower() == "autogen": + yield AutogenToken.autogen, s + elif s.lower() == "definitions": + yield AutogenToken.definitions, s + else: + yield AutogenToken.var_name, s + offset = end_name + else: + self.error("Invalid input character '%s'" % c) + yield AutogenToken.eof, None + + def do_need_name_end(self, token): + if len(self.def_stack) > 1: + self.error("Definition blocks were left open") + + def do_need_name_var_name(self, token): + self.new_name = token + + def do_end_block(self, token): + if len(self.def_stack) <= 1: + self.error("Too many close braces") + new_name, parent_def = self.def_stack.pop() + parent_def.append((new_name, self.curdef)) + self.curdef = parent_def + + def do_empty_val(self, token): + self.curdef.append((self.new_name, "")) + + def do_str_value(self, token): + self.curdef.append((self.new_name, token)) + + def do_start_block(self, token): + self.def_stack.append((self.new_name, self.curdef)) + self.curdef = AutogenDefinition() + + def do_indexed_name(self, token): + self.new_name = token + + def read_definitions_file(self, f): + self.curdef = self.definitions + self.cur_line = 0 + state = AutogenState.init + + # The following transition table was reduced from the Autogen + # documentation: + # info -f autogen -n 'Full Syntax' + transitions = { + AutogenState.init: { + AutogenToken.autogen: (AutogenState.need_def, None), + }, + AutogenState.need_def: { + AutogenToken.definitions: (AutogenState.need_tpl, None), + }, + AutogenState.need_tpl: { + AutogenToken.var_name: (AutogenState.need_semi, None), + AutogenToken.other_name: (AutogenState.need_semi, None), + AutogenToken.string: (AutogenState.need_semi, None), + }, + AutogenState.need_semi: { + AutogenToken.semicolon: (AutogenState.need_name, None), + }, + AutogenState.need_name: { + AutogenToken.autogen: (AutogenState.need_def, None), + AutogenToken.eof: (AutogenState.done, self.do_need_name_end), + AutogenToken.var_name: ( + AutogenState.have_name, self.do_need_name_var_name), + AutogenToken.rbrace: ( + AutogenState.have_value, self.do_end_block), + }, + AutogenState.have_name: { + AutogenToken.semicolon: ( + AutogenState.need_name, self.do_empty_val), + AutogenToken.equals: (AutogenState.need_value, None), + AutogenToken.lbracket: (AutogenState.need_idx, None), + }, + AutogenState.need_value: { + AutogenToken.var_name: ( + AutogenState.have_value, self.do_str_value), + AutogenToken.other_name: ( + AutogenState.have_value, self.do_str_value), + AutogenToken.string: ( + AutogenState.have_value, self.do_str_value), + AutogenToken.number: ( + AutogenState.have_value, self.do_str_value), + AutogenToken.lbrace: ( + AutogenState.need_name, self.do_start_block), + }, + AutogenState.need_idx: { + AutogenToken.var_name: ( + AutogenState.need_rbracket, self.do_indexed_name), + AutogenToken.number: ( + AutogenState.need_rbracket, self.do_indexed_name), + }, + AutogenState.need_rbracket: { + AutogenToken.rbracket: (AutogenState.indx_name, None), + }, + AutogenState.indx_name: { + AutogenToken.semicolon: ( + AutogenState.need_name, self.do_empty_val), + AutogenToken.equals: (AutogenState.need_value, None), + }, + AutogenState.have_value: { + AutogenToken.semicolon: (AutogenState.need_name, None), + AutogenToken.comma: (AutogenState.need_value, None), + }, + } + + for code, token in self.read_tokens(f): + if code in transitions[state]: + state, handler = transitions[state][code] + if handler is not None: + handler(token) + else: + self.error( + "Parse error in state %s: unexpected token '%s'" % ( + state, token)) + if state == AutogenState.done: + break + + def read_definitions(self, path): + self.cur_file = path + with open(path) as f: + self.read_definitions_file(f) + +defparser = AutogenParser() + +# +# Output +# + +outputs = {} + +def output(s, section=''): + if s == "": + return + outputs.setdefault(section, []) + outputs[section].append(s) + +def write_output(section=''): + for s in outputs.get(section, []): + print(s, end='') + +# +# Global variables +# + +def gvar_add(var, value): + output(var + " += " + value + "\n") + +# +# Per PROGRAM/SCRIPT variables +# + +seen_vars = set() + +def vars_init(defn, *var_list): + name = defn['name'] + + if name not in seen_target and name not in seen_vars: + for var in var_list: + output(var + " = \n", section='decl') + seen_vars.add(name) + +def var_set(var, value): + output(var + " = " + value + "\n") + +def var_add(var, value): + output(var + " += " + value + "\n") + +# +# Variable names and rules +# + +canonical_name_re = re.compile(r'[^0-9A-Za-z@_]') +canonical_name_suffix = "" + +def set_canonical_name_suffix(suffix): + global canonical_name_suffix + canonical_name_suffix = suffix + +def cname(defn): + return canonical_name_re.sub('_', defn['name'] + canonical_name_suffix) + +def rule(target, source, cmd): + if cmd[0] == "\n": + output("\n" + target + ": " + source + cmd.replace("\n", "\n\t") + "\n") + else: + output("\n" + target + ": " + source + "\n\t" + cmd.replace("\n", "\n\t") + "\n") + +# +# Handle keys with platform names as values, for example: +# +# kernel = { +# nostrip = emu; +# ... +# } +# +def platform_tagged(defn, platform, tag): + for value in defn.find_all(tag): + for group in RMAP[platform]: + if value == group: + return True + return False + +def if_platform_tagged(defn, platform, tag, snippet_if, snippet_else=None): + if platform_tagged(defn, platform, tag): + return snippet_if + elif snippet_else is not None: + return snippet_else + +# +# Handle tagged values +# +# module = { +# extra_dist = ... +# extra_dist = ... +# ... +# }; +# +def foreach_value(defn, tag, closure): + r = [] + for value in defn.find_all(tag): + r.append(closure(value)) + return ''.join(r) + +# +# Handle best matched values for a platform, for example: +# +# module = { +# cflags = '-Wall'; +# emu_cflags = '-Wall -DGRUB_EMU=1'; +# ... +# } +# +def foreach_platform_specific_value(defn, platform, suffix, nonetag, closure): + r = [] + for group in RMAP[platform]: + values = list(defn.find_all(group + suffix)) + if values: + for value in values: + r.append(closure(value)) + break + else: + for value in defn.find_all(nonetag): + r.append(closure(value)) + return ''.join(r) + +# +# Handle values from sum of all groups for a platform, for example: +# +# module = { +# common = kern/misc.c; +# emu = kern/emu/misc.c; +# ... +# } +# +def foreach_platform_value(defn, platform, suffix, closure): + r = [] + for group in RMAP[platform]: + for value in defn.find_all(group + suffix): + r.append(closure(value)) + return ''.join(r) + +def platform_conditional(platform, closure): + output("\nif COND_" + platform + "\n") + closure(platform) + output("endif\n") + +# +# Handle guarding with platform-specific "enable" keys, for example: +# +# module = { +# name = pci; +# noemu = bus/pci.c; +# emu = bus/emu/pci.c; +# emu = commands/lspci.c; +# +# enable = emu; +# enable = i386_pc; +# enable = x86_efi; +# enable = i386_ieee1275; +# enable = i386_coreboot; +# }; +# +def foreach_enabled_platform(defn, closure): + if 'enable' in defn: + for platform in GRUB_PLATFORMS: + if platform_tagged(defn, platform, "enable"): + platform_conditional(platform, closure) + else: + for platform in GRUB_PLATFORMS: + platform_conditional(platform, closure) + +# +# Handle guarding with platform-specific automake conditionals, for example: +# +# module = { +# name = usb; +# common = bus/usb/usb.c; +# noemu = bus/usb/usbtrans.c; +# noemu = bus/usb/usbhub.c; +# enable = emu; +# enable = i386; +# enable = mips_loongson; +# emu_condition = COND_GRUB_EMU_SDL; +# }; +# +def under_platform_specific_conditionals(defn, platform, closure): + output(foreach_platform_specific_value(defn, platform, "_condition", "condition", lambda cond: "if " + cond + "\n")) + closure(defn, platform) + output(foreach_platform_specific_value(defn, platform, "_condition", "condition", lambda cond: "endif " + cond + "\n")) + +def platform_specific_values(defn, platform, suffix, nonetag): + return foreach_platform_specific_value(defn, platform, suffix, nonetag, + lambda value: value + " ") + +def platform_values(defn, platform, suffix): + return foreach_platform_value(defn, platform, suffix, lambda value: value + " ") + +def extra_dist(defn): + return foreach_value(defn, "extra_dist", lambda value: value + " ") + +def platform_sources(defn, p): return platform_values(defn, p, "") +def platform_nodist_sources(defn, p): return platform_values(defn, p, "_nodist") + +def platform_startup(defn, p): return platform_specific_values(defn, p, "_startup", "startup") +def platform_ldadd(defn, p): return platform_specific_values(defn, p, "_ldadd", "ldadd") +def platform_dependencies(defn, p): return platform_specific_values(defn, p, "_dependencies", "dependencies") +def platform_cflags(defn, p): return platform_specific_values(defn, p, "_cflags", "cflags") +def platform_ldflags(defn, p): return platform_specific_values(defn, p, "_ldflags", "ldflags") +def platform_cppflags(defn, p): return platform_specific_values(defn, p, "_cppflags", "cppflags") +def platform_ccasflags(defn, p): return platform_specific_values(defn, p, "_ccasflags", "ccasflags") +def platform_stripflags(defn, p): return platform_specific_values(defn, p, "_stripflags", "stripflags") +def platform_objcopyflags(defn, p): return platform_specific_values(defn, p, "_objcopyflags", "objcopyflags") + +# +# Emit snippet only the first time through for the current name. +# +seen_target = set() + +def first_time(defn, snippet): + if defn['name'] not in seen_target: + return snippet + return '' + +def is_platform_independent(defn): + if 'enable' in defn: + return False + for suffix in [ "", "_nodist" ]: + template = platform_values(defn, GRUB_PLATFORMS[0], suffix) + for platform in GRUB_PLATFORMS[1:]: + if template != platform_values(defn, platform, suffix): + return False + + for suffix in [ "startup", "ldadd", "dependencies", "cflags", "ldflags", "cppflags", "ccasflags", "stripflags", "objcopyflags", "condition" ]: + template = platform_specific_values(defn, GRUB_PLATFORMS[0], "_" + suffix, suffix) + for platform in GRUB_PLATFORMS[1:]: + if template != platform_specific_values(defn, platform, "_" + suffix, suffix): + return False + for tag in [ "nostrip" ]: + template = platform_tagged(defn, GRUB_PLATFORMS[0], tag) + for platform in GRUB_PLATFORMS[1:]: + if template != platform_tagged(defn, platform, tag): + return False + + return True + +def module(defn, platform): + name = defn['name'] + set_canonical_name_suffix(".module") + + gvar_add("platform_PROGRAMS", name + ".module") + gvar_add("MODULE_FILES", name + ".module$(EXEEXT)") + + var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources") + var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources") + var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform)) + var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform)) + var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform)) + var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform)) + var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform)) + var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform)) + + gvar_add("dist_noinst_DATA", extra_dist(defn)) + gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)") + gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)") + + gvar_add("MOD_FILES", name + ".mod") + gvar_add("MARKER_FILES", name + ".marker") + gvar_add("CLEANFILES", name + ".marker") + output(""" +""" + name + """.marker: $(""" + cname(defn) + """_SOURCES) $(nodist_""" + cname(defn) + """_SOURCES) + $(TARGET_CPP) -DGRUB_LST_GENERATOR $(CPPFLAGS_MARKER) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(""" + cname(defn) + """_CPPFLAGS) $(CPPFLAGS) $^ > $@.new || (rm -f $@; exit 1) + grep 'MARKER' $@.new > $@; rm -f $@.new +""") + +def kernel(defn, platform): + name = defn['name'] + set_canonical_name_suffix(".exec") + gvar_add("platform_PROGRAMS", name + ".exec") + var_set(cname(defn) + "_SOURCES", platform_startup(defn, platform)) + var_add(cname(defn) + "_SOURCES", platform_sources(defn, platform)) + var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources") + var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform)) + var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_KERNEL) " + platform_cflags(defn, platform)) + var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_KERNEL) " + platform_ldflags(defn, platform)) + var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_KERNEL) " + platform_cppflags(defn, platform)) + var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_KERNEL) " + platform_ccasflags(defn, platform)) + var_set(cname(defn) + "_STRIPFLAGS", "$(AM_STRIPFLAGS) $(STRIPFLAGS_KERNEL) " + platform_stripflags(defn, platform)) + var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF)") + + gvar_add("dist_noinst_DATA", extra_dist(defn)) + gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)") + gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)") + + gvar_add("platform_DATA", name + ".img") + gvar_add("CLEANFILES", name + ".img") + rule(name + ".img", name + ".exec$(EXEEXT)", + if_platform_tagged(defn, platform, "nostrip", +"""if test x$(TARGET_APPLE_LINKER) = x1; then \ + $(TARGET_OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -ed2022 -wd1106 -nu -nd $< $@; \ + elif test ! -z '$(TARGET_OBJ2ELF)'; then \ + $(TARGET_OBJ2ELF) $< $@ || (rm -f $@; exit 1); \ + else cp $< $@; fi""", +"""if test x$(TARGET_APPLE_LINKER) = x1; then \ + $(TARGET_STRIP) -S -x $(""" + cname(defn) + """) -o $@.bin $<; \ + $(TARGET_OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -ed2022 -ed2016 -wd1106 -nu -nd $@.bin $@; \ + rm -f $@.bin; \ + elif test ! -z '$(TARGET_OBJ2ELF)'; then \ + """ + "$(TARGET_STRIP) $(" + cname(defn) + "_STRIPFLAGS) -o $@.bin $< && \ + $(TARGET_OBJ2ELF) $@.bin $@ || (rm -f $@; rm -f $@.bin; exit 1); \ + rm -f $@.bin; \ +else """ + "$(TARGET_STRIP) $(" + cname(defn) + "_STRIPFLAGS) -o $@ $<; \ +fi""")) + +def image(defn, platform): + name = defn['name'] + set_canonical_name_suffix(".image") + gvar_add("platform_PROGRAMS", name + ".image") + var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform)) + var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + "## platform nodist sources") + var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform)) + var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_IMAGE) " + platform_cflags(defn, platform)) + var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_IMAGE) " + platform_ldflags(defn, platform)) + var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_IMAGE) " + platform_cppflags(defn, platform)) + var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_IMAGE) " + platform_ccasflags(defn, platform)) + var_set(cname(defn) + "_OBJCOPYFLAGS", "$(OBJCOPYFLAGS_IMAGE) " + platform_objcopyflags(defn, platform)) + # var_set(cname(defn) + "_DEPENDENCIES", platform_dependencies(defn, platform) + " " + platform_ldadd(defn, platform)) + + gvar_add("dist_noinst_DATA", extra_dist(defn)) + gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)") + gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)") + + gvar_add("platform_DATA", name + ".img") + gvar_add("CLEANFILES", name + ".img") + rule(name + ".img", name + ".image$(EXEEXT)", """ +if test x$(TARGET_APPLE_LINKER) = x1; then \ + $(MACHO2IMG) $< $@; \ +else \ + $(TARGET_OBJCOPY) $(""" + cname(defn) + """_OBJCOPYFLAGS) --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .MIPS.abiflags -R .reginfo -R .rel.dyn -R .note.gnu.gold-version -R .ARM.exidx $< $@; \ +fi +""") + +def library(defn, platform): + name = defn['name'] + set_canonical_name_suffix("") + + vars_init(defn, + cname(defn) + "_SOURCES", + "nodist_" + cname(defn) + "_SOURCES", + cname(defn) + "_CFLAGS", + cname(defn) + "_CPPFLAGS", + cname(defn) + "_CCASFLAGS") + # cname(defn) + "_DEPENDENCIES") + + if name not in seen_target: + gvar_add("noinst_LIBRARIES", name) + var_add(cname(defn) + "_SOURCES", platform_sources(defn, platform)) + var_add("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform)) + var_add(cname(defn) + "_CFLAGS", first_time(defn, "$(AM_CFLAGS) $(CFLAGS_LIBRARY) ") + platform_cflags(defn, platform)) + var_add(cname(defn) + "_CPPFLAGS", first_time(defn, "$(AM_CPPFLAGS) $(CPPFLAGS_LIBRARY) ") + platform_cppflags(defn, platform)) + var_add(cname(defn) + "_CCASFLAGS", first_time(defn, "$(AM_CCASFLAGS) $(CCASFLAGS_LIBRARY) ") + platform_ccasflags(defn, platform)) + # var_add(cname(defn) + "_DEPENDENCIES", platform_dependencies(defn, platform) + " " + platform_ldadd(defn, platform)) + + gvar_add("dist_noinst_DATA", extra_dist(defn)) + if name not in seen_target: + gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)") + gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)") + +def installdir(defn, default="bin"): + return defn.get('installdir', default) + +def manpage(defn, adddeps): + name = defn['name'] + mansection = defn['mansection'] + + output("if COND_MAN_PAGES\n") + gvar_add("man_MANS", name + "." + mansection) + rule(name + "." + mansection, name + " " + adddeps, """ +chmod a+x """ + name + """ +PATH=$(builddir):$$PATH pkgdatadir=$(builddir) $(HELP2MAN) --section=""" + mansection + """ -i $(top_srcdir)/docs/man/""" + name + """.h2m -o $@ """ + name + """ +""") + gvar_add("CLEANFILES", name + "." + mansection) + output("endif\n") + +def program(defn, platform, test=False): + name = defn['name'] + set_canonical_name_suffix("") + + if 'testcase' in defn: + gvar_add("check_PROGRAMS", name) + gvar_add("TESTS", name) + else: + var_add(installdir(defn) + "_PROGRAMS", name) + if 'mansection' in defn: + manpage(defn, "") + + var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform)) + var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform)) + var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform)) + var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_PROGRAM) " + platform_cflags(defn, platform)) + var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_PROGRAM) " + platform_ldflags(defn, platform)) + var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_PROGRAM) " + platform_cppflags(defn, platform)) + var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_PROGRAM) " + platform_ccasflags(defn, platform)) + # var_set(cname(defn) + "_DEPENDENCIES", platform_dependencies(defn, platform) + " " + platform_ldadd(defn, platform)) + + gvar_add("dist_noinst_DATA", extra_dist(defn)) + gvar_add("BUILT_SOURCES", "$(nodist_" + cname(defn) + "_SOURCES)") + gvar_add("CLEANFILES", "$(nodist_" + cname(defn) + "_SOURCES)") + +def data(defn, platform): + var_add("dist_" + installdir(defn) + "_DATA", platform_sources(defn, platform)) + gvar_add("dist_noinst_DATA", extra_dist(defn)) + +def transform_data(defn, platform): + name = defn['name'] + + var_add(installdir(defn) + "_DATA", name) + + rule(name, "$(top_builddir)/config.status " + platform_sources(defn, platform) + platform_dependencies(defn, platform), """ +(for x in """ + platform_sources(defn, platform) + """; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:- +chmod a+x """ + name + """ +""") + + gvar_add("CLEANFILES", name) + gvar_add("EXTRA_DIST", extra_dist(defn)) + gvar_add("dist_noinst_DATA", platform_sources(defn, platform)) + +def script(defn, platform): + name = defn['name'] + + if 'testcase' in defn: + gvar_add("check_SCRIPTS", name) + gvar_add ("TESTS", name) + else: + var_add(installdir(defn) + "_SCRIPTS", name) + if 'mansection' in defn: + manpage(defn, "grub-mkconfig_lib") + + rule(name, "$(top_builddir)/config.status " + platform_sources(defn, platform) + platform_dependencies(defn, platform), """ +(for x in """ + platform_sources(defn, platform) + """; do cat $(srcdir)/"$$x"; done) | $(top_builddir)/config.status --file=$@:- +chmod a+x """ + name + """ +""") + + gvar_add("CLEANFILES", name) + gvar_add("EXTRA_DIST", extra_dist(defn)) + gvar_add("dist_noinst_DATA", platform_sources(defn, platform)) + +def rules(target, closure): + seen_target.clear() + seen_vars.clear() + + for defn in defparser.definitions.find_all(target): + if is_platform_independent(defn): + under_platform_specific_conditionals(defn, GRUB_PLATFORMS[0], closure) + else: + foreach_enabled_platform( + defn, + lambda p: under_platform_specific_conditionals(defn, p, closure)) + # Remember that we've seen this target. + seen_target.add(defn['name']) + +parser = OptionParser(usage="%prog DEFINITION-FILES") +_, args = parser.parse_args() + +for arg in args: + defparser.read_definitions(arg) + +rules("module", module) +rules("kernel", kernel) +rules("image", image) +rules("library", library) +rules("program", program) +rules("script", script) +rules("data", data) +rules("transform_data", transform_data) + +write_output(section='decl') +write_output() diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.am b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.am new file mode 100644 index 0000000..53b5028 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.am @@ -0,0 +1,507 @@ +AUTOMAKE_OPTIONS = subdir-objects -Wno-portability + +DEPDIR=.deps-core + +include $(top_srcdir)/conf/Makefile.common + +CC=$(TARGET_CC) +CPP=$(TARGET_CC) +CCAS=$(TARGET_CC) +RANLIB=$(TARGET_RANLIB) +STRIP=$(TARGET_STRIP) + +MACHO2IMG=$(top_builddir)/grub-macho2img + +AM_CFLAGS = $(TARGET_CFLAGS) +AM_LDFLAGS = $(TARGET_LDFLAGS) +AM_CPPFLAGS = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) +AM_CCASFLAGS = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) + +CFLAGS_PROGRAM += $(CFLAGS_PLATFORM) +LDFLAGS_PROGRAM += $(LDFLAGS_PLATFORM) +CPPFLAGS_PROGRAM += $(CPPFLAGS_PLATFORM) +CCASFLAGS_PROGRAM += $(CCASFLAGS_PLATFORM) + +CFLAGS_LIBRARY += $(CFLAGS_PLATFORM) -fno-builtin +CPPFLAGS_LIBRARY += $(CPPFLAGS_PLATFORM) +CCASFLAGS_LIBRARY += $(CCASFLAGS_PLATFORM) + +build-grub-pep2elf$(BUILD_EXEEXT): $(top_srcdir)/util/grub-pe2elf.c $(top_srcdir)/grub-core/kern/emu/misc.c $(top_srcdir)/util/misc.c + $(BUILD_CC) -o $@ -I$(top_srcdir)/include $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(BUILD_LDFLAGS) -DGRUB_BUILD=1 -DGRUB_TARGET_WORDSIZE=64 -DGRUB_UTIL=1 -DGRUB_BUILD_PROGRAM_NAME=\"build-grub-pep2elf\" $^ +CLEANFILES += build-grub-pep2elf$(BUILD_EXEEXT) + +build-grub-pe2elf$(BUILD_EXEEXT): $(top_srcdir)/util/grub-pe2elf.c $(top_srcdir)/grub-core/kern/emu/misc.c $(top_srcdir)/util/misc.c + $(BUILD_CC) -o $@ -I$(top_srcdir)/include $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(BUILD_LDFLAGS) -DGRUB_BUILD=1 -DGRUB_TARGET_WORDSIZE=32 -DGRUB_UTIL=1 -DGRUB_BUILD_PROGRAM_NAME=\"build-grub-pe2elf\" $^ +CLEANFILES += build-grub-pe2elf$(BUILD_EXEEXT) + +# gentrigtables +gentrigtables$(BUILD_EXEEXT): gentrigtables.c + $(BUILD_CC) -o $@ -I$(top_srcdir)/include $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(BUILD_LDFLAGS) $< $(BUILD_LIBM) +CLEANFILES += gentrigtables$(BUILD_EXEEXT) + +build-grub-module-verifier$(BUILD_EXEEXT): $(top_srcdir)/util/grub-module-verifier.c $(top_srcdir)/util/grub-module-verifier32.c $(top_srcdir)/util/grub-module-verifier64.c $(top_srcdir)/grub-core/kern/emu/misc.c $(top_srcdir)/util/misc.c + $(BUILD_CC) -o $@ -I$(top_srcdir)/include $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(BUILD_LDFLAGS) -DGRUB_BUILD=1 -DGRUB_UTIL=1 -DGRUB_BUILD_PROGRAM_NAME=\"build-grub-module-verifier\" $^ +CLEANFILES += build-grub-module-verifier$(BUILD_EXEEXT) + +# trigtables.c +trigtables.c: gentrigtables$(BUILD_EXEEXT) gentrigtables.c $(top_srcdir)/configure.ac + ./gentrigtables$(BUILD_EXEEXT) > $@ +CLEANFILES += trigtables.c + +# XXX Use Automake's LEX & YACC support +grub_script.tab.h: script/parser.y + $(YACC) -d -p grub_script_yy -b grub_script $< +grub_script.tab.c: grub_script.tab.h +CLEANFILES += grub_script.tab.c grub_script.tab.h + +# For the lexer. +grub_script.yy.h: script/yylex.l + $(LEX) -o grub_script.yy.c --header-file=grub_script.yy.h $< +grub_script.yy.c: grub_script.yy.h + +rs_decoder.h: $(srcdir)/lib/reed_solomon.c + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Os -I$(top_builddir) -S -DSTANDALONE -o $@ $< -g0 -mregparm=3 -ffreestanding + +CLEANFILES += grub_script.yy.c grub_script.yy.h + +include $(srcdir)/Makefile.core.am + +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/dl.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/list.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/misc.h +if COND_emu +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/compiler-rt-emu.h +else +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/compiler-rt.h +endif +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h + +if COND_i386_pc +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +endif + +if COND_i386_xen_pvh +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/xen.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/xen/hypercall.h +endif + +if COND_i386_efi +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h +endif + +if COND_i386_coreboot +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/coreboot/lbio.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video_fb.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gfxterm.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/font.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bufio.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +endif + +if COND_i386_multiboot +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +endif + +if COND_i386_qemu +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +endif + +if COND_i386_ieee1275 +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +endif + +if COND_i386_xen +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/xen.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/xen/hypercall.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h +endif + +if COND_x86_64_xen +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/xen.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/x86_64/xen/hypercall.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h +endif + +if COND_x86_64_efi +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pmtimer.h +endif + +if COND_ia64_efi +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +endif + +if COND_mips +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/kernel.h +endif + +if COND_mips_arc +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arc/arc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +endif + +if COND_mips_qemu_mips +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/serial.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +endif + +if COND_mips_loongson +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/time.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video_fb.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gfxterm.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/font.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bufio.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cs5536.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pci.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/serial.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +endif + +if COND_mips_qemu_mips +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h +endif + +if COND_mips64_efi +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loongson.h +endif + +if COND_powerpc_ieee1275 +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +endif + +if COND_sparc64_ieee1275 +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sparc64/ieee1275/ieee1275.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +endif + +if COND_arm_uboot +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/uboot/uboot.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/uboot/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h +endif + +if COND_arm_coreboot +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video_fb.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gfxterm.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/font.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bufio.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/dma.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/coreboot/kernel.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdtbus.h +endif + +if COND_arm_efi +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +endif + +if COND_arm64_efi +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +endif + +if COND_riscv32_efi +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +endif + +if COND_riscv64_efi +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h +endif + +if COND_emu +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/net.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostdisk.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostfile.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h +if COND_GRUB_EMU_SDL +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h +endif +if COND_GRUB_EMU_PCI +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libpciaccess.h +endif +endif + +symlist.h: $(top_builddir)/config.h $(KERNEL_HEADER_FILES) + @list='$^'; \ + for p in $$list; do \ + echo "#include <$$p>" >> $@ || (rm -f $@; exit 1); \ + done +CLEANFILES += symlist.h +BUILT_SOURCES += symlist.h + +symlist.c: symlist.h gensymlist.sh + $(TARGET_CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS_KERNEL) $(CPPFLAGS) -DGRUB_SYMBOL_GENERATOR=1 symlist.h > symlist.p || (rm -f symlist.p; exit 1) + cat symlist.p | $(SHELL) $(srcdir)/gensymlist.sh $(top_builddir)/config.h $(KERNEL_HEADER_FILES) >$@ || (rm -f $@; exit 1) + rm -f symlist.p +CLEANFILES += symlist.c +BUILT_SOURCES += symlist.c + +if COND_HAVE_ASM_USCORE +ASM_PREFIX=_ +else +ASM_PREFIX= +endif + +noinst_DATA += kernel_syms.lst + +kernel_syms.lst: $(KERNEL_HEADER_FILES) $(top_builddir)/config.h + $(TARGET_CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS_KERNEL) $(CPPFLAGS) $(CFLAGS) -DGRUB_SYMBOL_GENERATOR=1 $^ >kernel_syms.input + cat kernel_syms.input | grep -v '^#' | sed -n \ + -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/defined kernel '"$(ASM_PREFIX)"'\1/;p;}' \ + -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/defined kernel '"$(ASM_PREFIX)"'\1/;p;}' \ + | sort -u >$@ + rm -f kernel_syms.input +CLEANFILES += kernel_syms.lst + +if COND_emu +kern/emu/grub_emu-main.$(OBJEXT):grub_emu_init.h +grub_emu-grub_emu_init.$(OBJEXT):grub_emu_init.h +kern/emu/grub_emu_dyn-main.$(OBJEXT):grub_emu_init.h +grub_emu_dyn-grub_emu_init.$(OBJEXT):grub_emu_init.h + +grub_emu_init.h: genemuinitheader.sh $(MODULE_FILES) + rm -f $@; echo $(MODULE_FILES) | sh $(srcdir)/genemuinitheader.sh $(TARGET_NM) > $@ +CLEANFILES += grub_emu_init.h + +grub_emu_init.c: grub_emu_init.h genemuinit.sh $(MODULE_FILES) + rm -f $@; echo $(MODULE_FILES) | sh $(srcdir)/genemuinit.sh $(TARGET_NM) > $@ +CLEANFILES += grub_emu_init.c +endif + +# List files + +fs.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + if grep 'FS_LIST_MARKER' $$pp >/dev/null 2>&1; then \ + echo $$b; \ + fi; \ + done) | sort -u > $@ +platform_DATA += fs.lst +CLEANFILES += fs.lst + +command.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + sed -n \ + -e "/EXTCOMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ + -e "/P1COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ + -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ + done) | sort -u > $@ +platform_DATA += command.lst +CLEANFILES += command.lst + +partmap.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + if grep 'PARTMAP_LIST_MARKER' $$pp >/dev/null 2>&1; then \ + echo $$b; \ + fi; \ + done) | sort -u > $@ +platform_DATA += partmap.lst +CLEANFILES += partmap.lst + +terminal.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + sed -n \ + -e "/INPUT_TERMINAL_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $$b/;p;}" \ + -e "/OUTPUT_TERMINAL_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $$b/;p;}" $$pp; \ + done) | sort -u > $@ +platform_DATA += terminal.lst +CLEANFILES += terminal.lst + +fdt.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + sed -n \ + -e "/FDT_DRIVER_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $$b/;p;}" \ + -e "/FDT_DRIVER_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $$b/;p;}" $$pp; \ + done) | sort -u > $@ +platform_DATA += fdt.lst +CLEANFILES += fdt.lst + +parttool.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + sed -n \ + -e "/PARTTOOL_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ + done) | sort -u > $@ +platform_DATA += parttool.lst +CLEANFILES += parttool.lst + +video.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + if grep 'VIDEO_LIST_MARKER' $$pp >/dev/null 2>&1; then \ + echo $$b; \ + fi; \ + done) | sort -u > $@ +platform_DATA += video.lst +CLEANFILES += video.lst + +# but, crypto.lst is simply copied +crypto.lst: $(srcdir)/lib/libgcrypt-grub/cipher/crypto.lst + cp $^ $@ +platform_DATA += crypto.lst +CLEANFILES += crypto.lst + +syminfo.lst: gensyminfo.sh kernel_syms.lst $(MODULE_FILES) + cat kernel_syms.lst > $@.new + for m in $(MODULE_FILES); do \ + sh $< $$m >> $@.new || exit 1; \ + done + mv $@.new $@ + +# generate global module dependencies list +moddep.lst: syminfo.lst genmoddep.awk video.lst + cat $< | sort | $(AWK) -f $(srcdir)/genmoddep.awk > $@ || (rm -f $@; exit 1) +platform_DATA += moddep.lst +CLEANFILES += config.log syminfo.lst moddep.lst + +$(MOD_FILES): %.mod : genmod.sh moddep.lst %.module$(EXEEXT) build-grub-module-verifier$(BUILD_EXEEXT) + TARGET_OBJ2ELF=@TARGET_OBJ2ELF@ sh $^ $@ +platform_DATA += $(MOD_FILES) +platform_DATA += modinfo.sh +CLEANFILES += $(MOD_FILES) + +if COND_ENABLE_EFIEMU +efiemu32.o: efiemu/runtime/efiemu.c $(TARGET_OBJ2ELF) + -rm -f $@ + -rm -f $@.bin + $(TARGET_CC) $(DEFS) $(INCLUDES) $(CPPFLAGS_EFIEMU) $(CPPFLAGS_DEFAULT) -m32 -Wall -Werror -nostdlib -static -O2 -c -o $@.bin $< + if test "x$(TARGET_APPLE_LINKER)" = x1; then \ + $(TARGET_OBJCONV) -felf32 -nu -nd $@.bin $@ || exit 1; \ + rm -f $@.bin ; \ + elif test ! -z "$(TARGET_OBJ2ELF)"; then \ + $(TARGET_OBJ2ELF) $@.bin || (rm -f $@.bin; exit 1); \ + mv $@.bin $@ ; \ + else \ + mv $@.bin $@ ; \ + fi + +# Link format -arch,x86_64 means Apple linker +efiemu64_c.o: efiemu/runtime/efiemu.c + $(TARGET_CC) $(DEFS) $(INCLUDES) $(CPPFLAGS_EFIEMU) $(CPPFLAGS_DEFAULT) -m64 -nostdlib -Wall -Werror -O2 -mcmodel=large -mno-red-zone -c -o $@ $< + +efiemu64_s.o: efiemu/runtime/efiemu.S + $(TARGET_CC) $(DEFS) $(INCLUDES) $(CPPFLAGS_EFIEMU) $(CPPFLAGS_DEFAULT) -m64 -Wall -Werror -nostdlib -O2 -mcmodel=large -mno-red-zone -c -o $@ $< + +efiemu64.o: efiemu64_c.o efiemu64_s.o $(TARGET_OBJ2ELEF) + -rm -f $@ + -rm -f $@.bin + $(TARGET_CC) -m64 $(EFIEMU64_LINK_FORMAT) -nostdlib -static -Wl,-r -o $@.bin $^ + if test "x$(EFIEMU64_LINK_FORMAT)" = x-arch,x86_64; then \ + $(TARGET_OBJCONV) -felf64 -nu -nd $@.bin $@ || exit 1; \ + rm -f $@.bin; \ + else \ + mv $@.bin $@ ; \ + fi + +platform_DATA += efiemu32.o efiemu64.o +CLEANFILES += efiemu32.o efiemu64.o efiemu64_c.o efiemu64_s.o +endif + +windowsdir=$(top_builddir)/$(PACKAGE)-$(VERSION)-for-windows +windowsdir: $(PROGRAMS) $(starfield_DATA) $(platform_DATA) + test -d $(windowsdir)/$(target_cpu)-$(platform) || mkdir $(windowsdir)/$(target_cpu)-$(platform) + for x in $(platform_DATA); do \ + cp -fp $$x $(windowsdir)/$(target_cpu)-$(platform)/$$x; \ + done diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def new file mode 100644 index 0000000..d722dbf --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def @@ -0,0 +1,2586 @@ +AutoGen definitions Makefile.tpl; + +transform_data = { + installdir = noinst; + name = gensyminfo.sh; + common = gensyminfo.sh.in; +}; + +transform_data = { + installdir = noinst; + name = genmod.sh; + common = genmod.sh.in; +}; + +transform_data = { + installdir = noinst; + name = modinfo.sh; + common = modinfo.sh.in; +}; + +transform_data = { + installdir = platform; + name = gmodule.pl; + common = gmodule.pl.in; +}; + +transform_data = { + installdir = platform; + name = gdb_grub; + common = gdb_grub.in; +}; + +transform_data = { + installdir = platform; + name = grub.chrp; + common = boot/powerpc/grub.chrp.in; + enable = powerpc_ieee1275; +}; + +transform_data = { + installdir = platform; + name = bootinfo.txt; + common = boot/powerpc/bootinfo.txt.in; + enable = powerpc_ieee1275; +}; + +kernel = { + name = kernel; + + nostrip = emu; + + emu_ldflags = '-Wl,-r,-d'; + i386_efi_ldflags = '-Wl,-r,-d'; + i386_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; + x86_64_efi_ldflags = '-Wl,-r,-d'; + x86_64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; + + ia64_efi_cflags = '-fno-builtin -fpic -minline-int-divide-max-throughput'; + ia64_efi_ldflags = '-Wl,-r,-d'; + ia64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; + + arm_efi_ldflags = '-Wl,-r,-d'; + arm_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; + + arm64_efi_ldflags = '-Wl,-r,-d'; + arm64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; + + riscv32_efi_ldflags = '-Wl,-r,-d'; + riscv32_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; + + riscv64_efi_ldflags = '-Wl,-r,-d'; + riscv64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; + + i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x9000'; + i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_qemu_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x9000'; + i386_coreboot_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_coreboot_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x9000'; + i386_multiboot_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_multiboot_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x9000'; + i386_ieee1275_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_ieee1275_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x10000'; + i386_xen_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_xen_ldflags = '$(TARGET_IMG_BASE_LDOPT),0'; + x86_64_xen_ldflags = '$(TARGET_IMG_LDFLAGS)'; + x86_64_xen_ldflags = '$(TARGET_IMG_BASE_LDOPT),0'; + i386_xen_pvh_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_xen_pvh_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x100000'; + + mips_loongson_ldflags = '-Wl,-Ttext,0x80200000'; + powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000'; + sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400'; + mips_arc_ldflags = '-Wl,-Ttext,$(TARGET_LINK_ADDR)'; + mips_qemu_mips_ldflags = '-Wl,-Ttext,0x80200000'; + + mips_arc_cppflags = '-DGRUB_DECOMPRESSOR_LINK_ADDR=$(TARGET_DECOMPRESSOR_LINK_ADDR)'; + i386_qemu_cppflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)'; + emu_cflags = '$(CFLAGS_GNULIB)'; + emu_cppflags = '$(CPPFLAGS_GNULIB)'; + arm_uboot_ldflags = '-Wl,-r,-d'; + arm_uboot_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; + + mips64_efi_ldflags = '-Wl,-r,-d'; + mips64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame -R .MIPS.abiflags'; + + arm_coreboot_ldflags = '-Wl,-r,-d'; + arm_coreboot_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; + + i386_pc_startup = kern/i386/pc/startup.S; + i386_efi_startup = kern/i386/efi/startup.S; + x86_64_efi_startup = kern/x86_64/efi/startup.S; + i386_xen_startup = kern/i386/xen/startup.S; + x86_64_xen_startup = kern/x86_64/xen/startup.S; + i386_xen_pvh_startup = kern/i386/xen/startup_pvh.S; + i386_qemu_startup = kern/i386/qemu/startup.S; + i386_ieee1275_startup = kern/i386/ieee1275/startup.S; + i386_coreboot_startup = kern/i386/coreboot/startup.S; + i386_multiboot_startup = kern/i386/coreboot/startup.S; + mips_startup = kern/mips/startup.S; + mips64_efi_startup = kern/mips64/efi/startup.S; + sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S; + powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S; + arm_uboot_startup = kern/arm/startup.S; + arm_coreboot_startup = kern/arm/startup.S; + arm_efi_startup = kern/arm/efi/startup.S; + arm64_efi_startup = kern/arm64/efi/startup.S; + riscv32_efi_startup = kern/riscv/efi/startup.S; + riscv64_efi_startup = kern/riscv/efi/startup.S; + + common = kern/command.c; + common = kern/corecmd.c; + common = kern/device.c; + common = kern/disk.c; + common = kern/dl.c; + common = kern/env.c; + common = kern/err.c; + common = kern/file.c; + common = kern/fs.c; + common = kern/list.c; + common = kern/main.c; + common = kern/misc.c; + common = kern/parser.c; + common = kern/partition.c; + common = kern/rescue_parser.c; + common = kern/rescue_reader.c; + common = kern/term.c; + + noemu = kern/compiler-rt.c; + noemu = kern/mm.c; + noemu = kern/time.c; + noemu = kern/generic/millisleep.c; + + noemu_nodist = symlist.c; + + mips = kern/generic/rtc_get_time_ms.c; + + ieee1275 = disk/ieee1275/ofdisk.c; + ieee1275 = kern/ieee1275/cmain.c; + ieee1275 = kern/ieee1275/ieee1275.c; + ieee1275 = kern/ieee1275/mmap.c; + ieee1275 = kern/ieee1275/openfw.c; + ieee1275 = term/ieee1275/console.c; + ieee1275 = kern/ieee1275/init.c; + + uboot = disk/uboot/ubootdisk.c; + uboot = kern/uboot/uboot.c; + uboot = kern/uboot/init.c; + uboot = kern/uboot/hw.c; + uboot = term/uboot/console.c; + arm_uboot = kern/arm/uboot/init.c; + arm_uboot = kern/arm/uboot/uboot.S; + + arm_coreboot = kern/arm/coreboot/init.c; + arm_coreboot = kern/arm/coreboot/timer.c; + arm_coreboot = kern/arm/coreboot/coreboot.S; + arm_coreboot = lib/fdt.c; + arm_coreboot = bus/fdt.c; + arm_coreboot = term/ps2.c; + arm_coreboot = term/arm/pl050.c; + arm_coreboot = term/arm/cros.c; + arm_coreboot = term/arm/cros_ec.c; + arm_coreboot = bus/spi/rk3288_spi.c; + arm_coreboot = commands/keylayouts.c; + arm_coreboot = kern/arm/coreboot/dma.c; + + terminfoinkernel = term/terminfo.c; + terminfoinkernel = term/tparm.c; + terminfoinkernel = commands/extcmd.c; + terminfoinkernel = lib/arg.c; + + softdiv = lib/division.c; + + i386 = kern/i386/dl.c; + i386_xen = kern/i386/dl.c; + i386_xen_pvh = kern/i386/dl.c; + + i386_coreboot = kern/i386/coreboot/init.c; + i386_multiboot = kern/i386/coreboot/init.c; + i386_qemu = kern/i386/qemu/init.c; + i386_coreboot_multiboot_qemu = term/i386/pc/vga_text.c; + coreboot = video/coreboot/cbfb.c; + + efi = disk/efi/efidisk.c; + efi = kern/efi/efi.c; + efi = kern/efi/init.c; + efi = kern/efi/mm.c; + efi = term/efi/console.c; + efi = kern/acpi.c; + efi = kern/efi/acpi.c; + i386_coreboot = kern/i386/pc/acpi.c; + i386_multiboot = kern/i386/pc/acpi.c; + i386_coreboot = kern/acpi.c; + i386_multiboot = kern/acpi.c; + + x86 = kern/i386/tsc.c; + x86 = kern/i386/tsc_pit.c; + i386_efi = kern/i386/efi/tsc.c; + x86_64_efi = kern/i386/efi/tsc.c; + i386_efi = kern/i386/tsc_pmtimer.c; + i386_coreboot = kern/i386/tsc_pmtimer.c; + x86_64_efi = kern/i386/tsc_pmtimer.c; + + i386_efi = kern/i386/efi/init.c; + i386_efi = bus/pci.c; + + x86_64 = kern/x86_64/dl.c; + x86_64_xen = kern/x86_64/dl.c; + x86_64_efi = kern/x86_64/efi/callwrap.S; + x86_64_efi = kern/i386/efi/init.c; + x86_64_efi = bus/pci.c; + + xen = kern/i386/tsc.c; + xen = kern/i386/xen/tsc.c; + x86_64_xen = kern/x86_64/xen/hypercall.S; + i386_xen = kern/i386/xen/hypercall.S; + xen = kern/xen/init.c; + xen = term/xen/console.c; + xen = disk/xen/xendisk.c; + xen = commands/boot.c; + + i386_xen_pvh = commands/boot.c; + i386_xen_pvh = disk/xen/xendisk.c; + i386_xen_pvh = kern/i386/tsc.c; + i386_xen_pvh = kern/i386/xen/tsc.c; + i386_xen_pvh = kern/i386/xen/pvh.c; + i386_xen_pvh = kern/xen/init.c; + i386_xen_pvh = term/xen/console.c; + + ia64_efi = kern/ia64/efi/startup.S; + ia64_efi = kern/ia64/efi/init.c; + ia64_efi = kern/ia64/dl.c; + ia64_efi = kern/ia64/dl_helper.c; + ia64_efi = kern/ia64/cache.c; + + arm_efi = kern/arm/efi/init.c; + arm_efi = kern/efi/fdt.c; + + arm64_efi = kern/arm64/efi/init.c; + arm64_efi = kern/efi/fdt.c; + + riscv32_efi = kern/riscv/efi/init.c; + riscv32_efi = kern/efi/fdt.c; + + riscv64_efi = kern/riscv/efi/init.c; + riscv64_efi = kern/efi/fdt.c; + + i386_pc = kern/i386/pc/init.c; + i386_pc = kern/i386/pc/mmap.c; + i386_pc = term/i386/pc/console.c; + + i386_qemu = bus/pci.c; + i386_qemu = kern/vga_init.c; + i386_qemu = kern/i386/qemu/mmap.c; + + coreboot = kern/coreboot/mmap.c; + i386_coreboot = kern/i386/coreboot/cbtable.c; + coreboot = kern/coreboot/cbtable.c; + arm_coreboot = kern/arm/coreboot/cbtable.c; + + i386_multiboot = kern/i386/multiboot_mmap.c; + + mips = kern/mips/cache.S; + mips = kern/mips/dl.c; + mips = kern/mips/init.c; + + mips_qemu_mips = kern/mips/qemu_mips/init.c; + mips_qemu_mips = term/ns8250.c; + mips_qemu_mips = term/serial.c; + mips_qemu_mips = term/at_keyboard.c; + mips_qemu_mips = term/ps2.c; + mips_qemu_mips = commands/boot.c; + mips_qemu_mips = commands/keylayouts.c; + mips_qemu_mips = term/i386/pc/vga_text.c; + mips_qemu_mips = kern/vga_init.c; + + mips_arc = kern/mips/arc/init.c; + mips_arc = term/arc/console.c; + mips_arc = disk/arc/arcdisk.c; + + mips_loongson = term/ns8250.c; + mips_loongson = bus/bonito.c; + mips_loongson = bus/cs5536.c; + mips_loongson = bus/pci.c; + mips_loongson = kern/mips/loongson/init.c; + mips_loongson = term/at_keyboard.c; + mips_loongson = term/ps2.c; + mips_loongson = commands/boot.c; + mips_loongson = term/serial.c; + mips_loongson = video/sm712.c; + mips_loongson = video/sis315pro.c; + mips_loongson = video/radeon_fuloong2e.c; + mips_loongson = video/radeon_yeeloong3a.c; + extra_dist = video/sm712_init.c; + extra_dist = video/sis315_init.c; + mips_loongson = commands/keylayouts.c; + + mips64 = kern/mips64/init.c; + mips64 = kern/mips64/dl.c; + mips64 = kern/mips64/cache.S; + mips64 = kern/generic/rtc_get_time_ms.c; + mips64_efi = kern/mips64/efi/init.c; + mips64_efi = kern/mips64/efi/loongson.c; + mips64_efi = lib/mips64/efi/loongson.c; + mips64_efi = lib/mips64/efi/loongson_asm.S; + + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; + powerpc_ieee1275 = kern/powerpc/compiler-rt.S; + + sparc64_ieee1275 = kern/sparc64/cache.S; + sparc64_ieee1275 = kern/sparc64/dl.c; + sparc64_ieee1275 = kern/sparc64/ieee1275/ieee1275.c; + sparc64_ieee1275 = disk/ieee1275/obdisk.c; + + arm = kern/arm/dl.c; + arm = kern/arm/dl_helper.c; + arm = kern/arm/cache_armv6.S; + arm = kern/arm/cache_armv7.S; + extra_dist = kern/arm/cache.S; + arm = kern/arm/cache.c; + arm = kern/arm/compiler-rt.S; + + arm64 = kern/arm64/cache.c; + arm64 = kern/arm64/cache_flush.S; + arm64 = kern/arm64/dl.c; + arm64 = kern/arm64/dl_helper.c; + + riscv32 = kern/riscv/cache.c; + riscv32 = kern/riscv/cache_flush.S; + riscv32 = kern/riscv/dl.c; + + riscv64 = kern/riscv/cache.c; + riscv64 = kern/riscv/cache_flush.S; + riscv64 = kern/riscv/dl.c; + + emu = disk/host.c; + emu = kern/emu/cache_s.S; + emu = kern/emu/hostdisk.c; + emu = osdep/unix/hostdisk.c; + emu = osdep/exec.c; + extra_dist = osdep/unix/exec.c; + emu = osdep/devmapper/hostdisk.c; + emu = osdep/hostdisk.c; + emu = kern/emu/hostfs.c; + emu = kern/emu/main.c; + emu = kern/emu/argp_common.c; + emu = kern/emu/misc.c; + emu = kern/emu/mm.c; + emu = kern/emu/time.c; + emu = kern/emu/cache.c; + emu = osdep/emuconsole.c; + extra_dist = osdep/unix/emuconsole.c; + extra_dist = osdep/windows/emuconsole.c; + emu = osdep/dl.c; + extra_dist = osdep/unix/dl.c; + extra_dist = osdep/windows/dl.c; + emu = osdep/sleep.c; + emu = osdep/init.c; + emu = osdep/emunet.c; + extra_dist = osdep/linux/emunet.c; + extra_dist = osdep/basic/emunet.c; + emu = osdep/cputime.c; + extra_dist = osdep/unix/cputime.c; + extra_dist = osdep/windows/cputime.c; + + videoinkernel = term/gfxterm.c; + videoinkernel = font/font.c; + videoinkernel = font/font_cmd.c; + videoinkernel = io/bufio.c; + videoinkernel = video/fb/fbblit.c; + videoinkernel = video/fb/fbfill.c; + videoinkernel = video/fb/fbutil.c; + videoinkernel = video/fb/video_fb.c; + videoinkernel = video/video.c; + + extra_dist = kern/i386/int.S; + extra_dist = kern/i386/realmode.S; + extra_dist = boot/i386/pc/lzma_decode.S; + extra_dist = kern/mips/cache_flush.S; +}; + +program = { + name = grub-emu; + mansection = 1; + + emu = kern/emu/full.c; + emu_nodist = grub_emu_init.c; + + ldadd = 'kernel.exec$(EXEEXT)'; + ldadd = '$(MODULE_FILES)'; + ldadd = 'lib/gnulib/libgnu.a $(LIBINTL) $(LIBUTIL) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + + enable = emu; +}; + +program = { + name = grub-emu-lite; + + emu = kern/emu/lite.c; + emu_nodist = symlist.c; + + ldadd = 'kernel.exec$(EXEEXT)'; + ldadd = 'lib/gnulib/libgnu.a $(LIBINTL) $(LIBUTIL) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + + enable = emu; +}; + +image = { + name = boot; + i386_pc = boot/i386/pc/boot.S; + i386_qemu = boot/i386/qemu/boot.S; + sparc64_ieee1275 = boot/sparc64/ieee1275/boot.S; + + i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00'; + + i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_qemu_ldflags = '$(TARGET_IMG_BASE_LDOPT),$(GRUB_BOOT_MACHINE_LINK_ADDR)'; + i386_qemu_ccasflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)'; + + /* The entry point for a.out binaries on sparc64 starts + at 0x4000. Since we are writing the 32 bytes long a.out + header in the assembly code ourselves, we need to tell + the linker to adjust the start of the text segment to + 0x4000 - 0x20 = 0x3fe0. + */ + sparc64_ieee1275_ldflags = ' -Wl,-Ttext=0x3fe0'; + sparc64_ieee1275_objcopyflags = '-O binary'; + + objcopyflags = '-O binary'; + enable = i386_pc; + enable = i386_qemu; + enable = sparc64_ieee1275; +}; + +image = { + name = boot_hybrid; + i386_pc = boot/i386/pc/boot.S; + + cppflags = '-DHYBRID_BOOT=1'; + + i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00'; + + objcopyflags = '-O binary'; + enable = i386_pc; +}; + +image = { + name = cdboot; + + i386_pc = boot/i386/pc/cdboot.S; + i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00'; + + sparc64_ieee1275 = boot/sparc64/ieee1275/boot.S; + + /* See comment for sparc64_ieee1275_ldflags above. */ + sparc64_ieee1275_ldflags = ' -Wl,-Ttext=0x3fe0'; + sparc64_ieee1275_objcopyflags = '-O binary'; + sparc64_ieee1275_cppflags = '-DCDBOOT=1'; + + objcopyflags = '-O binary'; + + enable = sparc64_ieee1275; + enable = i386_pc; +}; + +image = { + name = pxeboot; + i386_pc = boot/i386/pc/pxeboot.S; + + i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x7C00'; + + objcopyflags = '-O binary'; + enable = i386_pc; +}; + +image = { + name = diskboot; + i386_pc = boot/i386/pc/diskboot.S; + + i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8000'; + + sparc64_ieee1275 = boot/sparc64/ieee1275/diskboot.S; + sparc64_ieee1275_ldflags = '-Wl,-Ttext=0x4200'; + + objcopyflags = '-O binary'; + + enable = i386_pc; + enable = sparc64_ieee1275; +}; + +image = { + name = lnxboot; + i386_pc = boot/i386/pc/lnxboot.S; + + i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; + i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x6000'; + + objcopyflags = '-O binary'; + enable = i386_pc; +}; + +image = { + name = xz_decompress; + mips = boot/mips/startup_raw.S; + common = boot/decompressor/minilib.c; + common = boot/decompressor/xz.c; + common = lib/xzembed/xz_dec_bcj.c; + common = lib/xzembed/xz_dec_lzma2.c; + common = lib/xzembed/xz_dec_stream.c; + common = kern/compiler-rt.c; + + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed -DGRUB_EMBED_DECOMPRESSOR=1'; + + objcopyflags = '-O binary'; + mips_ldflags = '-Wl,-Ttext,$(TARGET_DECOMPRESSOR_LINK_ADDR)'; + cflags = '-Wno-unreachable-code'; + enable = mips; +}; + +image = { + name = none_decompress; + mips = boot/mips/startup_raw.S; + common = boot/decompressor/none.c; + + cppflags = '-DGRUB_EMBED_DECOMPRESSOR=1'; + + objcopyflags = '-O binary'; + mips_ldflags = '-Wl,-Ttext,$(TARGET_DECOMPRESSOR_LINK_ADDR)'; + enable = mips; +}; + +image = { + name = lzma_decompress; + i386_pc = boot/i386/pc/startup_raw.S; + i386_pc_nodist = rs_decoder.h; + + objcopyflags = '-O binary'; + ldflags = '$(TARGET_IMG_LDFLAGS) $(TARGET_IMG_BASE_LDOPT),0x8200'; + enable = i386_pc; +}; + +image = { + name = fwstart; + mips_loongson = boot/mips/loongson/fwstart.S; + objcopyflags = '-O binary'; + ldflags = '-Wl,-N,-S,-Ttext,0xbfc00000,-Bstatic'; + enable = mips_loongson; +}; + +image = { + name = fwstart_fuloong2f; + mips_loongson = boot/mips/loongson/fuloong2f.S; + objcopyflags = '-O binary'; + ldflags = '-Wl,-N,-S,-Ttext,0xbfc00000,-Bstatic'; + enable = mips_loongson; +}; + +module = { + name = disk; + common = lib/disk.c; + extra_dist = kern/disk_common.c; +}; + +module = { + name = trig; + common_nodist = trigtables.c; + extra_dist = gentrigtables.c; +}; + +module = { + name = cs5536; + x86 = bus/cs5536.c; + enable = x86; +}; + +module = { + name = lsspd; + mips_loongson = commands/mips/loongson/lsspd.c; + enable = mips_loongson; +}; + +module = { + name = usb; + common = bus/usb/usb.c; + common = bus/usb/usbtrans.c; + common = bus/usb/usbhub.c; + enable = usb; +}; + +module = { + name = usbserial_common; + common = bus/usb/serial/common.c; + enable = usb; +}; + +module = { + name = usbserial_pl2303; + common = bus/usb/serial/pl2303.c; + enable = usb; +}; + +module = { + name = usbserial_ftdi; + common = bus/usb/serial/ftdi.c; + enable = usb; +}; + +module = { + name = usbserial_usbdebug; + common = bus/usb/serial/usbdebug_late.c; + enable = usb; +}; + +module = { + name = uhci; + common = bus/usb/uhci.c; + enable = pci; +}; + +module = { + name = ohci; + common = bus/usb/ohci.c; + enable = pci; +}; + +module = { + name = ehci; + common = bus/usb/ehci.c; + arm_coreboot = bus/usb/ehci-fdt.c; + pci = bus/usb/ehci-pci.c; + enable = pci; + enable = arm_coreboot; +}; + +module = { + name = pci; + common = bus/pci.c; + i386_ieee1275 = bus/i386/ieee1275/pci.c; + + enable = i386_pc; + enable = i386_ieee1275; + enable = i386_coreboot; + enable = i386_multiboot; +}; + +module = { + name = nativedisk; + common = commands/nativedisk.c; + + enable = x86; + enable = mips_loongson; + enable = mips_qemu_mips; +}; + +module = { + name = emupci; + common = bus/emu/pci.c; + common = commands/lspci.c; + + enable = emu; + condition = COND_GRUB_EMU_PCI; +}; + +module = { + name = lsdev; + common = commands/arc/lsdev.c; + + enable = mips_arc; +}; + +module = { + name = lsxen; + common = commands/xen/lsxen.c; + + enable = xen; +}; + +module = { + name = cmostest; + common = commands/i386/cmostest.c; + enable = cmos; +}; + +module = { + name = cmosdump; + common = commands/i386/cmosdump.c; + enable = cmos; +}; + +module = { + name = iorw; + common = commands/iorw.c; + enable = x86; +}; + +module = { + name = cbtable; + common = kern/i386/coreboot/cbtable.c; + common = kern/coreboot/cbtable.c; + enable = i386_pc; + enable = i386_efi; + enable = i386_qemu; + enable = i386_multiboot; + enable = i386_ieee1275; + enable = x86_64_efi; +}; + +module = { + name = cbtime; + common = commands/i386/coreboot/cb_timestamps.c; + enable = x86; +}; + +module = { + name = cbls; + common = commands/i386/coreboot/cbls.c; + enable = x86; +}; + +module = { + name = cbmemc; + common = term/i386/coreboot/cbmemc.c; + enable = x86; +}; + +module = { + name = regexp; + common = commands/regexp.c; + common = commands/wildcard.c; + common = lib/gnulib/regex.c; + cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; + cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; +}; + +module = { + name = acpi; + + common = commands/acpi.c; + i386_pc = kern/acpi.c; + i386_pc = kern/i386/pc/acpi.c; + + enable = efi; + enable = i386_pc; + enable = i386_coreboot; + enable = i386_multiboot; +}; + +module = { + name = lsacpi; + + common = commands/lsacpi.c; + + enable = efi; + enable = i386_pc; + enable = i386_coreboot; + enable = i386_multiboot; +}; + +module = { + name = lsefisystab; + + common = commands/efi/lsefisystab.c; + + enable = efi; +}; + +module = { + name = lssal; + + common = commands/efi/lssal.c; + + enable = efi; +}; + +module = { + name = lsefimmap; + + common = commands/efi/lsefimmap.c; + + enable = efi; +}; + +module = { + name = lsefi; + common = commands/efi/lsefi.c; + enable = efi; +}; + +module = { + name = efifwsetup; + efi = commands/efi/efifwsetup.c; + enable = efi; +}; + +module = { + name = blocklist; + common = commands/blocklist.c; +}; + +module = { + name = blscfg; + common = commands/blscfg.c; + common = commands/loadenv.h; + enable = powerpc_ieee1275; + enable = efi; + enable = i386_pc; + enable = emu; +}; + +module = { + name = boot; + common = commands/boot.c; + i386_pc = lib/i386/pc/biosnum.c; + enable = x86; + enable = emu; + enable = sparc64_ieee1275; + enable = powerpc_ieee1275; + enable = mips_arc; + enable = mips64_efi; + enable = ia64_efi; + enable = arm_efi; + enable = arm64_efi; + enable = arm_uboot; + enable = arm_coreboot; + enable = riscv32_efi; + enable = riscv64_efi; +}; + +module = { + name = cat; + common = commands/cat.c; +}; + +module = { + name = cmp; + common = commands/cmp.c; +}; + +module = { + name = configfile; + common = commands/configfile.c; +}; + +module = { + name = cpuid; + common = commands/i386/cpuid.c; + enable = x86; + enable = i386_xen_pvh; + enable = i386_xen; + enable = x86_64_xen; +}; + +module = { + name = date; + common = commands/date.c; +}; + +module = { + name = drivemap; + + i386_pc = commands/i386/pc/drivemap.c; + i386_pc = commands/i386/pc/drivemap_int13h.S; + enable = i386_pc; +}; + +module = { + name = echo; + common = commands/echo.c; +}; + +module = { + name = eval; + common = commands/eval.c; +}; + +module = { + name = extcmd; + common = commands/extcmd.c; + common = lib/arg.c; + enable = terminfomodule; +}; + +module = { + name = fixvideo; + common = commands/efi/fixvideo.c; + enable = i386_efi; + enable = x86_64_efi; +}; + +module = { + name = fwload; + efi = commands/efi/fwload.c; + enable = efi; +}; + +module = { + name = gptsync; + common = commands/gptsync.c; +}; + +module = { + name = halt; + nopc = commands/halt.c; + i386_pc = commands/i386/pc/halt.c; + i386_pc = commands/acpihalt.c; + i386_coreboot = commands/acpihalt.c; + i386_multiboot = commands/acpihalt.c; + i386_efi = commands/acpihalt.c; + x86_64_efi = commands/acpihalt.c; + i386_multiboot = lib/i386/halt.c; + i386_coreboot = lib/i386/halt.c; + i386_qemu = lib/i386/halt.c; + xen = lib/xen/halt.c; + i386_xen_pvh = lib/xen/halt.c; + efi = lib/efi/halt.c; + ieee1275 = lib/ieee1275/halt.c; + emu = lib/emu/halt.c; + uboot = lib/dummy/halt.c; + arm_coreboot = lib/dummy/halt.c; +}; + +module = { + name = reboot; + i386 = lib/i386/reboot.c; + i386 = lib/i386/reboot_trampoline.S; + powerpc_ieee1275 = lib/ieee1275/reboot.c; + sparc64_ieee1275 = lib/ieee1275/reboot.c; + mips_arc = lib/mips/arc/reboot.c; + mips_loongson = lib/mips/loongson/reboot.c; + mips_qemu_mips = lib/mips/qemu_mips/reboot.c; + xen = lib/xen/reboot.c; + i386_xen_pvh = lib/xen/reboot.c; + uboot = lib/uboot/reboot.c; + arm_coreboot = lib/dummy/reboot.c; + common = commands/reboot.c; +}; + +module = { + name = hashsum; + common = commands/hashsum.c; +}; + +module = { + name = pgp; + common = commands/pgp.c; + cflags = '$(CFLAGS_POSIX)'; + cppflags = '-I$(srcdir)/lib/posix_wrap'; +}; + +module = { + name = verifiers; + common = commands/verifiers.c; +}; + +module = { + name = shim_lock; + common = commands/efi/shim_lock.c; + enable = x86_64_efi; +}; + +module = { + name = hdparm; + common = commands/hdparm.c; + enable = pci; + enable = mips_qemu_mips; +}; + +module = { + name = help; + common = commands/help.c; +}; + +module = { + name = hexdump; + common = commands/hexdump.c; + common = lib/hexdump.c; +}; + +module = { + name = keystatus; + common = commands/keystatus.c; +}; + +module = { + name = loadbios; + common = commands/efi/loadbios.c; + enable = i386_efi; + enable = x86_64_efi; +}; + +module = { + name = loadenv; + common = commands/loadenv.c; + common = commands/loadenv.h; + common = lib/envblk.c; +}; + +module = { + name = ls; + common = commands/ls.c; +}; + +module = { + name = lsmmap; + common = commands/lsmmap.c; +}; + +module = { + name = lspci; + common = commands/lspci.c; + + enable = pci; +}; + +module = { + name = memrw; + common = commands/memrw.c; +}; + +module = { + name = minicmd; + common = commands/minicmd.c; +}; + +module = { + name = parttool; + common = commands/parttool.c; +}; + +module = { + name = password; + common = commands/password.c; +}; + +module = { + name = password_pbkdf2; + common = commands/password_pbkdf2.c; +}; + +module = { + name = play; + x86 = commands/i386/pc/play.c; + enable = x86; +}; + +module = { + name = spkmodem; + x86 = term/spkmodem.c; + enable = x86; +}; + +module = { + name = morse; + x86 = term/morse.c; + enable = x86; +}; + +module = { + name = probe; + common = commands/probe.c; +}; + +module = { + name = read; + common = commands/read.c; +}; + +module = { + name = search; + common = commands/search_wrap.c; + extra_dist = commands/search.c; +}; + +module = { + name = search_fs_file; + common = commands/search_file.c; +}; + +module = { + name = search_fs_uuid; + common = commands/search_uuid.c; +}; + +module = { + name = search_label; + common = commands/search_label.c; +}; + +module = { + name = setpci; + common = commands/setpci.c; + enable = pci; +}; + +module = { + name = pcidump; + common = commands/pcidump.c; + enable = pci; +}; + +module = { + name = sleep; + common = commands/sleep.c; +}; + +module = { + name = smbios; + + common = commands/smbios.c; + efi = commands/efi/smbios.c; + i386_pc = commands/i386/pc/smbios.c; + i386_coreboot = commands/i386/pc/smbios.c; + i386_multiboot = commands/i386/pc/smbios.c; + + enable = efi; + enable = i386_pc; + enable = i386_coreboot; + enable = i386_multiboot; +}; + +module = { + name = suspend; + ieee1275 = commands/ieee1275/suspend.c; + enable = i386_ieee1275; + enable = powerpc_ieee1275; +}; + +module = { + name = escc; + ieee1275 = term/ieee1275/escc.c; + enable = powerpc_ieee1275; +}; + +module = { + name = terminal; + common = commands/terminal.c; +}; + +module = { + name = test; + common = commands/test.c; +}; + +module = { + name = true; + common = commands/true.c; +}; + +module = { + name = usbtest; + common = commands/usbtest.c; + enable = usb; +}; + +module = { + name = videoinfo; + common = commands/videoinfo.c; +}; + +module = { + name = videotest; + common = commands/videotest.c; +}; + +module = { + name = xnu_uuid; + common = commands/xnu_uuid.c; +}; + +module = { + name = dm_nv; + common = disk/dmraid_nvidia.c; +}; + +module = { + name = loopback; + common = disk/loopback.c; +}; + +module = { + name = cryptodisk; + common = disk/cryptodisk.c; +}; + +module = { + name = luks; + common = disk/luks.c; + common = disk/AFSplitter.c; +}; + +module = { + name = geli; + common = disk/geli.c; +}; + +module = { + name = lvm; + common = disk/lvm.c; +}; + +module = { + name = ldm; + common = disk/ldm.c; +}; + +module = { + name = mdraid09; + common = disk/mdraid_linux.c; +}; + +module = { + name = mdraid09_be; + common = disk/mdraid_linux_be.c; +}; + +module = { + name = mdraid1x; + common = disk/mdraid1x_linux.c; +}; + +module = { + name = diskfilter; + common = disk/diskfilter.c; +}; + +module = { + name = raid5rec; + common = disk/raid5_recover.c; +}; + +module = { + name = raid6rec; + common = disk/raid6_recover.c; +}; + +module = { + name = scsi; + common = disk/scsi.c; +}; + +module = { + name = memdisk; + common = disk/memdisk.c; +}; + +module = { + name = ata; + common = disk/ata.c; + enable = pci; + enable = mips_qemu_mips; +}; + +module = { + name = ahci; + common = disk/ahci.c; + enable = pci; +}; + +module = { + name = pata; + common = disk/pata.c; + enable = pci; + enable = mips_qemu_mips; +}; + +module = { + name = biosdisk; + i386_pc = disk/i386/pc/biosdisk.c; + enable = i386_pc; +}; + +module = { + name = usbms; + common = disk/usbms.c; + enable = usb; +}; + +module = { + name = nand; + ieee1275 = disk/ieee1275/nand.c; + enable = i386_ieee1275; +}; + +module = { + name = efiemu; + common = efiemu/main.c; + common = efiemu/i386/loadcore32.c; + common = efiemu/i386/loadcore64.c; + i386_pc = efiemu/i386/pc/cfgtables.c; + i386_coreboot = efiemu/i386/pc/cfgtables.c; + i386_multiboot = efiemu/i386/pc/cfgtables.c; + i386_ieee1275 = efiemu/i386/nocfgtables.c; + i386_qemu = efiemu/i386/nocfgtables.c; + common = efiemu/mm.c; + common = efiemu/loadcore_common.c; + common = efiemu/symbols.c; + common = efiemu/loadcore32.c; + common = efiemu/loadcore64.c; + common = efiemu/prepare32.c; + common = efiemu/prepare64.c; + common = efiemu/pnvram.c; + common = efiemu/i386/coredetect.c; + + extra_dist = efiemu/prepare.c; + extra_dist = efiemu/loadcore.c; + extra_dist = efiemu/runtime/efiemu.S; + extra_dist = efiemu/runtime/efiemu.c; + + enable = i386_pc; + enable = i386_coreboot; + enable = i386_ieee1275; + enable = i386_multiboot; + enable = i386_qemu; +}; + +module = { + name = font; + common = font/font.c; + common = font/font_cmd.c; + enable = videomodules; +}; + +module = { + name = procfs; + common = fs/proc.c; +}; + +module = { + name = affs; + common = fs/affs.c; +}; + +module = { + name = afs; + common = fs/afs.c; +}; + +module = { + name = bfs; + common = fs/bfs.c; +}; + +module = { + name = zstd; + common = lib/zstd/debug.c; + common = lib/zstd/entropy_common.c; + common = lib/zstd/error_private.c; + common = lib/zstd/fse_decompress.c; + common = lib/zstd/huf_decompress.c; + common = lib/zstd/module.c; + common = lib/zstd/xxhash.c; + common = lib/zstd/zstd_common.c; + common = lib/zstd/zstd_decompress.c; + cflags = '$(CFLAGS_POSIX) -Wno-undef'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/zstd'; +}; + +module = { + name = btrfs; + common = fs/btrfs.c; + common = lib/crc.c; + cflags = '$(CFLAGS_POSIX) -Wno-undef'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -I$(srcdir)/lib/zstd -DMINILZO_HAVE_CONFIG_H'; +}; + +module = { + name = archelp; + common = fs/archelp.c; +}; + +module = { + name = cbfs; + common = fs/cbfs.c; +}; + +module = { + name = cpio; + common = fs/cpio.c; +}; + +module = { + name = cpio_be; + common = fs/cpio_be.c; +}; + +module = { + name = newc; + common = fs/newc.c; +}; + +module = { + name = odc; + common = fs/odc.c; +}; + +module = { + name = ext2; + common = fs/ext2.c; +}; + +module = { + name = fat; + common = fs/fat.c; +}; + +module = { + name = exfat; + common = fs/exfat.c; +}; + +module = { + name = f2fs; + common = fs/f2fs.c; +}; + +module = { + name = fshelp; + common = fs/fshelp.c; +}; + +module = { + name = hfs; + common = fs/hfs.c; +}; + +module = { + name = hfsplus; + common = fs/hfsplus.c; +}; + +module = { + name = hfspluscomp; + common = fs/hfspluscomp.c; +}; + +module = { + name = iso9660; + common = fs/iso9660.c; +}; + +module = { + name = jfs; + common = fs/jfs.c; +}; + +module = { + name = minix; + common = fs/minix.c; +}; + +module = { + name = minix2; + common = fs/minix2.c; +}; + +module = { + name = minix3; + common = fs/minix3.c; +}; + +module = { + name = minix_be; + common = fs/minix_be.c; +}; + +module = { + name = minix2_be; + common = fs/minix2_be.c; +}; + +module = { + name = minix3_be; + common = fs/minix3_be.c; +}; + +module = { + name = nilfs2; + common = fs/nilfs2.c; +}; + +module = { + name = ntfs; + common = fs/ntfs.c; +}; + +module = { + name = ntfscomp; + common = fs/ntfscomp.c; +}; + +module = { + name = reiserfs; + common = fs/reiserfs.c; +}; + +module = { + name = romfs; + common = fs/romfs.c; +}; + +module = { + name = sfs; + common = fs/sfs.c; +}; + +module = { + name = squash4; + common = fs/squash4.c; + cflags = '$(CFLAGS_POSIX) -Wno-undef'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed -I$(srcdir)/lib/minilzo -I$(srcdir)/lib/zstd -DMINILZO_HAVE_CONFIG_H'; +}; + +module = { + name = tar; + common = fs/tar.c; +}; + +module = { + name = udf; + common = fs/udf.c; +}; + +module = { + name = ufs1; + common = fs/ufs.c; +}; + +module = { + name = ufs1_be; + common = fs/ufs_be.c; +}; + +module = { + name = ufs2; + common = fs/ufs2.c; +}; + +module = { + name = xfs; + common = fs/xfs.c; +}; + +module = { + name = zfs; + common = fs/zfs/zfs.c; + common = fs/zfs/zfs_lzjb.c; + common = fs/zfs/zfs_lz4.c; + common = fs/zfs/zfs_sha256.c; + common = fs/zfs/zfs_fletcher.c; +}; + +module = { + name = zfscrypt; + common = fs/zfs/zfscrypt.c; +}; + +module = { + name = zfsinfo; + common = fs/zfs/zfsinfo.c; +}; + +module = { + name = macbless; + common = commands/macbless.c; +}; + +module = { + name = pxe; + i386_pc = net/drivers/i386/pc/pxe.c; + enable = i386_pc; +}; + +module = { + name = gettext; + common = gettext/gettext.c; +}; + +module = { + name = gfxmenu; + common = gfxmenu/gfxmenu.c; + common = gfxmenu/view.c; + common = gfxmenu/font.c; + common = gfxmenu/icon_manager.c; + common = gfxmenu/theme_loader.c; + common = gfxmenu/widget-box.c; + common = gfxmenu/gui_canvas.c; + common = gfxmenu/gui_circular_progress.c; + common = gfxmenu/gui_box.c; + common = gfxmenu/gui_label.c; + common = gfxmenu/gui_list.c; + common = gfxmenu/gui_image.c; + common = gfxmenu/gui_progress_bar.c; + common = gfxmenu/gui_util.c; + common = gfxmenu/gui_string_util.c; +}; + +/* Added by longpanda for Ventoy Project */ +module = { + name = ventoy; + common = ventoy/ventoy.c; + common = ventoy/ventoy_cmd.c; + common = ventoy/ventoy_linux.c; + common = ventoy/ventoy_unix.c; + common = ventoy/ventoy_windows.c; + common = ventoy/ventoy_vhd.c; + common = ventoy/ventoy_plugin.c; + common = ventoy/ventoy_json.c; + common = ventoy/ventoy_browser.c; + common = ventoy/lzx.c; + common = ventoy/xpress.c; + common = ventoy/huffman.c; + common = ventoy/miniz.c; +}; + +module = { + name = setkey; + common = term/setkey.c; +}; + +module = { + name = mouse; + efi = term/efi/mouse.c; + enable = efi; +}; + +module = { + name = hello; + common = hello/hello.c; +}; + +module = { + name = gzio; + common = io/gzio.c; +}; + +module = { + name = offsetio; + common = io/offset.c; +}; + +module = { + name = bufio; + common = io/bufio.c; + enable = videomodules; +}; + +module = { + name = elf; + common = kern/elf.c; + + extra_dist = kern/elfXX.c; +}; + +module = { + name = crypto; + common = lib/crypto.c; + + extra_dist = lib/libgcrypt-grub/cipher/crypto.lst; +}; + +module = { + name = pbkdf2; + common = lib/pbkdf2.c; +}; + +module = { + name = relocator; + common = lib/relocator.c; + x86 = lib/i386/relocator16.S; + x86 = lib/i386/relocator32.S; + x86 = lib/i386/relocator64.S; + i386_xen_pvh = lib/i386/relocator16.S; + i386_xen_pvh = lib/i386/relocator32.S; + i386_xen_pvh = lib/i386/relocator64.S; + i386 = lib/i386/relocator_asm.S; + i386_xen_pvh = lib/i386/relocator_asm.S; + x86_64 = lib/x86_64/relocator_asm.S; + i386_xen = lib/i386/relocator_asm.S; + x86_64_xen = lib/x86_64/relocator_asm.S; + x86 = lib/i386/relocator.c; + x86 = lib/i386/relocator_common_c.c; + i386_xen_pvh = lib/i386/relocator.c; + i386_xen_pvh = lib/i386/relocator_common_c.c; + ieee1275 = lib/ieee1275/relocator.c; + efi = lib/efi/relocator.c; + mips = lib/mips/relocator_asm.S; + mips = lib/mips/relocator.c; + mips64 = lib/mips64/relocator_asm.S; + mips64 = lib/mips64/relocator.c; + powerpc = lib/powerpc/relocator_asm.S; + powerpc = lib/powerpc/relocator.c; + xen = lib/xen/relocator.c; + i386_xen = lib/i386/xen/relocator.S; + x86_64_xen = lib/x86_64/xen/relocator.S; + xen = lib/i386/relocator_common_c.c; + x86_64_efi = lib/x86_64/efi/relocator.c; + + extra_dist = lib/i386/relocator_common.S; + extra_dist = kern/powerpc/cache_flush.S; + + enable = mips; + enable = mips64; + enable = powerpc; + enable = x86; + enable = i386_xen_pvh; + enable = xen; +}; + +module = { + name = datetime; + cmos = lib/cmos_datetime.c; + efi = lib/efi/datetime.c; + uboot = lib/dummy/datetime.c; + arm_coreboot = lib/dummy/datetime.c; + sparc64_ieee1275 = lib/ieee1275/datetime.c; + powerpc_ieee1275 = lib/ieee1275/datetime.c; + sparc64_ieee1275 = lib/ieee1275/cmos.c; + powerpc_ieee1275 = lib/ieee1275/cmos.c; + xen = lib/xen/datetime.c; + i386_xen_pvh = lib/xen/datetime.c; + + mips_arc = lib/arc/datetime.c; + enable = noemu; +}; + +module = { + name = setjmp; + common = lib/setjmp.S; + extra_dist = lib/i386/setjmp.S; + extra_dist = lib/mips/setjmp.S; + extra_dist = lib/x86_64/setjmp.S; + extra_dist = lib/sparc64/setjmp.S; + extra_dist = lib/powerpc/setjmp.S; + extra_dist = lib/ia64/setjmp.S; + extra_dist = lib/ia64/longjmp.S; + extra_dist = lib/arm/setjmp.S; + extra_dist = lib/arm64/setjmp.S; + extra_dist = lib/riscv/setjmp.S; +}; + +module = { + name = aout; + common = loader/aout.c; + enable = x86; +}; + +module = { + name = bsd; + x86 = loader/i386/bsd.c; + x86 = loader/i386/bsd32.c; + x86 = loader/i386/bsd64.c; + + extra_dist = loader/i386/bsdXX.c; + extra_dist = loader/i386/bsd_pagetable.c; + + enable = x86; +}; + +module = { + name = plan9; + i386_pc = loader/i386/pc/plan9.c; + enable = i386_pc; +}; + + +module = { + name = linux16; + common = loader/i386/pc/linux.c; + enable = x86; +}; + +module = { + name = ntldr; + i386_pc = loader/i386/pc/ntldr.c; + enable = i386_pc; +}; + + +module = { + name = truecrypt; + i386_pc = loader/i386/pc/truecrypt.c; + enable = i386_pc; +}; + + +module = { + name = freedos; + i386_pc = loader/i386/pc/freedos.c; + enable = i386_pc; +}; + +module = { + name = pxechain; + i386_pc = loader/i386/pc/pxechainloader.c; + enable = i386_pc; +}; + +module = { + name = multiboot2; + cppflags = "-DGRUB_USE_MULTIBOOT2"; + + common = loader/multiboot.c; + common = loader/multiboot_mbi2.c; + enable = x86; + enable = i386_xen_pvh; + enable = mips; +}; + +module = { + name = multiboot; + common = loader/multiboot.c; + x86 = loader/i386/multiboot_mbi.c; + i386_xen_pvh = loader/i386/multiboot_mbi.c; + extra_dist = loader/multiboot_elfxx.c; + enable = x86; + enable = i386_xen_pvh; +}; + +module = { + name = xen_boot; + arm64 = loader/arm64/xen_boot.c; + enable = arm64; +}; + +module = { + name = linux; + x86 = loader/i386/linux.c; + i386_xen_pvh = loader/i386/linux.c; + xen = loader/i386/xen.c; + i386_pc = lib/i386/pc/vesa_modes_table.c; + i386_xen_pvh = lib/i386/pc/vesa_modes_table.c; + mips = loader/mips/linux.c; + mips64 = loader/mips64/linux.c; + powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; + sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; + ia64_efi = loader/ia64/efi/linux.c; + arm_coreboot = loader/arm/linux.c; + arm_efi = loader/arm64/linux.c; + arm_uboot = loader/arm/linux.c; + arm64 = loader/arm64/linux.c; + riscv32 = loader/riscv/linux.c; + riscv64 = loader/riscv/linux.c; + common = loader/linux.c; + common = lib/cmdline.c; + enable = noemu; +}; + +module = { + name = fdt; + efi = loader/efi/fdt.c; + common = lib/fdt.c; + enable = fdt; +}; + +module = { + name = xnu; + x86 = loader/xnu_resume.c; + x86 = loader/i386/xnu.c; + x86 = loader/xnu.c; + + /* Code is pretty generic but relies on RNG which + is available only on few platforms. It's not a + big deal as xnu needs ACPI anyway and we have + RNG on all platforms with ACPI. + */ + enable = i386_multiboot; + enable = i386_coreboot; + enable = i386_pc; + enable = i386_efi; + enable = x86_64_efi; +}; + +module = { + name = random; + x86 = lib/i386/random.c; + common = lib/random.c; + + i386_multiboot = kern/i386/tsc_pmtimer.c; + i386_coreboot = kern/i386/tsc_pmtimer.c; + i386_pc = kern/i386/tsc_pmtimer.c; + + enable = i386_multiboot; + enable = i386_coreboot; + enable = i386_pc; + enable = i386_efi; + enable = x86_64_efi; +}; + +module = { + name = macho; + + common = loader/macho.c; + common = loader/macho32.c; + common = loader/macho64.c; + common = loader/lzss.c; + extra_dist = loader/machoXX.c; +}; + +module = { + name = appleldr; + common = loader/efi/appleloader.c; + enable = i386_efi; + enable = x86_64_efi; +}; + +module = { + name = chain; + efi = loader/efi/chainloader.c; + i386_pc = loader/i386/pc/chainloader.c; + i386_coreboot = loader/i386/coreboot/chainloader.c; + i386_coreboot = lib/LzmaDec.c; + enable = i386_pc; + enable = i386_coreboot; + enable = efi; +}; + +module = { + name = mmap; + common = mmap/mmap.c; + x86 = mmap/i386/uppermem.c; + x86 = mmap/i386/mmap.c; + i386_xen_pvh = mmap/i386/uppermem.c; + i386_xen_pvh = mmap/i386/mmap.c; + + i386_pc = mmap/i386/pc/mmap.c; + i386_pc = mmap/i386/pc/mmap_helper.S; + + efi = mmap/efi/mmap.c; + + mips = mmap/mips/uppermem.c; + + enable = x86; + enable = i386_xen_pvh; + enable = ia64_efi; + enable = arm_efi; + enable = arm64_efi; + enable = riscv32_efi; + enable = riscv64_efi; + enable = mips; + enable = mips64_efi; +}; + +module = { + name = normal; + common = normal/main.c; + common = normal/cmdline.c; + common = normal/dyncmd.c; + common = normal/auth.c; + common = normal/autofs.c; + common = normal/color.c; + common = normal/completion.c; + common = normal/datetime.c; + common = normal/menu.c; + common = normal/menu_entry.c; + common = normal/menu_text.c; + common = normal/misc.c; + common = normal/crypto.c; + common = normal/term.c; + common = normal/context.c; + common = normal/charset.c; + common = lib/getline.c; + + common = script/main.c; + common = script/script.c; + common = script/execute.c; + common = script/function.c; + common = script/lexer.c; + common = script/argv.c; + + common = commands/menuentry.c; + + common = unidata.c; + common_nodist = grub_script.tab.c; + common_nodist = grub_script.yy.c; + common_nodist = grub_script.tab.h; + common_nodist = grub_script.yy.h; + + extra_dist = script/yylex.l; + extra_dist = script/parser.y; + + cflags = '$(CFLAGS_POSIX) -Wno-redundant-decls'; + cppflags = '$(CPPFLAGS_POSIX)'; +}; + +module = { + name = part_acorn; + common = partmap/acorn.c; +}; + +module = { + name = part_amiga; + common = partmap/amiga.c; +}; + +module = { + name = part_apple; + common = partmap/apple.c; +}; + +module = { + name = part_gpt; + common = partmap/gpt.c; +}; + +module = { + name = part_msdos; + common = partmap/msdos.c; +}; + +module = { + name = part_sun; + common = partmap/sun.c; +}; + +module = { + name = part_plan; + common = partmap/plan.c; +}; + +module = { + name = part_dvh; + common = partmap/dvh.c; +}; + +module = { + name = part_bsd; + common = partmap/bsdlabel.c; +}; + +module = { + name = part_sunpc; + common = partmap/sunpc.c; +}; + +module = { + name = part_dfly; + common = partmap/dfly.c; +}; + +module = { + name = msdospart; + common = parttool/msdospart.c; +}; + +module = { + name = at_keyboard; + common = term/at_keyboard.c; + common = term/ps2.c; + enable = x86; +}; + +module = { + name = gfxterm; + common = term/gfxterm.c; + enable = videomodules; +}; + +module = { + name = gfxterm_background; + common = term/gfxterm_background.c; +}; + +module = { + name = serial; + common = term/serial.c; + x86 = term/ns8250.c; + ieee1275 = term/ieee1275/serial.c; + mips_arc = term/arc/serial.c; + efi = term/efi/serial.c; + + enable = terminfomodule; + enable = ieee1275; + enable = mips_arc; +}; + +module = { + name = sendkey; + i386_pc = commands/i386/pc/sendkey.c; + enable = i386_pc; +}; + +module = { + name = terminfo; + common = term/terminfo.c; + common = term/tparm.c; + enable = terminfomodule; +}; + +module = { + name = usb_keyboard; + common = term/usb_keyboard.c; + enable = usb; +}; + +module = { + name = vga; + common = video/i386/pc/vga.c; + enable = i386_pc; +}; + +module = { + name = vga_text; + common = term/i386/pc/vga_text.c; + enable = i386_pc; +}; + +module = { + name = mda_text; + common = term/i386/pc/mda_text.c; + enable = i386_pc; + enable = i386_coreboot_multiboot_qemu; +}; + +module = { + name = video_cirrus; + x86 = video/cirrus.c; + enable = x86; +}; + +module = { + name = video_bochs; + x86 = video/bochs.c; + enable = x86; +}; + +module = { + name = functional_test; + common = tests/lib/functional_test.c; + common = tests/lib/test.c; + common = tests/checksums.h; + common = tests/video_checksum.c; + common = tests/fake_input.c; + common = video/capture.c; +}; + +module = { + name = exfctest; + common = tests/example_functional_test.c; +}; + +module = { + name = strtoull_test; + common = tests/strtoull_test.c; +}; + +module = { + name = setjmp_test; + common = tests/setjmp_test.c; +}; + +module = { + name = signature_test; + common = tests/signature_test.c; + common = tests/signatures.h; +}; + +module = { + name = sleep_test; + common = tests/sleep_test.c; +}; + +module = { + name = xnu_uuid_test; + common = tests/xnu_uuid_test.c; +}; + +module = { + name = pbkdf2_test; + common = tests/pbkdf2_test.c; +}; + +module = { + name = legacy_password_test; + common = tests/legacy_password_test.c; + enable = i386_pc; + enable = i386_xen_pvh; + enable = i386_efi; + enable = x86_64_efi; + enable = emu; + enable = xen; +}; + +module = { + name = div; + common = lib/division.c; + enable = no_softdiv; +}; + +module = { + name = div_test; + common = tests/div_test.c; +}; + +module = { + name = mul_test; + common = tests/mul_test.c; +}; + +module = { + name = shift_test; + common = tests/shift_test.c; +}; + +module = { + name = cmp_test; + common = tests/cmp_test.c; +}; + +module = { + name = ctz_test; + common = tests/ctz_test.c; +}; + +module = { + name = bswap_test; + common = tests/bswap_test.c; +}; + +module = { + name = videotest_checksum; + common = tests/videotest_checksum.c; +}; + +module = { + name = gfxterm_menu; + common = tests/gfxterm_menu.c; +}; + +module = { + name = cmdline_cat_test; + common = tests/cmdline_cat_test.c; +}; + +module = { + name = bitmap; + common = video/bitmap.c; +}; + +module = { + name = bitmap_scale; + common = video/bitmap_scale.c; +}; + +module = { + name = efi_gop; + efi = video/efi_gop.c; + enable = efi; +}; + +module = { + name = efi_uga; + efi = video/efi_uga.c; + enable = i386_efi; + enable = x86_64_efi; +}; + +module = { + name = jpeg; + common = video/readers/jpeg.c; +}; + +module = { + name = png; + common = video/readers/png.c; +}; + +module = { + name = tga; + common = video/readers/tga.c; +}; + +module = { + name = vbe; + common = video/i386/pc/vbe.c; + enable = i386_pc; +}; + +module = { + name = video_fb; + common = video/fb/video_fb.c; + common = video/fb/fbblit.c; + common = video/fb/fbfill.c; + common = video/fb/fbutil.c; + enable = videomodules; +}; + +module = { + name = video; + common = video/video.c; + enable = videomodules; +}; + +module = { + name = video_colors; + common = video/colors.c; +}; + +module = { + name = ieee1275_fb; + ieee1275 = video/ieee1275.c; + enable = powerpc_ieee1275; +}; + +module = { + name = sdl; + emu = video/emu/sdl.c; + enable = emu; + condition = COND_GRUB_EMU_SDL; +}; + +module = { + name = datehook; + common = hook/datehook.c; +}; + +module = { + name = net; + common = net/net.c; + common = net/dns.c; + common = net/bootp.c; + common = net/ip.c; + common = net/udp.c; + common = net/tcp.c; + common = net/icmp.c; + common = net/icmp6.c; + common = net/ethernet.c; + common = net/arp.c; + common = net/netbuff.c; +}; + +module = { + name = tftp; + common = net/tftp.c; +}; + +module = { + name = http; + common = net/http.c; +}; + +module = { + name = ofnet; + common = net/drivers/ieee1275/ofnet.c; + enable = ieee1275; +}; + +module = { + name = ubootnet; + common = net/drivers/uboot/ubootnet.c; + enable = uboot; +}; + +module = { + name = efinet; + common = net/drivers/efi/efinet.c; + enable = efi; +}; + +module = { + name = emunet; + emu = net/drivers/emu/emunet.c; + enable = emu; +}; + +module = { + name = legacycfg; + common = commands/legacycfg.c; + common = lib/legacy_parse.c; + emu = lib/i386/pc/vesa_modes_table.c; + i386_efi = lib/i386/pc/vesa_modes_table.c; + x86_64_efi = lib/i386/pc/vesa_modes_table.c; + xen = lib/i386/pc/vesa_modes_table.c; + + enable = i386_pc; + enable = i386_xen_pvh; + enable = i386_efi; + enable = x86_64_efi; + enable = emu; + enable = xen; +}; + +module = { + name = syslinuxcfg; + common = lib/syslinux_parse.c; + common = commands/syslinuxcfg.c; +}; + +module = { + name = test_blockarg; + common = tests/test_blockarg.c; +}; + +module = { + name = xzio; + common = io/xzio.c; + common = lib/xzembed/xz_dec_bcj.c; + common = lib/xzembed/xz_dec_lzma2.c; + common = lib/xzembed/xz_dec_stream.c; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed'; + cflags='-Wno-unreachable-code'; +}; + +module = { + name = lzopio; + common = io/lzopio.c; + common = lib/minilzo/minilzo.c; + cflags = '$(CFLAGS_POSIX) -Wno-undef -Wno-redundant-decls -Wno-error'; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H'; +}; + +module = { + name = testload; + common = commands/testload.c; +}; + +module = { + name = backtrace; + x86 = lib/i386/backtrace.c; + i386_xen_pvh = lib/i386/backtrace.c; + i386_xen = lib/i386/backtrace.c; + x86_64_xen = lib/i386/backtrace.c; + common = lib/backtrace.c; + enable = x86; + enable = i386_xen_pvh; + enable = i386_xen; + enable = x86_64_xen; +}; + +module = { + name = lsapm; + common = commands/i386/pc/lsapm.c; + enable = i386_pc; +}; + +module = { + name = keylayouts; + common = commands/keylayouts.c; + enable = x86; +}; + +module = { + name = priority_queue; + common = lib/priority_queue.c; +}; + +module = { + name = time; + common = commands/time.c; +}; + +module = { + name = cacheinfo; + common = commands/cacheinfo.c; + condition = COND_ENABLE_CACHE_STATS; +}; + +module = { + name = boottime; + common = commands/boottime.c; + condition = COND_ENABLE_BOOT_TIME_STATS; +}; + +module = { + name = adler32; + common = lib/adler32.c; +}; + +module = { + name = crc64; + common = lib/crc64.c; +}; + +module = { + name = mpi; + common = lib/libgcrypt-grub/mpi/mpiutil.c; + common = lib/libgcrypt-grub/mpi/mpi-bit.c; + common = lib/libgcrypt-grub/mpi/mpi-add.c; + common = lib/libgcrypt-grub/mpi/mpi-mul.c; + common = lib/libgcrypt-grub/mpi/mpi-mod.c; + common = lib/libgcrypt-grub/mpi/mpi-gcd.c; + common = lib/libgcrypt-grub/mpi/mpi-div.c; + common = lib/libgcrypt-grub/mpi/mpi-cmp.c; + common = lib/libgcrypt-grub/mpi/mpi-inv.c; + common = lib/libgcrypt-grub/mpi/mpi-pow.c; + common = lib/libgcrypt-grub/mpi/mpi-mpow.c; + common = lib/libgcrypt-grub/mpi/mpih-lshift.c; + common = lib/libgcrypt-grub/mpi/mpih-mul.c; + common = lib/libgcrypt-grub/mpi/mpih-mul1.c; + common = lib/libgcrypt-grub/mpi/mpih-mul2.c; + common = lib/libgcrypt-grub/mpi/mpih-mul3.c; + common = lib/libgcrypt-grub/mpi/mpih-add1.c; + common = lib/libgcrypt-grub/mpi/mpih-sub1.c; + common = lib/libgcrypt-grub/mpi/mpih-div.c; + common = lib/libgcrypt-grub/mpi/mpicoder.c; + common = lib/libgcrypt-grub/mpi/mpih-rshift.c; + common = lib/libgcrypt-grub/mpi/mpi-inline.c; + common = lib/libgcrypt_wrap/mem.c; + + cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare'; + cppflags = '$(CPPFLAGS_GCRY)'; +}; + +module = { + name = all_video; + common = lib/fake_module.c; +}; + +module = { + name = gdb; + common = gdb/cstub.c; + common = gdb/gdb.c; + i386 = gdb/i386/idt.c; + i386 = gdb/i386/machdep.S; + i386 = gdb/i386/signal.c; + enable = i386; +}; + +module = { + name = testspeed; + common = commands/testspeed.c; +}; + +module = { + name = tpm; + common = commands/tpm.c; + efi = commands/efi/tpm.c; + enable = x86_64_efi; +}; + +module = { + name = tr; + common = commands/tr.c; +}; + +module = { + name = progress; + common = lib/progress.c; +}; + +module = { + name = file; + common = commands/file.c; + common = commands/file32.c; + common = commands/file64.c; + extra_dist = commands/fileXX.c; + common = loader/i386/xen_file.c; + common = loader/i386/xen_file32.c; + common = loader/i386/xen_file64.c; + extra_dist = loader/i386/xen_fileXX.c; +}; +module = { + name = rdmsr; + common = commands/i386/rdmsr.c; + enable = x86; +}; +module = { + name = wrmsr; + common = commands/i386/wrmsr.c; + enable = x86; +}; diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/boot/i386/pc/boot.S b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/boot/i386/pc/boot.S new file mode 100644 index 0000000..1445c41 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/boot/i386/pc/boot.S @@ -0,0 +1,545 @@ +/* -*-Asm-*- */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +/* + * defines for the code go here + */ + + /* Print message string */ +#define MSG(x) movw $x, %si; call LOCAL(message) +#define ERR(x) movw $x, %si; jmp LOCAL(error_message) + + .macro floppy +part_start: + +LOCAL(probe_values): + .byte 36, 18, 15, 9, 0 + +LOCAL(floppy_probe): + pushw %dx +/* + * Perform floppy probe. + */ +#ifdef __APPLE__ + LOCAL(probe_values_minus_one) = LOCAL(probe_values) - 1 + movw MACRO_DOLLAR(LOCAL(probe_values_minus_one)), %si +#else + movw MACRO_DOLLAR(LOCAL(probe_values)) - 1, %si +#endif + +LOCAL(probe_loop): + /* reset floppy controller INT 13h AH=0 */ + xorw %ax, %ax + int MACRO_DOLLAR(0x13) + + incw %si + movb (%si), %cl + + /* if number of sectors is 0, display error and die */ + testb %cl, %cl + jnz 1f + +/* + * Floppy disk probe failure. + */ + MSG(fd_probe_error_string) + jmp LOCAL(general_error) + +/* "Floppy" */ +fd_probe_error_string: .asciz "Floppy" + +1: + /* perform read */ + movw MACRO_DOLLAR(GRUB_BOOT_MACHINE_BUFFER_SEG), %bx + movw %bx, %es + xorw %bx, %bx + movw MACRO_DOLLAR(0x201), %ax + movb MACRO_DOLLAR(0), %ch + movb MACRO_DOLLAR(0), %dh + int MACRO_DOLLAR(0x13) + + /* if error, jump to "LOCAL(probe_loop)" */ + jc LOCAL(probe_loop) + + /* %cl is already the correct value! */ + movb MACRO_DOLLAR(1), %dh + movb MACRO_DOLLAR(79), %ch + + jmp LOCAL(final_init) + .endm + + .macro scratch + + /* scratch space */ +mode: + .byte 0 +disk_address_packet: +sectors: + .long 0 +heads: + .long 0 +cylinders: + .word 0 +sector_start: + .byte 0 +head_start: + .byte 0 +cylinder_start: + .word 0 + /* more space... */ + .endm + + .file "boot.S" + + .text + + /* Tell GAS to generate 16-bit instructions so that this code works + in real mode. */ + .code16 + +.globl _start, start; +_start: +start: + /* + * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00 + */ + + /* + * Beginning of the sector is compatible with the FAT/HPFS BIOS + * parameter block. + */ + + jmp LOCAL(after_BPB) + nop /* do I care about this ??? */ + +#ifdef HYBRID_BOOT + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + nop + nop + nop + + nop + nop + jmp LOCAL(after_BPB) +#else + /* + * This space is for the BIOS parameter block!!!! Don't change + * the first jump, nor start the code anywhere but right after + * this area. + */ + + .org GRUB_BOOT_MACHINE_BPB_START + .org 4 +#endif +#ifdef HYBRID_BOOT + floppy +#else + scratch +#endif + + .org GRUB_BOOT_MACHINE_BPB_END + /* + * End of BIOS parameter block. + */ + +LOCAL(kernel_address): + .word GRUB_BOOT_MACHINE_KERNEL_ADDR + +#ifndef HYBRID_BOOT + .org GRUB_BOOT_MACHINE_KERNEL_SECTOR +LOCAL(kernel_sector): + .long 1 +LOCAL(kernel_sector_high): + .long 0 +#endif + + .org GRUB_BOOT_MACHINE_BOOT_DRIVE +boot_drive: + .byte 0xff /* the disk to load kernel from */ + /* 0xff means use the boot drive */ + +LOCAL(after_BPB): + +/* general setup */ + cli /* we're not safe here! */ + + /* + * This is a workaround for buggy BIOSes which don't pass boot + * drive correctly. If GRUB is installed into a HDD, check if + * DL is masked correctly. If not, assume that the BIOS passed + * a bogus value and set DL to 0x80, since this is the only + * possible boot drive. If GRUB is installed into a floppy, + * this does nothing (only jump). + */ + .org GRUB_BOOT_MACHINE_DRIVE_CHECK +boot_drive_check: + jmp 3f /* grub-setup may overwrite this jump */ + testb $0x80, %dl + jz 2f +3: + /* Ignore %dl different from 0-0x0f and 0x80-0x8f. */ + testb $0x70, %dl + jz 1f +2: + movb $0x80, %dl +1: + /* + * ljmp to the next instruction because some bogus BIOSes + * jump to 07C0:0000 instead of 0000:7C00. + */ + ljmp $0, $real_start + +real_start: + + /* set up %ds and %ss as offset from 0 */ + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + + /* set up the REAL stack */ + movw $GRUB_BOOT_MACHINE_STACK_SEG, %sp + + sti /* we're safe again */ + + /* + * Check if we have a forced disk reference here + */ + movb boot_drive, %al + cmpb $0xff, %al + je 1f + movb %al, %dl +1: + /* save drive reference first thing! */ + pushw %dx + + /* print a notification message on the screen */ + MSG(notification_string) + + /* set %si to the disk address packet */ + movw $disk_address_packet, %si + + /* check if LBA is supported */ + movb $0x41, %ah + movw $0x55aa, %bx + int $0x13 + + /* + * %dl may have been clobbered by INT 13, AH=41H. + * This happens, for example, with AST BIOS 1.04. + */ + popw %dx + pushw %dx + + /* use CHS if fails */ + jc LOCAL(chs_mode) + cmpw $0xaa55, %bx + jne LOCAL(chs_mode) + + andw $1, %cx + jz LOCAL(chs_mode) + +LOCAL(lba_mode): + xorw %ax, %ax + movw %ax, 4(%si) + + incw %ax + /* set the mode to non-zero */ + movb %al, -1(%si) + + /* the blocks */ + movw %ax, 2(%si) + + /* the size and the reserved byte */ + movw $0x0010, (%si) + + /* the absolute address */ + movl LOCAL(kernel_sector), %ebx + movl %ebx, 8(%si) + movl LOCAL(kernel_sector_high), %ebx + movl %ebx, 12(%si) + + /* the segment of buffer address */ + movw $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si) + +/* + * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory + * Call with %ah = 0x42 + * %dl = drive number + * %ds:%si = segment:offset of disk address packet + * Return: + * %al = 0x0 on success; err code on failure + */ + + movb $0x42, %ah + int $0x13 + + /* LBA read is not supported, so fallback to CHS. */ + jc LOCAL(chs_mode) + + movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx + jmp LOCAL(copy_buffer) + +LOCAL(chs_mode): + /* + * Determine the hard disk geometry from the BIOS! + * We do this first, so that LS-120 IDE floppies work correctly. + */ + movb $8, %ah + int $0x13 + jnc LOCAL(final_init) + + popw %dx + /* + * The call failed, so maybe use the floppy probe instead. + */ + testb %dl, %dl + jnb LOCAL(floppy_probe) + + /* Nope, we definitely have a hard disk, and we're screwed. */ + ERR(hd_probe_error_string) + +LOCAL(final_init): + /* set the mode to zero */ + movzbl %dh, %eax + movb %ah, -1(%si) + + /* save number of heads */ + incw %ax + movl %eax, 4(%si) + + movzbw %cl, %dx + shlw $2, %dx + movb %ch, %al + movb %dh, %ah + + /* save number of cylinders */ + incw %ax + movw %ax, 8(%si) + + movzbw %dl, %ax + shrb $2, %al + + /* save number of sectors */ + movl %eax, (%si) + +setup_sectors: + /* load logical sector start (top half) */ + movl LOCAL(kernel_sector_high), %eax + + orl %eax, %eax + jnz LOCAL(geometry_error) + + /* load logical sector start (bottom half) */ + movl LOCAL(kernel_sector), %eax + + /* zero %edx */ + xorl %edx, %edx + + /* divide by number of sectors */ + divl (%si) + + /* save sector start */ + movb %dl, %cl + + xorw %dx, %dx /* zero %edx */ + divl 4(%si) /* divide by number of heads */ + + /* do we need too many cylinders? */ + cmpw 8(%si), %ax + jge LOCAL(geometry_error) + + /* normalize sector start (1-based) */ + incb %cl + + /* low bits of cylinder start */ + movb %al, %ch + + /* high bits of cylinder start */ + xorb %al, %al + shrw $2, %ax + orb %al, %cl + + /* save head start */ + movb %dl, %al + + /* restore %dl */ + popw %dx + + /* head start */ + movb %al, %dh + +/* + * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory + * Call with %ah = 0x2 + * %al = number of sectors + * %ch = cylinder + * %cl = sector (bits 6-7 are high bits of "cylinder") + * %dh = head + * %dl = drive (0x80 for hard disk, 0x0 for floppy disk) + * %es:%bx = segment:offset of buffer + * Return: + * %al = 0x0 on success; err code on failure + */ + + movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx + movw %bx, %es /* load %es segment with disk buffer */ + + xorw %bx, %bx /* %bx = 0, put it at 0 in the segment */ + movw $0x0201, %ax /* function 2 */ + int $0x13 + + jc LOCAL(read_error) + + movw %es, %bx + +LOCAL(copy_buffer): + /* + * We need to save %cx and %si because the startup code in + * kernel uses them without initializing them. + */ + pusha + pushw %ds + + movw $0x100, %cx + movw %bx, %ds + xorw %si, %si + movw $GRUB_BOOT_MACHINE_KERNEL_ADDR, %di + movw %si, %es + + cld + + rep + movsw + + popw %ds + popa + + /* boot kernel */ + jmp *(LOCAL(kernel_address)) + +/* END OF MAIN LOOP */ + +/* + * BIOS Geometry translation error (past the end of the disk geometry!). + */ +LOCAL(geometry_error): + ERR(geometry_error_string) + +/* + * Read error on the disk. + */ +LOCAL(read_error): + movw $read_error_string, %si +LOCAL(error_message): + call LOCAL(message) +LOCAL(general_error): + MSG(general_error_string) + +/* go here when you need to stop the machine hard after an error condition */ + /* tell the BIOS a boot failure, which may result in no effect */ + int $0x18 +LOCAL(stop): + jmp LOCAL(stop) + +ventoy_uuid: .ascii "XXXXXXXXXXXXXXXX" +notification_string: .asciz "VT" +geometry_error_string: .asciz "Ge" +hd_probe_error_string: .asciz "HD" +read_error_string: .asciz "Rd" +general_error_string: .asciz " Er\r\n" + + + +/* + * message: write the string pointed to by %si + * + * WARNING: trashes %si, %ax, and %bx + */ + + /* + * Use BIOS "int 10H Function 0Eh" to write character in teletype mode + * %ah = 0xe %al = character + * %bh = page %bl = foreground color (graphics modes) + */ +1: + movw $0x0001, %bx + movb $0xe, %ah + int $0x10 /* display a byte */ +LOCAL(message): + lodsb + cmpb $0, %al + jne 1b /* if not end of string, jmp to display */ + ret + + /* + * Windows NT breaks compatibility by embedding a magic + * number here. + */ + +#ifdef HYBRID_BOOT + .org 0x1b0 +LOCAL(kernel_sector): + .long 1 +LOCAL(kernel_sector_high): + .long 0 +#endif + .org GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC +nt_magic: + .long 0 + .word 0 + + /* + * This is where an MBR would go if on a hard disk. The code + * here isn't even referenced unless we're on a floppy. Kinda + * sneaky, huh? + */ + + .org GRUB_BOOT_MACHINE_PART_START + +#ifndef HYBRID_BOOT + floppy +#else + scratch +#endif + + .org GRUB_BOOT_MACHINE_PART_END + +/* the last 2 bytes in the sector 0 contain the signature */ + .word GRUB_BOOT_MACHINE_SIGNATURE diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blocklist.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blocklist.c new file mode 100644 index 0000000..7188df2 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blocklist.c @@ -0,0 +1,162 @@ +/* blocklist.c - print the block list of a file */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* Context for grub_cmd_blocklist. */ +struct blocklist_ctx +{ + unsigned long start_sector; + unsigned num_sectors; + int num_entries; + grub_disk_addr_t part_start; +}; + +/* Helper for grub_cmd_blocklist. */ +static void +print_blocklist (grub_disk_addr_t sector, unsigned num, + unsigned offset, unsigned length, struct blocklist_ctx *ctx) +{ + if (ctx->num_entries++) + grub_printf (","); + + grub_printf ("%llu", (unsigned long long) (sector - ctx->part_start)); + if (num > 0) + grub_printf ("+%u", num); + if (offset != 0 || length != 0) + grub_printf ("[%u-%u]", offset, offset + length); +} + +/* Helper for grub_cmd_blocklist. */ +static void +read_blocklist (grub_disk_addr_t sector, unsigned offset, unsigned length, + void *data) +{ + struct blocklist_ctx *ctx = data; + + if (ctx->num_sectors > 0) + { + if (ctx->start_sector + ctx->num_sectors == sector + && offset == 0 && length >= GRUB_DISK_SECTOR_SIZE) + { + ctx->num_sectors += length >> GRUB_DISK_SECTOR_BITS; + sector += length >> GRUB_DISK_SECTOR_BITS; + length &= (GRUB_DISK_SECTOR_SIZE - 1); + } + + if (!length) + return; + print_blocklist (ctx->start_sector, ctx->num_sectors, 0, 0, ctx); + ctx->num_sectors = 0; + } + + if (offset) + { + unsigned l = length + offset; + l &= (GRUB_DISK_SECTOR_SIZE - 1); + l -= offset; + print_blocklist (sector, 0, offset, l, ctx); + length -= l; + sector++; + offset = 0; + } + + if (!length) + return; + + if (length & (GRUB_DISK_SECTOR_SIZE - 1)) + { + if (length >> GRUB_DISK_SECTOR_BITS) + { + print_blocklist (sector, length >> GRUB_DISK_SECTOR_BITS, 0, 0, ctx); + sector += length >> GRUB_DISK_SECTOR_BITS; + } + print_blocklist (sector, 0, 0, length & (GRUB_DISK_SECTOR_SIZE - 1), ctx); + } + else + { + ctx->start_sector = sector; + ctx->num_sectors = length >> GRUB_DISK_SECTOR_BITS; + } +} + +static grub_err_t +grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_file_t file; + char buf[GRUB_DISK_SECTOR_SIZE]; + struct blocklist_ctx ctx = { + .start_sector = 0, + .num_sectors = 0, + .num_entries = 0, + .part_start = 0 + }; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + file = grub_file_open (args[0], GRUB_FILE_TYPE_PRINT_BLOCKLIST + | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! file) + return grub_errno; + + if (! file->device->disk) + return grub_error (GRUB_ERR_BAD_DEVICE, + "this command is available only for disk devices"); + + ctx.part_start = grub_partition_get_start (file->device->disk->partition); + + file->read_hook = read_blocklist; + file->read_hook_data = &ctx; + + while (grub_file_read (file, buf, sizeof (buf)) > 0) + ; + + if (ctx.num_sectors > 0) + print_blocklist (ctx.start_sector, ctx.num_sectors, 0, 0, &ctx); + + grub_printf("\nentry number:%d \n", ctx.num_entries); + + grub_file_close (file); + + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(blocklist) +{ + cmd = grub_register_command ("blocklist", grub_cmd_blocklist, + N_("FILE"), N_("Print a block list.")); +} + +GRUB_MOD_FINI(blocklist) +{ + grub_unregister_command (cmd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blscfg.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blscfg.c new file mode 100644 index 0000000..3d3a88e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/blscfg.c @@ -0,0 +1,1111 @@ +/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/ + +/* bls.c - implementation of the boot loader spec */ + +/* + * GRUB -- GRand Unified Bootloader + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#include "loadenv.h" + +#define GRUB_BLS_CONFIG_PATH "/loader/entries/" +#ifdef GRUB_MACHINE_EMU +#define GRUB_BOOT_DEVICE "/boot" +#else +#define GRUB_BOOT_DEVICE "($root)" +#endif + +struct keyval +{ + const char *key; + char *val; +}; + +static struct bls_entry *entries = NULL; + +#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) + +static int bls_add_keyval(struct bls_entry *entry, char *key, char *val) +{ + char *k, *v; + struct keyval **kvs, *kv; + int new_n = entry->nkeyvals + 1; + + kvs = grub_realloc (entry->keyvals, new_n * sizeof (struct keyval *)); + if (!kvs) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "couldn't find space for BLS entry"); + entry->keyvals = kvs; + + kv = grub_malloc (sizeof (struct keyval)); + if (!kv) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "couldn't find space for BLS entry"); + + k = grub_strdup (key); + if (!k) + { + grub_free (kv); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "couldn't find space for BLS entry"); + } + + v = grub_strdup (val); + if (!v) + { + grub_free (k); + grub_free (kv); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "couldn't find space for BLS entry"); + } + + kv->key = k; + kv->val = v; + + entry->keyvals[entry->nkeyvals] = kv; + grub_dprintf("blscfg", "new keyval at %p:%s:%s\n", entry->keyvals[entry->nkeyvals], k, v); + entry->nkeyvals = new_n; + + return 0; +} + +/* Find they value of the key named by keyname. If there are allowed to be + * more than one, pass a pointer to an int set to -1 the first time, and pass + * the same pointer through each time after, and it'll return them in sorted + * order as defined in the BLS fragment file */ +static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last) +{ + int idx, start = 0; + struct keyval *kv = NULL; + + if (last) + start = *last + 1; + + for (idx = start; idx < entry->nkeyvals; idx++) { + kv = entry->keyvals[idx]; + + if (!grub_strcmp (keyname, kv->key)) + break; + } + + if (idx == entry->nkeyvals) { + if (last) + *last = -1; + return NULL; + } + + if (last) + *last = idx; + + return kv->val; +} + +#define goto_return(x) ({ ret = (x); goto finish; }) + +/* compare alpha and numeric segments of two versions */ +/* return 1: a is newer than b */ +/* 0: a and b are the same version */ +/* -1: b is newer than a */ +static int vercmp(const char * a, const char * b) +{ + char oldch1, oldch2; + char *abuf, *bbuf; + char *str1, *str2; + char * one, * two; + int rc; + int isnum; + int ret = 0; + + grub_dprintf("blscfg", "%s comparing %s and %s\n", __func__, a, b); + if (!grub_strcmp(a, b)) + return 0; + + abuf = grub_malloc(grub_strlen(a) + 1); + bbuf = grub_malloc(grub_strlen(b) + 1); + str1 = abuf; + str2 = bbuf; + grub_strcpy(str1, a); + grub_strcpy(str2, b); + + one = str1; + two = str2; + + /* loop through each version segment of str1 and str2 and compare them */ + while (*one || *two) { + while (*one && !grub_isalnum(*one) && *one != '~') one++; + while (*two && !grub_isalnum(*two) && *two != '~') two++; + + /* handle the tilde separator, it sorts before everything else */ + if (*one == '~' || *two == '~') { + if (*one != '~') goto_return (1); + if (*two != '~') goto_return (-1); + one++; + two++; + continue; + } + + /* If we ran to the end of either, we are finished with the loop */ + if (!(*one && *two)) break; + + str1 = one; + str2 = two; + + /* grab first completely alpha or completely numeric segment */ + /* leave one and two pointing to the start of the alpha or numeric */ + /* segment and walk str1 and str2 to end of segment */ + if (grub_isdigit(*str1)) { + while (*str1 && grub_isdigit(*str1)) str1++; + while (*str2 && grub_isdigit(*str2)) str2++; + isnum = 1; + } else { + while (*str1 && grub_isalpha(*str1)) str1++; + while (*str2 && grub_isalpha(*str2)) str2++; + isnum = 0; + } + + /* save character at the end of the alpha or numeric segment */ + /* so that they can be restored after the comparison */ + oldch1 = *str1; + *str1 = '\0'; + oldch2 = *str2; + *str2 = '\0'; + + /* this cannot happen, as we previously tested to make sure that */ + /* the first string has a non-null segment */ + if (one == str1) goto_return(-1); /* arbitrary */ + + /* take care of the case where the two version segments are */ + /* different types: one numeric, the other alpha (i.e. empty) */ + /* numeric segments are always newer than alpha segments */ + /* XXX See patch #60884 (and details) from bugzilla #50977. */ + if (two == str2) goto_return (isnum ? 1 : -1); + + if (isnum) { + grub_size_t onelen, twolen; + /* this used to be done by converting the digit segments */ + /* to ints using atoi() - it's changed because long */ + /* digit segments can overflow an int - this should fix that. */ + + /* throw away any leading zeros - it's a number, right? */ + while (*one == '0') one++; + while (*two == '0') two++; + + /* whichever number has more digits wins */ + onelen = grub_strlen(one); + twolen = grub_strlen(two); + if (onelen > twolen) goto_return (1); + if (twolen > onelen) goto_return (-1); + } + + /* grub_strcmp will return which one is greater - even if the two */ + /* segments are alpha or if they are numeric. don't return */ + /* if they are equal because there might be more segments to */ + /* compare */ + rc = grub_strcmp(one, two); + if (rc) goto_return (rc < 1 ? -1 : 1); + + /* restore character that was replaced by null above */ + *str1 = oldch1; + one = str1; + *str2 = oldch2; + two = str2; + } + + /* this catches the case where all numeric and alpha segments have */ + /* compared identically but the segment sepparating characters were */ + /* different */ + if ((!*one) && (!*two)) goto_return (0); + + /* whichever version still has characters left over wins */ + if (!*one) goto_return (-1); else goto_return (1); + +finish: + grub_free (abuf); + grub_free (bbuf); + return ret; +} + +/* returns name/version/release */ +/* NULL string pointer returned if nothing found */ +static void +split_package_string (char *package_string, char **name, + char **version, char **release) +{ + char *package_version, *package_release; + + /* Release */ + package_release = grub_strrchr (package_string, '-'); + + if (package_release != NULL) + *package_release++ = '\0'; + + *release = package_release; + + if (name == NULL) + { + *version = package_string; + } + else + { + /* Version */ + package_version = grub_strrchr(package_string, '-'); + + if (package_version != NULL) + *package_version++ = '\0'; + + *version = package_version; + /* Name */ + *name = package_string; + } + + /* Bubble up non-null values from release to name */ + if (name != NULL && *name == NULL) + { + *name = (*version == NULL ? *release : *version); + *version = *release; + *release = NULL; + } + if (*version == NULL) + { + *version = *release; + *release = NULL; + } +} + +static int +split_cmp(char *nvr0, char *nvr1, int has_name) +{ + int ret = 0; + char *name0, *version0, *release0; + char *name1, *version1, *release1; + + split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0); + split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1); + + if (has_name) + { + ret = vercmp(name0 == NULL ? "" : name0, + name1 == NULL ? "" : name1); + if (ret != 0) + return ret; + } + + ret = vercmp(version0 == NULL ? "" : version0, + version1 == NULL ? "" : version1); + if (ret != 0) + return ret; + + ret = vercmp(release0 == NULL ? "" : release0, + release1 == NULL ? "" : release1); + return ret; +} + +/* return 1: e0 is newer than e1 */ +/* 0: e0 and e1 are the same version */ +/* -1: e1 is newer than e0 */ +static int bls_cmp(const struct bls_entry *e0, const struct bls_entry *e1) +{ + char *id0, *id1; + int r; + + id0 = grub_strdup(e0->filename); + id1 = grub_strdup(e1->filename); + + r = split_cmp(id0, id1, 1); + + grub_free(id0); + grub_free(id1); + + return r; +} + +static void list_add_tail(struct bls_entry *head, struct bls_entry *item) +{ + item->next = head; + if (head->prev) + head->prev->next = item; + item->prev = head->prev; + head->prev = item; +} + +static int bls_add_entry(struct bls_entry *entry) +{ + struct bls_entry *e, *last = NULL; + int rc; + + if (!entries) { + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); + entries = entry; + return 0; + } + + FOR_BLS_ENTRIES(e) { + rc = bls_cmp(entry, e); + + if (!rc) + return GRUB_ERR_BAD_ARGUMENT; + + if (rc == 1) { + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); + list_add_tail (e, entry); + if (e == entries) { + entries = entry; + entry->prev = NULL; + } + return 0; + } + last = e; + } + + if (last) { + grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); + last->next = entry; + entry->prev = last; + } + + return 0; +} + +struct read_entry_info { + const char *devid; + const char *dirname; + grub_file_t file; +}; + +static int read_entry ( + const char *filename, + const struct grub_dirhook_info *dirhook_info UNUSED, + void *data) +{ + grub_size_t m = 0, n, clip = 0; + int rc = 0; + char *p = NULL; + grub_file_t f = NULL; + struct bls_entry *entry; + struct read_entry_info *info = (struct read_entry_info *)data; + + grub_dprintf ("blscfg", "filename: \"%s\"\n", filename); + + n = grub_strlen (filename); + + if (info->file) + { + f = info->file; + } + else + { + if (filename[0] == '.') + return 0; + + if (n <= 5) + return 0; + + if (grub_strcmp (filename + n - 5, ".conf") != 0) + return 0; + + p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename); + + f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG); + if (!f) + goto finish; + } + + entry = grub_zalloc (sizeof (*entry)); + if (!entry) + goto finish; + + if (info->file) + { + char *slash; + + if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0) + clip = 5; + + slash = grub_strrchr (filename, '/'); + if (!slash) + slash = grub_strrchr (filename, '\\'); + + while (*slash == '/' || *slash == '\\') + slash++; + + m = slash ? slash - filename : 0; + } + else + { + m = 0; + clip = 5; + } + n -= m; + + entry->filename = grub_strndup(filename + m, n - clip); + if (!entry->filename) + goto finish; + + entry->filename[n - 5] = '\0'; + + for (;;) + { + char *buf; + char *separator; + + buf = grub_file_getline (f); + if (!buf) + break; + + while (buf && buf[0] && (buf[0] == ' ' || buf[0] == '\t')) + buf++; + if (buf[0] == '#') + continue; + + separator = grub_strchr (buf, ' '); + + if (!separator) + separator = grub_strchr (buf, '\t'); + + if (!separator || separator[1] == '\0') + { + grub_free (buf); + break; + } + + separator[0] = '\0'; + + do { + separator++; + } while (*separator == ' ' || *separator == '\t'); + + rc = bls_add_keyval (entry, buf, separator); + grub_free (buf); + if (rc < 0) + break; + } + + if (!rc) + bls_add_entry(entry); + +finish: + if (p) + grub_free (p); + + if (f) + grub_file_close (f); + + return 0; +} + +static grub_envblk_t saved_env = NULL; + +static int UNUSED +save_var (const char *name, const char *value, void *whitelist UNUSED) +{ + const char *val = grub_env_get (name); + grub_dprintf("blscfg", "saving \"%s\"\n", name); + + if (val) + grub_envblk_set (saved_env, name, value); + + return 0; +} + +static int UNUSED +unset_var (const char *name, const char *value UNUSED, void *whitelist) +{ + grub_dprintf("blscfg", "restoring \"%s\"\n", name); + if (! whitelist) + { + grub_env_unset (name); + return 0; + } + + if (test_whitelist_membership (name, + (const grub_env_whitelist_t *) whitelist)) + grub_env_unset (name); + + return 0; +} + +static char **bls_make_list (struct bls_entry *entry, const char *key, int *num) +{ + int last = -1; + char *val; + + int nlist = 0; + char **list = NULL; + + list = grub_malloc (sizeof (char *)); + if (!list) + return NULL; + list[0] = NULL; + + while (1) + { + char **new; + + val = bls_get_val (entry, key, &last); + if (!val) + break; + + new = grub_realloc (list, (nlist + 2) * sizeof (char *)); + if (!new) + break; + + list = new; + list[nlist++] = val; + list[nlist] = NULL; + } + + if (num) + *num = nlist; + + return list; +} + +static char *field_append(bool is_var, char *buffer, char *start, char *end) +{ + char *temp = grub_strndup(start, end - start + 1); + const char *field = temp; + + if (is_var) { + field = grub_env_get (temp); + if (!field) + return buffer; + } + + if (!buffer) { + buffer = grub_strdup(field); + if (!buffer) + return NULL; + } else { + buffer = grub_realloc (buffer, grub_strlen(buffer) + grub_strlen(field)); + if (!buffer) + return NULL; + + grub_stpcpy (buffer + grub_strlen(buffer), field); + } + + return buffer; +} + +static char *expand_val(char *value) +{ + char *buffer = NULL; + char *start = value; + char *end = value; + bool is_var = false; + + if (!value) + return NULL; + + while (*value) { + if (*value == '$') { + if (start != end) { + buffer = field_append(is_var, buffer, start, end); + if (!buffer) + return NULL; + } + + is_var = true; + start = value + 1; + } else if (is_var) { + if (!grub_isalnum(*value) && *value != '_') { + buffer = field_append(is_var, buffer, start, end); + is_var = false; + start = value; + } + } + + end = value; + value++; + } + + if (start != end) { + buffer = field_append(is_var, buffer, start, end); + if (!buffer) + return NULL; + } + + return buffer; +} + +static char **early_initrd_list (const char *initrd) +{ + int nlist = 0; + char **list = NULL; + char *separator; + + while ((separator = grub_strchr (initrd, ' '))) + { + list = grub_realloc (list, (nlist + 2) * sizeof (char *)); + if (!list) + return NULL; + + list[nlist++] = grub_strndup(initrd, separator - initrd); + list[nlist] = NULL; + initrd = separator + 1; + } + + list = grub_realloc (list, (nlist + 2) * sizeof (char *)); + if (!list) + return NULL; + + list[nlist++] = grub_strndup(initrd, grub_strlen(initrd)); + list[nlist] = NULL; + + return list; +} + +static void create_entry (struct bls_entry *entry) +{ + int argc = 0; + const char **argv = NULL; + + char *title = NULL; + char *clinux = NULL; + char *options = NULL; + char **initrds = NULL; + char *initrd = NULL; + const char *early_initrd = NULL; + char **early_initrds = NULL; + char *initrd_prefix = NULL; + char *id = entry->filename; + char *dotconf = id; + char *hotkey = NULL; + + char *users = NULL; + char **classes = NULL; + + char **args = NULL; + + char *src = NULL; + int bootlen; + const char *bootdev; + int i, index; + + grub_dprintf("blscfg", "%s got here\n", __func__); + clinux = bls_get_val (entry, "linux", NULL); + if (!clinux) + { + grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", entry->filename); + goto finish; + } + + bootdev = grub_env_get("ventoy_bls_bootdev"); + if (!bootdev) + { + bootdev = GRUB_BOOT_DEVICE; + } + bootlen = grub_strlen(bootdev) + 2;//space and \0 + + /* + * strip the ".conf" off the end before we make it our "id" field. + */ + do + { + dotconf = grub_strstr(dotconf, ".conf"); + } while (dotconf != NULL && dotconf[5] != '\0'); + if (dotconf) + dotconf[0] = '\0'; + + title = bls_get_val (entry, "title", NULL); + options = expand_val (bls_get_val (entry, "options", NULL)); + + if (!options) + options = expand_val ((char *)grub_env_get("default_kernelopts")); + + initrds = bls_make_list (entry, "initrd", NULL); + + hotkey = bls_get_val (entry, "grub_hotkey", NULL); + users = expand_val (bls_get_val (entry, "grub_users", NULL)); + classes = bls_make_list (entry, "grub_class", NULL); + args = bls_make_list (entry, "grub_arg", &argc); + + argc += 1; + argv = grub_malloc ((argc + 1) * sizeof (char *)); + argv[0] = title ? title : clinux; + for (i = 1; i < argc; i++) + argv[i] = args[i-1]; + argv[argc] = NULL; + + early_initrd = grub_env_get("early_initrd"); + + grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id \"%s\"\n", + title, id); + if (early_initrd) + { + early_initrds = early_initrd_list(early_initrd); + if (!early_initrds) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + + if (initrds != NULL && initrds[0] != NULL) + { + initrd_prefix = grub_strrchr (initrds[0], '/'); + initrd_prefix = grub_strndup(initrds[0], initrd_prefix - initrds[0] + 1); + } + else + { + initrd_prefix = grub_strrchr (clinux, '/'); + initrd_prefix = grub_strndup(clinux, initrd_prefix - clinux + 1); + } + + if (!initrd_prefix) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + } + + if (early_initrds || initrds) + { + int initrd_size = sizeof ("initrd"); + char *tmp; + + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) + initrd_size += bootlen \ + + grub_strlen(initrd_prefix) \ + + grub_strlen (early_initrds[i]) + 1; + + for (i = 0; initrds != NULL && initrds[i] != NULL; i++) + initrd_size += bootlen \ + + grub_strlen (initrds[i]) + 1; + initrd_size += 1; + + initrd = grub_malloc (initrd_size); + if (!initrd) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + + + tmp = grub_stpcpy(initrd, "initrd"); + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) + { + grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]); + tmp = grub_stpcpy (tmp, " "); + tmp = grub_stpcpy (tmp, bootdev); + tmp = grub_stpcpy (tmp, initrd_prefix); + tmp = grub_stpcpy (tmp, early_initrds[i]); + grub_free(early_initrds[i]); + } + + for (i = 0; initrds != NULL && initrds[i] != NULL; i++) + { + grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]); + tmp = grub_stpcpy (tmp, " "); + tmp = grub_stpcpy (tmp, bootdev); + tmp = grub_stpcpy (tmp, initrds[i]); + } + tmp = grub_stpcpy (tmp, "\n"); + } + + src = grub_xasprintf ("load_video\n" + "set gfxpayload=keep\n" + "insmod gzio\n" + "linux %s%s%s%s\n" + "%s", + bootdev, clinux, options ? " " : "", options ? options : "", + initrd ? initrd : ""); + + grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry); + grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id); + +finish: + grub_free (initrd); + grub_free (initrd_prefix); + grub_free (early_initrds); + grub_free (initrds); + grub_free (options); + grub_free (classes); + grub_free (args); + grub_free (argv); + grub_free (src); +} + +struct find_entry_info { + const char *dirname; + const char *devid; + grub_device_t dev; + grub_fs_t fs; +}; + +/* + * info: the filesystem object the file is on. + */ +static int find_entry (struct find_entry_info *info) +{ + struct read_entry_info read_entry_info; + grub_fs_t blsdir_fs = NULL; + grub_device_t blsdir_dev = NULL; + const char *blsdir = info->dirname; + int fallback = 0; + int r = 0; + + if (!blsdir) { + blsdir = grub_env_get ("blsdir"); + if (!blsdir) + blsdir = GRUB_BLS_CONFIG_PATH; + } + + read_entry_info.file = NULL; + read_entry_info.dirname = blsdir; + + grub_dprintf ("blscfg", "scanning blsdir: %s\n", blsdir); + + blsdir_dev = info->dev; + blsdir_fs = info->fs; + read_entry_info.devid = info->devid; + +read_fallback: + r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry, + &read_entry_info); + if (r != 0) { + grub_dprintf ("blscfg", "read_entry returned error\n"); + grub_err_t e; + do + { + e = grub_error_pop(); + } while (e); + } + + if (r && !info->dirname && !fallback) { + read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH; + grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to %s\n", + blsdir, read_entry_info.dirname); + fallback = 1; + goto read_fallback; + } + + return 0; +} + +static grub_err_t +bls_load_entries (const char *path) +{ + grub_size_t len; + grub_fs_t fs; + grub_device_t dev; + static grub_err_t r; + const char *devid = NULL; + char *blsdir = NULL; + struct find_entry_info info = { + .dev = NULL, + .fs = NULL, + .dirname = NULL, + }; + struct read_entry_info rei = { + .devid = NULL, + .dirname = NULL, + }; + + if (path) { + len = grub_strlen (path); + if (grub_strcmp (path + len - 5, ".conf") == 0) { + rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG); + if (!rei.file) + return grub_errno; + /* + * read_entry() closes the file + */ + return read_entry(path, NULL, &rei); + } else if (path[0] == '(') { + devid = path + 1; + + blsdir = grub_strchr (path, ')'); + if (!blsdir) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Filepath isn't correct")); + + *blsdir = '\0'; + blsdir = blsdir + 1; + } + } + + if (!devid) { +#ifdef GRUB_MACHINE_EMU + devid = "host"; +#elif defined(GRUB_MACHINE_EFI) + devid = grub_env_get ("root"); +#else + devid = grub_env_get ("boot"); + if (!devid) + { + devid = grub_env_get ("root"); + } +#endif + if (!devid) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + N_("variable `%s' isn't set"), "boot"); + } + + grub_dprintf ("blscfg", "opening %s\n", devid); + dev = grub_device_open (devid); + if (!dev) + return grub_errno; + + grub_dprintf ("blscfg", "probing fs\n"); + fs = grub_fs_probe (dev); + if (!fs) + { + r = grub_errno; + goto finish; + } + + info.dirname = blsdir; + info.devid = devid; + info.dev = dev; + info.fs = fs; + find_entry(&info); + +finish: + if (dev) + grub_device_close (dev); + + return r; +} + +static bool +is_default_entry(const char *def_entry, struct bls_entry *entry, int idx) +{ + const char *title; + int def_idx; + + if (!def_entry) + return false; + + if (grub_strcmp(def_entry, entry->filename) == 0) + return true; + + title = bls_get_val(entry, "title", NULL); + + if (title && grub_strcmp(def_entry, title) == 0) + return true; + + def_idx = (int)grub_strtol(def_entry, NULL, 0); + if (grub_errno == GRUB_ERR_BAD_NUMBER) { + grub_errno = GRUB_ERR_NONE; + return false; + } + + if (def_idx == idx) + return true; + + return false; +} + +static grub_err_t +bls_create_entries (bool show_default, bool show_non_default, char *entry_id) +{ + const char *def_entry = NULL; + struct bls_entry *entry = NULL; + int idx = 0; + + def_entry = grub_env_get("default"); + + grub_dprintf ("blscfg", "%s Creating entries from bls\n", __func__); + FOR_BLS_ENTRIES(entry) { + if (entry->visible) { + idx++; + continue; + } + + if ((show_default && is_default_entry(def_entry, entry, idx)) || + (show_non_default && !is_default_entry(def_entry, entry, idx)) || + (entry_id && grub_strcmp(entry_id, entry->filename) == 0)) { + create_entry(entry); + entry->visible = 1; + } + idx++; + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED, + int argc, char **args) +{ + grub_err_t r; + char *path = NULL; + char *entry_id = NULL; + bool show_default = true; + bool show_non_default = true; + + if (argc == 1) { + if (grub_strcmp (args[0], "default") == 0) { + show_non_default = false; + } else if (grub_strcmp (args[0], "non-default") == 0) { + show_default = false; + } else if (args[0][0] == '(') { + path = args[0]; + } else { + entry_id = args[0]; + show_default = false; + show_non_default = false; + } + } + + r = bls_load_entries(path); + if (r) + return r; + + return bls_create_entries(show_default, show_non_default, entry_id); +} + +static grub_extcmd_t cmd; +static grub_extcmd_t oldcmd; + +GRUB_MOD_INIT(blscfg) +{ + grub_dprintf("blscfg", "%s got here\n", __func__); + cmd = grub_register_extcmd ("blscfg", + grub_cmd_blscfg, + 0, + NULL, + N_("Import Boot Loader Specification snippets."), + NULL); + oldcmd = grub_register_extcmd ("bls_import", + grub_cmd_blscfg, + 0, + NULL, + N_("Import Boot Loader Specification snippets."), + NULL); +} + +GRUB_MOD_FINI(blscfg) +{ + grub_unregister_extcmd (cmd); + grub_unregister_extcmd (oldcmd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/efi/efifwsetup.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/efi/efifwsetup.c new file mode 100644 index 0000000..890cae1 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/efi/efifwsetup.c @@ -0,0 +1,98 @@ +/* fwsetup.c - Reboot into firmware setup menu. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_efi_boolean_t efifwsetup_is_supported (void); + +static grub_err_t +grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + grub_efi_uint64_t *old_os_indications; + grub_efi_uint64_t os_indications = GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + grub_err_t status; + grub_size_t oi_size; + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; + + if (argc >= 1 && grub_strcmp(args[0], "--is-supported") == 0) + return !efifwsetup_is_supported (); + + if (!efifwsetup_is_supported ()) + return grub_error (GRUB_ERR_INVALID_COMMAND, + N_("reboot to firmware setup is not supported by the current firmware")); + + old_os_indications = grub_efi_get_variable ("OsIndications", &global, + &oi_size); + + if (old_os_indications != NULL && oi_size == sizeof (os_indications)) + os_indications |= *old_os_indications; + + status = grub_efi_set_variable ("OsIndications", &global, &os_indications, + sizeof (os_indications)); + if (status != GRUB_ERR_NONE) + return status; + + grub_reboot (); + + return GRUB_ERR_BUG; +} + +static grub_command_t cmd = NULL; + +static grub_efi_boolean_t +efifwsetup_is_supported (void) +{ + grub_efi_uint64_t *os_indications_supported = NULL; + grub_size_t oi_size = 0; + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; + + os_indications_supported = grub_efi_get_variable ("OsIndicationsSupported", + &global, &oi_size); + + if (!os_indications_supported) + return 0; + + if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI) + return 1; + + return 0; +} + +GRUB_MOD_INIT (efifwsetup) +{ + cmd = grub_register_command ("fwsetup", grub_cmd_fwsetup, NULL, + N_("Reboot into firmware setup menu.")); + +} + +GRUB_MOD_FINI (efifwsetup) +{ + if (cmd) + grub_unregister_command (cmd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/efi/fwload.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/efi/fwload.c new file mode 100644 index 0000000..6adaf6a --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/efi/fwload.c @@ -0,0 +1,205 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2022 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID; + +static grub_efi_status_t +grub_efi_connect_all (void) +{ + grub_efi_status_t status; + grub_efi_uintn_t handle_count; + grub_efi_handle_t *handle_buffer; + grub_efi_uintn_t index; + grub_efi_boot_services_t *b; + grub_dprintf ("efi", "Connecting ...\n"); + b = grub_efi_system_table->boot_services; + status = efi_call_5 (b->locate_handle_buffer, + GRUB_EFI_ALL_HANDLES, NULL, NULL, + &handle_count, &handle_buffer); + + if (status != GRUB_EFI_SUCCESS) + return status; + + for (index = 0; index < handle_count; index++) + { + status = efi_call_4 (b->connect_controller, + handle_buffer[index], NULL, NULL, 1); + } + + if (handle_buffer) + { + efi_call_1 (b->free_pool, handle_buffer); + } + return GRUB_EFI_SUCCESS; +} + +static grub_err_t +grub_efi_load_driver (grub_size_t size, void *boot_image, int connect) +{ + grub_efi_status_t status; + grub_efi_handle_t driver_handle; + grub_efi_boot_services_t *b; + grub_efi_loaded_image_t *loaded_image; + + b = grub_efi_system_table->boot_services; + + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, NULL, + boot_image, size, &driver_handle); + if (status != GRUB_EFI_SUCCESS) + { + if (status == GRUB_EFI_OUT_OF_RESOURCES) + grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources"); + else + grub_error (GRUB_ERR_BAD_OS, "cannot load image"); + goto fail; + } + loaded_image = grub_efi_get_loaded_image (driver_handle); + if (! loaded_image) + { + grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); + goto fail; + } + grub_dprintf ("efi", "Registering loaded image\n"); + status = efi_call_3 (b->handle_protocol, driver_handle, + &loaded_image_guid, (void **)&loaded_image); + if (status != GRUB_EFI_SUCCESS) + { + grub_error (GRUB_ERR_BAD_OS, "not a dirver"); + goto fail; + } + grub_dprintf ("efi", "StartImage: %p\n", boot_image); + status = efi_call_3 (b->start_image, driver_handle, NULL, NULL); + if (status != GRUB_EFI_SUCCESS) + { + grub_error (GRUB_ERR_BAD_OS, "StartImage failed"); + goto fail; + } + if (connect) + { + status = grub_efi_connect_all (); + if (status != GRUB_EFI_SUCCESS) + { + grub_error (GRUB_ERR_BAD_OS, "cannot connect controllers\n"); + goto fail; + } + } + grub_dprintf ("efi", "Driver installed\n"); + return 0; +fail: + return grub_errno; +} + +static const struct grub_arg_option options_fwload[] = +{ + {"nc", 'n', 0, N_("Loads the driver, but does not connect the driver."), 0, 0}, + {0, 0, 0, 0, 0, 0} +}; + +static grub_err_t +grub_cmd_fwload (grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + int connect = 1; + grub_file_t file = 0; + grub_efi_boot_services_t *b; + grub_efi_status_t status; + grub_efi_uintn_t pages = 0; + grub_ssize_t size; + grub_efi_physical_address_t address; + void *boot_image = 0; + + b = grub_efi_system_table->boot_services; + if (argc != 1) + goto fail; + + file = grub_file_open (args[0], GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); + if (! file) + goto fail; + size = grub_file_size (file); + if (!size) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]); + goto fail; + } + pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12); + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, + GRUB_EFI_LOADER_CODE, pages, &address); + if (status != GRUB_EFI_SUCCESS) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto fail; + } + boot_image = (void *) ((grub_addr_t) address); + if (grub_file_read (file, boot_image, size) != size) + { + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]); + goto fail; + } + grub_file_close (file); + if (state[0].set) + connect = 0; + if (grub_efi_load_driver (size, boot_image, connect)) + goto fail; + return GRUB_ERR_NONE; +fail: + if (file) + grub_file_close (file); + if (address) + efi_call_2 (b->free_pages, address, pages); + return grub_errno; +} + +static grub_err_t +grub_cmd_fwconnect (grub_extcmd_context_t ctxt __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + grub_efi_connect_all (); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd_fwload, cmd_fwconnect; + +GRUB_MOD_INIT(fwload) +{ + cmd_fwload = grub_register_extcmd ("fwload", grub_cmd_fwload, 0, N_("FILE"), + N_("Install UEFI driver."), options_fwload); + cmd_fwconnect = grub_register_extcmd ("fwconnect", grub_cmd_fwconnect, 0, + NULL, N_("Connect drivers."), 0); +} + +GRUB_MOD_FINI(fwload) +{ + grub_unregister_extcmd (cmd_fwload); + grub_unregister_extcmd (cmd_fwconnect); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/efi/smbios.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/efi/smbios.c new file mode 100644 index 0000000..b370019 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/efi/smbios.c @@ -0,0 +1,61 @@ +/* smbios.c - get smbios tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2019 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include + +struct grub_smbios_eps * +grub_machine_smbios_get_eps (void) +{ + unsigned i; + static grub_efi_packed_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID; + + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) + { + grub_efi_packed_guid_t *guid = + &grub_efi_system_table->configuration_table[i].vendor_guid; + + if (! grub_memcmp (guid, &smbios_guid, sizeof (grub_efi_packed_guid_t))) + return (struct grub_smbios_eps *) + grub_efi_system_table->configuration_table[i].vendor_table; + } + + return 0; +} + +struct grub_smbios_eps3 * +grub_machine_smbios_get_eps3 (void) +{ + unsigned i; + static grub_efi_packed_guid_t smbios3_guid = GRUB_EFI_SMBIOS3_TABLE_GUID; + + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) + { + grub_efi_packed_guid_t *guid = + &grub_efi_system_table->configuration_table[i].vendor_guid; + + if (! grub_memcmp (guid, &smbios3_guid, sizeof (grub_efi_packed_guid_t))) + return (struct grub_smbios_eps3 *) + grub_efi_system_table->configuration_table[i].vendor_table; + } + + return 0; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/hashsum.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/hashsum.c new file mode 100644 index 0000000..4b866f2 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/hashsum.c @@ -0,0 +1,351 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static const struct grub_arg_option options[] = { + {"hash", 'h', 0, N_("Specify hash to use."), N_("HASH"), ARG_TYPE_STRING}, + {"check", 'c', 0, N_("Check hashes of files with hash list FILE."), + N_("FILE"), ARG_TYPE_STRING}, + {"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIR"), + ARG_TYPE_STRING}, + {"keep-going", 'k', 0, N_("Don't stop after first error."), 0, 0}, + {"uncompress", 'u', 0, N_("Uncompress file before checksumming."), 0, 0}, + {0, 0, 0, 0, 0, 0} +}; + +static struct { const char *name; const char *hashname; } aliases[] = + { + {"sha256sum", "sha256"}, + {"sha512sum", "sha512"}, + {"sha1sum", "sha1"}, + {"md5sum", "md5"}, + {"crc", "crc32"}, + }; + +static inline int +hextoval (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +static grub_err_t +hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result) +{ + int progress = 0; + grub_uint64_t ro = 0; + grub_uint64_t div = 0; + grub_uint64_t total = 0; + void *context; + grub_uint8_t *readbuf; +#define BUF_SIZE 1024 * 1024 + readbuf = grub_malloc (BUF_SIZE); + if (!readbuf) + return grub_errno; + context = grub_zalloc (hash->contextsize); + if (!readbuf || !context) + goto fail; + + if (file->size > 16 * 1024 * 1024) + progress = 1; + + hash->init (context); + while (1) + { + grub_ssize_t r; + r = grub_file_read (file, readbuf, BUF_SIZE); + if (r < 0) + goto fail; + if (r == 0) + break; + hash->write (context, readbuf, r); + if (progress) + { + total += r; + div = grub_divmod64(total * 100, (grub_uint64_t)file->size, &ro); + grub_printf("\rCalculating %s %d%% ", hash->name, (int)div); + grub_refresh(); + } + } + hash->final (context); + grub_memcpy (result, hash->read (context), hash->mdlen); + + grub_free (readbuf); + grub_free (context); + if (progress) + { + grub_printf("\rCalculating %s 100%% \n\r\n", hash->name); + grub_refresh(); + } + return GRUB_ERR_NONE; + + fail: + grub_free (readbuf); + grub_free (context); + return grub_errno; +} + +static grub_err_t +check_list (const gcry_md_spec_t *hash, const char *hashfilename, + const char *prefix, int keep, int uncompress) +{ + grub_file_t hashlist, file; + char *buf = NULL; + grub_uint8_t expected[GRUB_CRYPTO_MAX_MDLEN]; + grub_uint8_t actual[GRUB_CRYPTO_MAX_MDLEN]; + grub_err_t err; + unsigned i; + unsigned unread = 0, mismatch = 0; + + if (hash->mdlen > GRUB_CRYPTO_MAX_MDLEN) + return grub_error (GRUB_ERR_BUG, "mdlen is too long"); + + hashlist = grub_file_open (hashfilename, GRUB_FILE_TYPE_HASHLIST); + if (!hashlist) + return grub_errno; + + while (grub_free (buf), (buf = grub_file_getline (hashlist))) + { + const char *p = buf; + while (grub_isspace (p[0])) + p++; + for (i = 0; i < hash->mdlen; i++) + { + int high, low; + high = hextoval (*p++); + low = hextoval (*p++); + if (high < 0 || low < 0) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); + expected[i] = (high << 4) | low; + } + if ((p[0] != ' ' && p[0] != '\t') || (p[1] != ' ' && p[1] != '\t')) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); + p += 2; + if (prefix) + { + char *filename; + + filename = grub_xasprintf ("%s/%s", prefix, p); + if (!filename) + return grub_errno; + file = grub_file_open (filename, GRUB_FILE_TYPE_TO_HASH + | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS + : GRUB_FILE_TYPE_NONE)); + grub_free (filename); + } + else + file = grub_file_open (p, GRUB_FILE_TYPE_TO_HASH + | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS + : GRUB_FILE_TYPE_NONE)); + if (!file) + { + grub_file_close (hashlist); + grub_free (buf); + return grub_errno; + } + err = hash_file (file, hash, actual); + grub_file_close (file); + if (err) + { + grub_printf_ (N_("%s: READ ERROR\n"), p); + if (!keep) + { + grub_file_close (hashlist); + grub_free (buf); + return err; + } + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0) + { + grub_printf_ (N_("%s: HASH MISMATCH\n"), p); + if (!keep) + { + grub_file_close (hashlist); + grub_free (buf); + return grub_error (GRUB_ERR_TEST_FAILURE, + "hash of '%s' mismatches", p); + } + mismatch++; + continue; + } + grub_printf_ (N_("%s: OK\n"), p); + } + if (mismatch || unread) + return grub_error (GRUB_ERR_TEST_FAILURE, + "%d files couldn't be read and hash " + "of %d files mismatches", unread, mismatch); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_hashsum (struct grub_extcmd_context *ctxt, + int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + const char *hashname = NULL; + const char *prefix = NULL; + const gcry_md_spec_t *hash; + unsigned i; + int keep = state[3].set; + int uncompress = state[4].set; + unsigned unread = 0; + int len = 0; + char hashsum[256]; + + for (i = 0; i < ARRAY_SIZE (aliases); i++) + if (grub_strcmp (ctxt->extcmd->cmd->name, aliases[i].name) == 0) + hashname = aliases[i].hashname; + if (state[0].set) + hashname = state[0].arg; + + if (!hashname) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no hash specified"); + + hash = grub_crypto_lookup_md_by_name (hashname); + if (!hash) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown hash"); + + if (hash->mdlen > GRUB_CRYPTO_MAX_MDLEN) + return grub_error (GRUB_ERR_BUG, "mdlen is too long"); + + if (state[2].set) + prefix = state[2].arg; + + if (state[1].set) + { + if (argc != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "--check is incompatible with file list"); + return check_list (hash, state[1].arg, prefix, keep, uncompress); + } + + for (i = 0; i < (unsigned) argc; i++) + { + GRUB_PROPERLY_ALIGNED_ARRAY (result, GRUB_CRYPTO_MAX_MDLEN); + grub_file_t file; + grub_err_t err; + unsigned j; + int vlnk = 0; + file = grub_file_open (args[i], GRUB_FILE_TYPE_TO_HASH + | (!uncompress ? GRUB_FILE_TYPE_NO_DECOMPRESS + : GRUB_FILE_TYPE_NONE)); + if (!file) + { + if (!keep) + return grub_errno; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + vlnk = file->vlnk; + err = hash_file (file, hash, result); + grub_file_close (file); + if (err) + { + if (!keep) + return err; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + for (j = 0; j < hash->mdlen; j++) + { + grub_printf ("%02x", ((grub_uint8_t *) result)[j]); + len += grub_snprintf(hashsum + len, sizeof(hashsum) - len, "%02x", ((grub_uint8_t *) result)[j]); + } + grub_printf (" %s\n", vlnk ? grub_file_get_vlnk(args[i], NULL) : args[i]); + grub_env_set("VT_LAST_CHECK_SUM", hashsum); + } + + if (unread) + return grub_error (GRUB_ERR_TEST_FAILURE, "%d files couldn't be read", + unread); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd, cmd_md5, cmd_sha1, cmd_sha256, cmd_sha512, cmd_crc; + +GRUB_MOD_INIT(hashsum) +{ + cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, 0, + N_("-h HASH [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + /* TRANSLATORS: "hash checksum" is just to + be a bit more precise, you can treat it as + just "hash". */ + N_("Compute or check hash checksum."), + options); + cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, 0, + N_("[-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + N_("Compute or check hash checksum."), + options); + cmd_sha1 = grub_register_extcmd ("sha1sum", grub_cmd_hashsum, 0, + N_("[-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + N_("Compute or check hash checksum."), + options); + cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, 0, + N_("[-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + N_("Compute or check hash checksum."), + options); + cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, 0, + N_("[-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + N_("Compute or check hash checksum."), + options); + + cmd_crc = grub_register_extcmd ("crc", grub_cmd_hashsum, 0, + N_("[-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + N_("Compute or check hash checksum."), + options); +} + +GRUB_MOD_FINI(hashsum) +{ + grub_unregister_extcmd (cmd); + grub_unregister_extcmd (cmd_md5); + grub_unregister_extcmd (cmd_sha1); + grub_unregister_extcmd (cmd_sha256); + grub_unregister_extcmd (cmd_sha512); + grub_unregister_extcmd (cmd_crc); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/i386/pc/smbios.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/i386/pc/smbios.c new file mode 100644 index 0000000..15b2146 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/i386/pc/smbios.c @@ -0,0 +1,52 @@ +/* smbios.c - get smbios tables. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2019 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include + +struct grub_smbios_eps * +grub_machine_smbios_get_eps (void) +{ + grub_uint8_t *ptr; + + grub_dprintf ("smbios", "Looking for SMBIOS EPS. Scanning BIOS\n"); + + for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000; ptr += 16) + if (grub_memcmp (ptr, "_SM_", 4) == 0 + && grub_byte_checksum (ptr, sizeof (struct grub_smbios_eps)) == 0) + return (struct grub_smbios_eps *) ptr; + + return 0; +} + +struct grub_smbios_eps3 * +grub_machine_smbios_get_eps3 (void) +{ + grub_uint8_t *ptr; + + grub_dprintf ("smbios", "Looking for SMBIOS3 EPS. Scanning BIOS\n"); + + for (ptr = (grub_uint8_t *) 0xf0000; ptr < (grub_uint8_t *) 0x100000; ptr += 16) + if (grub_memcmp (ptr, "_SM3_", 5) == 0 + && grub_byte_checksum (ptr, sizeof (struct grub_smbios_eps3)) == 0) + return (struct grub_smbios_eps3 *) ptr; + + return 0; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/legacycfg.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/legacycfg.c new file mode 100644 index 0000000..ab4d1f1 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/legacycfg.c @@ -0,0 +1,894 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000, 2001, 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* Helper for legacy_file. */ +static grub_err_t +legacy_file_getline (char **line, int cont __attribute__ ((unused)), + void *data __attribute__ ((unused))) +{ + *line = 0; + return GRUB_ERR_NONE; +} + +static grub_err_t +legacy_file (const char *filename) +{ + grub_file_t file; + char *entryname = NULL, *entrysrc = NULL; + grub_menu_t menu; + char *suffix = grub_strdup (""); + + if (!suffix) + return grub_errno; + + file = grub_file_open (filename, GRUB_FILE_TYPE_CONFIG); + if (! file) + { + grub_free (suffix); + return grub_errno; + } + + menu = grub_env_get_menu (); + if (! menu) + { + menu = grub_zalloc (sizeof (*menu)); + if (! menu) + { + grub_free (suffix); + return grub_errno; + } + + grub_env_set_menu (menu); + } + + while (1) + { + char *buf = grub_file_getline (file); + char *parsed = NULL; + + if (!buf && grub_errno) + { + grub_file_close (file); + grub_free (suffix); + return grub_errno; + } + + if (!buf) + break; + + { + char *oldname = NULL; + char *newsuffix; + char *ptr; + + for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++); + + oldname = entryname; + parsed = grub_legacy_parse (ptr, &entryname, &newsuffix); + grub_free (buf); + buf = NULL; + if (newsuffix) + { + char *t; + + t = suffix; + suffix = grub_realloc (suffix, grub_strlen (suffix) + + grub_strlen (newsuffix) + 1); + if (!suffix) + { + grub_free (t); + grub_free (entrysrc); + grub_free (parsed); + grub_free (newsuffix); + grub_free (suffix); + return grub_errno; + } + grub_memcpy (suffix + grub_strlen (suffix), newsuffix, + grub_strlen (newsuffix) + 1); + grub_free (newsuffix); + newsuffix = NULL; + } + if (oldname != entryname && oldname) + { + const char **args = grub_malloc (sizeof (args[0])); + if (!args) + { + grub_file_close (file); + return grub_errno; + } + args[0] = oldname; + grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy", + NULL, NULL, + entrysrc, 0, NULL, NULL); + grub_free (args); + entrysrc[0] = 0; + grub_free (oldname); + } + } + + if (parsed && !entryname) + { + grub_normal_parse_line (parsed, legacy_file_getline, NULL); + grub_print_error (); + grub_free (parsed); + parsed = NULL; + } + else if (parsed) + { + if (!entrysrc) + entrysrc = parsed; + else + { + char *t; + + t = entrysrc; + entrysrc = grub_realloc (entrysrc, grub_strlen (entrysrc) + + grub_strlen (parsed) + 1); + if (!entrysrc) + { + grub_free (t); + grub_free (parsed); + grub_free (suffix); + return grub_errno; + } + grub_memcpy (entrysrc + grub_strlen (entrysrc), parsed, + grub_strlen (parsed) + 1); + grub_free (parsed); + parsed = NULL; + } + } + } + grub_file_close (file); + + if (entryname) + { + const char **args = grub_malloc (sizeof (args[0])); + if (!args) + { + grub_file_close (file); + grub_free (suffix); + grub_free (entrysrc); + return grub_errno; + } + args[0] = entryname; + grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, + NULL, NULL, entrysrc, 0, NULL, + NULL); + grub_free (args); + } + + grub_normal_parse_line (suffix, legacy_file_getline, NULL); + grub_print_error (); + grub_free (suffix); + grub_free (entrysrc); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_legacy_source (struct grub_command *cmd, + int argc, char **args) +{ + int new_env, extractor; + grub_err_t ret; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + extractor = (cmd->name[0] == 'e'); + new_env = (cmd->name[extractor ? (sizeof ("extract_legacy_entries_") - 1) + : (sizeof ("legacy_") - 1)] == 'c'); + + if (new_env) + grub_cls (); + + if (new_env && !extractor) + grub_env_context_open (); + if (extractor) + grub_env_extractor_open (!new_env); + + ret = legacy_file (args[0]); + + if (new_env) + { + grub_menu_t menu; + menu = grub_env_get_menu (); + if (menu && menu->size) + grub_show_menu (menu, 1, 0); + if (!extractor) + grub_env_context_close (); + } + if (extractor) + grub_env_extractor_close (!new_env); + + return ret; +} + +static enum + { + GUESS_IT, LINUX, MULTIBOOT, KFREEBSD, KNETBSD, KOPENBSD + } kernel_type; + +static grub_err_t +grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + int i; +#ifdef TODO + int no_mem_option = 0; +#endif + struct grub_command *cmd; + char **cutargs; + int cutargc; + grub_err_t err = GRUB_ERR_NONE; + + for (i = 0; i < 2; i++) + { + /* FIXME: really support this. */ + if (argc >= 1 && grub_strcmp (args[0], "--no-mem-option") == 0) + { +#ifdef TODO + no_mem_option = 1; +#endif + argc--; + args++; + continue; + } + + /* linux16 handles both zImages and bzImages. */ + if (argc >= 1 && (grub_strcmp (args[0], "--type=linux") == 0 + || grub_strcmp (args[0], "--type=biglinux") == 0)) + { + kernel_type = LINUX; + argc--; + args++; + continue; + } + + if (argc >= 1 && grub_strcmp (args[0], "--type=multiboot") == 0) + { + kernel_type = MULTIBOOT; + argc--; + args++; + continue; + } + + if (argc >= 1 && grub_strcmp (args[0], "--type=freebsd") == 0) + { + kernel_type = KFREEBSD; + argc--; + args++; + continue; + } + + if (argc >= 1 && grub_strcmp (args[0], "--type=openbsd") == 0) + { + kernel_type = KOPENBSD; + argc--; + args++; + continue; + } + + if (argc >= 1 && grub_strcmp (args[0], "--type=netbsd") == 0) + { + kernel_type = KNETBSD; + argc--; + args++; + continue; + } + } + + if (argc < 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + cutargs = grub_malloc (sizeof (cutargs[0]) * (argc - 1)); + if (!cutargs) + return grub_errno; + cutargc = argc - 1; + grub_memcpy (cutargs + 1, args + 2, sizeof (cutargs[0]) * (argc - 2)); + cutargs[0] = args[0]; + + do + { + /* First try Linux. */ + if (kernel_type == GUESS_IT || kernel_type == LINUX) + { +#ifdef GRUB_MACHINE_PCBIOS + cmd = grub_command_find ("linux16"); +#else + cmd = grub_command_find ("linux"); +#endif + if (cmd) + { + if (!(cmd->func) (cmd, cutargc, cutargs)) + { + kernel_type = LINUX; + goto out; + } + } + grub_errno = GRUB_ERR_NONE; + } + + /* Then multiboot. */ + if (kernel_type == GUESS_IT || kernel_type == MULTIBOOT) + { + cmd = grub_command_find ("multiboot"); + if (cmd) + { + if (!(cmd->func) (cmd, argc, args)) + { + kernel_type = MULTIBOOT; + goto out; + } + } + grub_errno = GRUB_ERR_NONE; + } + + { + int bsd_device = -1; + int bsd_slice = -1; + int bsd_part = -1; + { + grub_device_t dev; + const char *hdbiasstr; + int hdbias = 0; + hdbiasstr = grub_env_get ("legacy_hdbias"); + if (hdbiasstr) + { + hdbias = grub_strtoul (hdbiasstr, 0, 0); + grub_errno = GRUB_ERR_NONE; + } + dev = grub_device_open (0); + if (dev && dev->disk + && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID + && dev->disk->id >= 0x80 && dev->disk->id <= 0x90) + { + struct grub_partition *part = dev->disk->partition; + bsd_device = dev->disk->id - 0x80 - hdbias; + if (part && (grub_strcmp (part->partmap->name, "netbsd") == 0 + || grub_strcmp (part->partmap->name, "openbsd") == 0 + || grub_strcmp (part->partmap->name, "bsd") == 0)) + { + bsd_part = part->number; + part = part->parent; + } + if (part && grub_strcmp (part->partmap->name, "msdos") == 0) + bsd_slice = part->number; + } + if (dev) + grub_device_close (dev); + } + + /* k*BSD didn't really work well with grub-legacy. */ + if (kernel_type == GUESS_IT || kernel_type == KFREEBSD) + { + char buf[sizeof("adXXXXXXXXXXXXsXXXXXXXXXXXXYYY")]; + if (bsd_device != -1) + { + if (bsd_slice != -1 && bsd_part != -1) + grub_snprintf(buf, sizeof(buf), "ad%ds%d%c", bsd_device, + bsd_slice, 'a' + bsd_part); + else if (bsd_slice != -1) + grub_snprintf(buf, sizeof(buf), "ad%ds%d", bsd_device, + bsd_slice); + else + grub_snprintf(buf, sizeof(buf), "ad%d", bsd_device); + grub_env_set ("kFreeBSD.vfs.root.mountfrom", buf); + } + else + grub_env_unset ("kFreeBSD.vfs.root.mountfrom"); + cmd = grub_command_find ("kfreebsd"); + if (cmd) + { + if (!(cmd->func) (cmd, cutargc, cutargs)) + { + kernel_type = KFREEBSD; + goto out; + } + } + grub_errno = GRUB_ERR_NONE; + } + { + char **bsdargs; + int bsdargc; + char bsddevname[sizeof ("wdXXXXXXXXXXXXY")]; + int found = 0; + + if (bsd_device == -1) + { + bsdargs = cutargs; + bsdargc = cutargc; + } + else + { + char rbuf[3] = "-r"; + bsdargc = cutargc + 2; + bsdargs = grub_malloc (sizeof (bsdargs[0]) * bsdargc); + if (!bsdargs) + { + err = grub_errno; + goto out; + } + grub_memcpy (bsdargs, args, argc * sizeof (bsdargs[0])); + bsdargs[argc] = rbuf; + bsdargs[argc + 1] = bsddevname; + grub_snprintf (bsddevname, sizeof (bsddevname), + "wd%d%c", bsd_device, + bsd_part != -1 ? bsd_part + 'a' : 'c'); + } + if (kernel_type == GUESS_IT || kernel_type == KNETBSD) + { + cmd = grub_command_find ("knetbsd"); + if (cmd) + { + if (!(cmd->func) (cmd, bsdargc, bsdargs)) + { + kernel_type = KNETBSD; + found = 1; + goto free_bsdargs; + } + } + grub_errno = GRUB_ERR_NONE; + } + if (kernel_type == GUESS_IT || kernel_type == KOPENBSD) + { + cmd = grub_command_find ("kopenbsd"); + if (cmd) + { + if (!(cmd->func) (cmd, bsdargc, bsdargs)) + { + kernel_type = KOPENBSD; + found = 1; + goto free_bsdargs; + } + } + grub_errno = GRUB_ERR_NONE; + } + +free_bsdargs: + if (bsdargs != cutargs) + grub_free (bsdargs); + if (found) + goto out; + } + } + } + while (0); + + err = grub_error (GRUB_ERR_BAD_OS, "couldn't load file %s", + args[0]); +out: + grub_free (cutargs); + return err; +} + +static grub_err_t +grub_cmd_legacy_initrd (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_command *cmd; + + if (kernel_type == LINUX) + { +#ifdef GRUB_MACHINE_PCBIOS + cmd = grub_command_find ("initrd16"); +#else + cmd = grub_command_find ("initrd"); +#endif + if (!cmd) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"), +#ifdef GRUB_MACHINE_PCBIOS + "initrd16" +#else + "initrd" +#endif + ); + + return cmd->func (cmd, argc ? 1 : 0, args); + } + if (kernel_type == MULTIBOOT) + { + cmd = grub_command_find ("module"); + if (!cmd) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"), + "module"); + + return cmd->func (cmd, argc, args); + } + + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("you need to load the kernel first")); +} + +static grub_err_t +grub_cmd_legacy_initrdnounzip (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_command *cmd; + + if (kernel_type == LINUX) + { + cmd = grub_command_find ("initrd16"); + if (!cmd) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"), + "initrd16"); + + return cmd->func (cmd, argc, args); + } + if (kernel_type == MULTIBOOT) + { + char **newargs; + grub_err_t err; + char nounzipbuf[10] = "--nounzip"; + + cmd = grub_command_find ("module"); + if (!cmd) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"), + "module"); + + newargs = grub_malloc ((argc + 1) * sizeof (newargs[0])); + if (!newargs) + return grub_errno; + grub_memcpy (newargs + 1, args, argc * sizeof (newargs[0])); + newargs[0] = nounzipbuf; + + err = cmd->func (cmd, argc + 1, newargs); + grub_free (newargs); + return err; + } + + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("you need to load the kernel first")); +} + +static grub_err_t +check_password_deny (const char *user __attribute__ ((unused)), + const char *entered __attribute__ ((unused)), + void *password __attribute__ ((unused))) +{ + return GRUB_ACCESS_DENIED; +} + +#define MD5_HASHLEN 16 + +struct legacy_md5_password +{ + grub_uint8_t *salt; + int saltlen; + grub_uint8_t hash[MD5_HASHLEN]; +}; + +static int +check_password_md5_real (const char *entered, + struct legacy_md5_password *pw) +{ + grub_size_t enteredlen = grub_strlen (entered); + unsigned char alt_result[MD5_HASHLEN]; + unsigned char *digest; + grub_uint8_t *ctx; + grub_size_t i; + int ret; + + ctx = grub_zalloc (GRUB_MD_MD5->contextsize); + if (!ctx) + return 0; + + GRUB_MD_MD5->init (ctx); + GRUB_MD_MD5->write (ctx, entered, enteredlen); + GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3); + GRUB_MD_MD5->write (ctx, entered, enteredlen); + digest = GRUB_MD_MD5->read (ctx); + GRUB_MD_MD5->final (ctx); + grub_memcpy (alt_result, digest, MD5_HASHLEN); + + GRUB_MD_MD5->init (ctx); + GRUB_MD_MD5->write (ctx, entered, enteredlen); + GRUB_MD_MD5->write (ctx, pw->salt, pw->saltlen); /* include the $1$ header */ + for (i = enteredlen; i > 16; i -= 16) + GRUB_MD_MD5->write (ctx, alt_result, 16); + GRUB_MD_MD5->write (ctx, alt_result, i); + + for (i = enteredlen; i > 0; i >>= 1) + GRUB_MD_MD5->write (ctx, entered + ((i & 1) ? enteredlen : 0), 1); + digest = GRUB_MD_MD5->read (ctx); + GRUB_MD_MD5->final (ctx); + + for (i = 0; i < 1000; i++) + { + grub_memcpy (alt_result, digest, 16); + + GRUB_MD_MD5->init (ctx); + if ((i & 1) != 0) + GRUB_MD_MD5->write (ctx, entered, enteredlen); + else + GRUB_MD_MD5->write (ctx, alt_result, 16); + + if (i % 3 != 0) + GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3); + + if (i % 7 != 0) + GRUB_MD_MD5->write (ctx, entered, enteredlen); + + if ((i & 1) != 0) + GRUB_MD_MD5->write (ctx, alt_result, 16); + else + GRUB_MD_MD5->write (ctx, entered, enteredlen); + digest = GRUB_MD_MD5->read (ctx); + GRUB_MD_MD5->final (ctx); + } + + ret = (grub_crypto_memcmp (digest, pw->hash, MD5_HASHLEN) == 0); + grub_free (ctx); + return ret; +} + +static grub_err_t +check_password_md5 (const char *user, + const char *entered, + void *password) +{ + if (!check_password_md5_real (entered, password)) + return GRUB_ACCESS_DENIED; + + grub_auth_authenticate (user); + + return GRUB_ERR_NONE; +} + +static inline int +ib64t (char c) +{ + if (c == '.') + return 0; + if (c == '/') + return 1; + if (c >= '0' && c <= '9') + return c - '0' + 2; + if (c >= 'A' && c <= 'Z') + return c - 'A' + 12; + if (c >= 'a' && c <= 'z') + return c - 'a' + 38; + return -1; +} + +static struct legacy_md5_password * +parse_legacy_md5 (int argc, char **args) +{ + const char *salt, *saltend; + struct legacy_md5_password *pw = NULL; + int i; + const char *p; + + if (grub_memcmp (args[0], "--md5", sizeof ("--md5")) != 0) + goto fail; + if (argc == 1) + goto fail; + if (grub_strlen(args[1]) <= 3) + goto fail; + salt = args[1]; + saltend = grub_strchr (salt + 3, '$'); + if (!saltend) + goto fail; + pw = grub_malloc (sizeof (*pw)); + if (!pw) + goto fail; + + p = saltend + 1; + for (i = 0; i < 5; i++) + { + int n; + grub_uint32_t w = 0; + + for (n = 0; n < 4; n++) + { + int ww = ib64t(*p++); + if (ww == -1) + goto fail; + w |= ww << (n * 6); + } + pw->hash[i == 4 ? 5 : 12+i] = w & 0xff; + pw->hash[6+i] = (w >> 8) & 0xff; + pw->hash[i] = (w >> 16) & 0xff; + } + { + int n; + grub_uint32_t w = 0; + for (n = 0; n < 2; n++) + { + int ww = ib64t(*p++); + if (ww == -1) + goto fail; + w |= ww << (6 * n); + } + if (w >= 0x100) + goto fail; + pw->hash[11] = w; + } + + pw->saltlen = saltend - salt; + pw->salt = (grub_uint8_t *) grub_strndup (salt, pw->saltlen); + if (!pw->salt) + goto fail; + + return pw; + + fail: + grub_free (pw); + return NULL; +} + +static grub_err_t +grub_cmd_legacy_password (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + struct legacy_md5_password *pw = NULL; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + if (args[0][0] != '-' || args[0][1] != '-') + return grub_normal_set_password ("legacy", args[0]); + + pw = parse_legacy_md5 (argc, args); + + if (pw) + return grub_auth_register_authentication ("legacy", check_password_md5, pw); + else + /* This is to imitate minor difference between grub-legacy in GRUB2. + If 2 password commands are executed in a row and second one fails + on GRUB2 the password of first one is used, whereas in grub-legacy + authenthication is denied. In case of no password command was executed + early both versions deny any access. */ + return grub_auth_register_authentication ("legacy", check_password_deny, + NULL); +} + +int +grub_legacy_check_md5_password (int argc, char **args, + char *entered) +{ + struct legacy_md5_password *pw = NULL; + int ret; + + if (args[0][0] != '-' || args[0][1] != '-') + { + char correct[GRUB_AUTH_MAX_PASSLEN]; + + grub_memset (correct, 0, sizeof (correct)); + grub_strncpy (correct, args[0], sizeof (correct)); + + return grub_crypto_memcmp (entered, correct, GRUB_AUTH_MAX_PASSLEN) == 0; + } + + pw = parse_legacy_md5 (argc, args); + + if (!pw) + return 0; + + ret = check_password_md5_real (entered, pw); + grub_free (pw); + return ret; +} + +static grub_err_t +grub_cmd_legacy_check_password (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + char entered[GRUB_AUTH_MAX_PASSLEN]; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + grub_puts_ (N_("Enter password: ")); + if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN)) + return GRUB_ACCESS_DENIED; + + if (!grub_legacy_check_md5_password (argc, args, + entered)) + return GRUB_ACCESS_DENIED; + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_source, cmd_configfile; +static grub_command_t cmd_source_extract, cmd_configfile_extract; +static grub_command_t cmd_kernel, cmd_initrd, cmd_initrdnounzip; +static grub_command_t cmd_password, cmd_check_password; + +GRUB_MOD_INIT(legacycfg) +{ + cmd_source + = grub_register_command ("legacy_source", + grub_cmd_legacy_source, + N_("FILE"), + /* TRANSLATORS: "legacy config" means + "config as used by grub-legacy". */ + N_("Parse legacy config in same context")); + cmd_configfile + = grub_register_command ("legacy_configfile", + grub_cmd_legacy_source, + N_("FILE"), + N_("Parse legacy config in new context")); + cmd_source_extract + = grub_register_command ("extract_legacy_entries_source", + grub_cmd_legacy_source, + N_("FILE"), + N_("Parse legacy config in same context taking only menu entries")); + cmd_configfile_extract + = grub_register_command ("extract_legacy_entries_configfile", + grub_cmd_legacy_source, + N_("FILE"), + N_("Parse legacy config in new context taking only menu entries")); + + cmd_kernel = grub_register_command ("legacy_kernel", + grub_cmd_legacy_kernel, + N_("[--no-mem-option] [--type=TYPE] FILE [ARG ...]"), + N_("Simulate grub-legacy `kernel' command")); + + cmd_initrd = grub_register_command ("legacy_initrd", + grub_cmd_legacy_initrd, + N_("FILE [ARG ...]"), + N_("Simulate grub-legacy `initrd' command")); + cmd_initrdnounzip = grub_register_command ("legacy_initrd_nounzip", + grub_cmd_legacy_initrdnounzip, + N_("FILE [ARG ...]"), + N_("Simulate grub-legacy `modulenounzip' command")); + + cmd_password = grub_register_command ("legacy_password", + grub_cmd_legacy_password, + N_("[--md5] PASSWD [FILE]"), + N_("Simulate grub-legacy `password' command")); + + cmd_check_password = grub_register_command ("legacy_check_password", + grub_cmd_legacy_check_password, + N_("[--md5] PASSWD [FILE]"), + N_("Simulate grub-legacy `password' command in menu entry mode")); + +} + +GRUB_MOD_FINI(legacycfg) +{ + grub_unregister_command (cmd_source); + grub_unregister_command (cmd_configfile); + grub_unregister_command (cmd_source_extract); + grub_unregister_command (cmd_configfile_extract); + + grub_unregister_command (cmd_kernel); + grub_unregister_command (cmd_initrd); + grub_unregister_command (cmd_initrdnounzip); + + grub_unregister_command (cmd_password); + grub_unregister_command (cmd_check_password); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/loadenv.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/loadenv.c new file mode 100644 index 0000000..0a2c439 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/loadenv.c @@ -0,0 +1,397 @@ +/* loadenv.c - command to load/save environment variable. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "loadenv.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +static const struct grub_arg_option options[] = + { + /* TRANSLATORS: This option is used to override default filename + for loading and storing environment. */ + {"file", 'f', 0, N_("Specify filename."), 0, ARG_TYPE_PATHNAME}, + {"skip-sig", 's', 0, + N_("Skip signature-checking of the environment file."), 0, ARG_TYPE_NONE}, + {0, 0, 0, 0, 0, 0} + }; + +/* Opens 'filename' with compression filters disabled. Optionally disables the + PUBKEY filter (that insists upon properly signed files) as well. PUBKEY + filter is restored before the function returns. */ +static grub_file_t +open_envblk_file (char *filename, + enum grub_file_type type) +{ + grub_file_t file; + char *buf = 0; + + if (! filename) + { + const char *prefix; + int len; + + prefix = grub_env_get ("prefix"); + if (! prefix) + { + grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix"); + return 0; + } + + len = grub_strlen (prefix); + buf = grub_malloc (len + 1 + sizeof (GRUB_ENVBLK_DEFCFG)); + if (! buf) + return 0; + filename = buf; + + grub_strcpy (filename, prefix); + filename[len] = '/'; + grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG); + } + + file = grub_file_open (filename, type); + + grub_free (buf); + return file; +} + +static grub_err_t +grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + grub_file_t file; + grub_envblk_t envblk; + grub_env_whitelist_t whitelist; + + whitelist.len = argc; + whitelist.list = args; + + /* state[0] is the -f flag; state[1] is the --skip-sig flag */ + file = open_envblk_file ((state[0].set) ? state[0].arg : 0, + GRUB_FILE_TYPE_LOADENV + | (state[1].set + ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE)); + if (! file) + return grub_errno; + + envblk = read_envblk_file (file); + if (! envblk) + goto fail; + + /* argc > 0 indicates caller provided a whitelist of variables to read. */ + grub_envblk_iterate (envblk, argc > 0 ? &whitelist : 0, set_var); + grub_envblk_close (envblk); + + fail: + grub_file_close (file); + return grub_errno; +} + +/* Print all variables in current context. */ +static int +print_var (const char *name, const char *value, + void *hook_data __attribute__ ((unused))) +{ + grub_printf ("%s=%s\n", name, value); + return 0; +} + +static grub_err_t +grub_cmd_list_env (grub_extcmd_context_t ctxt, + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + struct grub_arg_list *state = ctxt->state; + grub_file_t file; + grub_envblk_t envblk; + + file = open_envblk_file ((state[0].set) ? state[0].arg : 0, + GRUB_FILE_TYPE_LOADENV + | (state[1].set + ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE)); + if (! file) + return grub_errno; + + envblk = read_envblk_file (file); + if (! envblk) + goto fail; + + grub_envblk_iterate (envblk, NULL, print_var); + grub_envblk_close (envblk); + + fail: + grub_file_close (file); + return grub_errno; +} + +/* Used to maintain a variable length of blocklists internally. */ +struct blocklist +{ + grub_disk_addr_t sector; + unsigned offset; + unsigned length; + struct blocklist *next; +}; + +static void +free_blocklists (struct blocklist *p) +{ + struct blocklist *q; + + for (; p; p = q) + { + q = p->next; + grub_free (p); + } +} + +static grub_err_t +check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, + grub_file_t file) +{ + grub_size_t total_length; + grub_size_t index; + grub_disk_t disk; + grub_disk_addr_t part_start; + struct blocklist *p; + char *buf; + + /* Sanity checks. */ + total_length = 0; + for (p = blocklists; p; p = p->next) + { + struct blocklist *q; + /* Check if any pair of blocks overlap. */ + for (q = p->next; q; q = q->next) + { + grub_disk_addr_t s1, s2; + grub_disk_addr_t e1, e2; + + s1 = p->sector; + e1 = s1 + ((p->length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); + + s2 = q->sector; + e2 = s2 + ((q->length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); + + if (s1 < e2 && s2 < e1) + { + /* This might be actually valid, but it is unbelievable that + any filesystem makes such a silly allocation. */ + return grub_error (GRUB_ERR_BAD_FS, "malformed file"); + } + } + + total_length += p->length; + } + + if (total_length != grub_file_size (file)) + { + /* Maybe sparse, unallocated sectors. No way in GRUB. */ + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "sparse file not allowed"); + } + + /* One more sanity check. Re-read all sectors by blocklists, and compare + those with the data read via a file. */ + disk = file->device->disk; + + part_start = grub_partition_get_start (disk->partition); + + buf = grub_envblk_buffer (envblk); + char *blockbuf = NULL; + grub_size_t blockbuf_len = 0; + for (p = blocklists, index = 0; p; index += p->length, p = p->next) + { + if (p->length > blockbuf_len) + { + grub_free (blockbuf); + blockbuf_len = 2 * p->length; + blockbuf = grub_malloc (blockbuf_len); + if (!blockbuf) + return grub_errno; + } + + if (grub_disk_read (disk, p->sector - part_start, + p->offset, p->length, blockbuf)) + return grub_errno; + + if (grub_memcmp (buf + index, blockbuf, p->length) != 0) + return grub_error (GRUB_ERR_FILE_READ_ERROR, "invalid blocklist"); + } + + return GRUB_ERR_NONE; +} + +static int +write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, + grub_file_t file) +{ + char *buf; + grub_disk_t disk; + grub_disk_addr_t part_start; + struct blocklist *p; + grub_size_t index; + + buf = grub_envblk_buffer (envblk); + disk = file->device->disk; + part_start = grub_partition_get_start (disk->partition); + + index = 0; + for (p = blocklists; p; index += p->length, p = p->next) + { + if (grub_disk_write (disk, p->sector - part_start, + p->offset, p->length, buf + index)) + return 0; + } + + return 1; +} + +/* Context for grub_cmd_save_env. */ +struct grub_cmd_save_env_ctx +{ + struct blocklist *head, *tail; +}; + +/* Store blocklists in a linked list. */ +static void +save_env_read_hook (grub_disk_addr_t sector, unsigned offset, unsigned length, + void *data) +{ + struct grub_cmd_save_env_ctx *ctx = data; + struct blocklist *block; + + block = grub_malloc (sizeof (*block)); + if (! block) + return; + + block->sector = sector; + block->offset = offset; + block->length = length; + + /* Slightly complicated, because the list should be FIFO. */ + block->next = 0; + if (ctx->tail) + ctx->tail->next = block; + ctx->tail = block; + if (! ctx->head) + ctx->head = block; +} + +static grub_err_t +grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + grub_file_t file; + grub_envblk_t envblk; + struct grub_cmd_save_env_ctx ctx = { + .head = 0, + .tail = 0 + }; + + if (! argc) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified"); + + file = open_envblk_file ((state[0].set) ? state[0].arg : 0, + GRUB_FILE_TYPE_SAVEENV + | GRUB_FILE_TYPE_SKIP_SIGNATURE); + if (! file) + return grub_errno; + + if (! file->device->disk) + { + grub_file_close (file); + return grub_error (GRUB_ERR_BAD_DEVICE, "disk device required"); + } + + file->read_hook = save_env_read_hook; + file->read_hook_data = &ctx; + envblk = read_envblk_file (file); + file->read_hook = 0; + if (! envblk) + goto fail; + + if (check_blocklists (envblk, ctx.head, file)) + goto fail; + + while (argc) + { + const char *value; + + value = grub_env_get (args[0]); + if (value) + { + if (! grub_envblk_set (envblk, args[0], value)) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "environment block too small"); + goto fail; + } + } + else + grub_envblk_delete (envblk, args[0]); + + argc--; + args++; + } + + write_blocklists (envblk, ctx.head, file); + + fail: + if (envblk) + grub_envblk_close (envblk); + free_blocklists (ctx.head); + grub_file_close (file); + return grub_errno; +} + +static grub_extcmd_t cmd_load, cmd_list, cmd_save; + +GRUB_MOD_INIT(loadenv) +{ + cmd_load = + grub_register_extcmd ("load_env", grub_cmd_load_env, 0, + N_("[-f FILE] [-s|--skip-sig] [variable_name_to_whitelist] [...]"), + N_("Load variables from environment block file."), + options); + cmd_list = + grub_register_extcmd ("list_env", grub_cmd_list_env, 0, N_("[-f FILE]"), + N_("List variables from environment block file."), + options); + cmd_save = + grub_register_extcmd ("save_env", grub_cmd_save_env, 0, + N_("[-f FILE] variable_name [...]"), + N_("Save variables to environment block file."), + options); +} + +GRUB_MOD_FINI(loadenv) +{ + grub_unregister_extcmd (cmd_load); + grub_unregister_extcmd (cmd_list); + grub_unregister_extcmd (cmd_save); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/loadenv.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/loadenv.h new file mode 100644 index 0000000..6a7da2d --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/loadenv.h @@ -0,0 +1,93 @@ +/* loadenv.c - command to load/save environment variable. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +static grub_envblk_t UNUSED +read_envblk_file (grub_file_t file) +{ + grub_off_t offset = 0; + char *buf; + grub_size_t size = grub_file_size (file); + grub_envblk_t envblk; + + buf = grub_malloc (size); + if (! buf) + return 0; + + while (size > 0) + { + grub_ssize_t ret; + + ret = grub_file_read (file, buf + offset, size); + if (ret <= 0) + { + grub_free (buf); + return 0; + } + + size -= ret; + offset += ret; + } + + envblk = grub_envblk_open (buf, offset); + if (! envblk) + { + grub_free (buf); + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); + return 0; + } + + return envblk; +} + +struct grub_env_whitelist +{ + grub_size_t len; + char **list; +}; +typedef struct grub_env_whitelist grub_env_whitelist_t; + +static int UNUSED +test_whitelist_membership (const char* name, + const grub_env_whitelist_t* whitelist) +{ + grub_size_t i; + + for (i = 0; i < whitelist->len; i++) + if (grub_strcmp (name, whitelist->list[i]) == 0) + return 1; /* found it */ + + return 0; /* not found */ +} + +/* Helper for grub_cmd_load_env. */ +static int UNUSED +set_var (const char *name, const char *value, void *whitelist) +{ + if (! whitelist) + { + grub_env_set (name, value); + return 0; + } + + if (test_whitelist_membership (name, + (const grub_env_whitelist_t *) whitelist)) + grub_env_set (name, value); + + return 0; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/menuentry.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/menuentry.c new file mode 100644 index 0000000..64a055a --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/menuentry.c @@ -0,0 +1,349 @@ +/* menuentry.c - menuentry command */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +static const struct grub_arg_option options[] = + { + {"class", 1, GRUB_ARG_OPTION_REPEATABLE, + N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING}, + {"users", 2, 0, + N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"), + ARG_TYPE_STRING}, + {"hotkey", 3, 0, + N_("Keyboard key to quickly boot this entry."), N_("KEYBOARD_KEY"), ARG_TYPE_STRING}, + {"source", 4, 0, + N_("Use STRING as menu entry body."), N_("STRING"), ARG_TYPE_STRING}, + {"id", 0, 0, N_("Menu entry identifier."), N_("STRING"), ARG_TYPE_STRING}, + /* TRANSLATORS: menu entry can either be bootable by anyone or only by + handful of users. By default when security is active only superusers can + boot a given menu entry. With --unrestricted (this option) + anyone can boot it. */ + {"unrestricted", 0, 0, N_("This entry can be booted by any user."), + 0, ARG_TYPE_NONE}, + {0, 0, 0, 0, 0, 0} + }; + +static struct +{ + const char *name; + int key; +} hotkey_aliases[] = + { + {"backspace", GRUB_TERM_BACKSPACE}, + {"tab", GRUB_TERM_TAB}, + {"delete", GRUB_TERM_KEY_DC}, + {"insert", GRUB_TERM_KEY_INSERT}, + {"f1", GRUB_TERM_KEY_F1}, + {"f2", GRUB_TERM_KEY_F2}, + {"f3", GRUB_TERM_KEY_F3}, + {"f4", GRUB_TERM_KEY_F4}, + {"f5", GRUB_TERM_KEY_F5}, + {"f6", GRUB_TERM_KEY_F6}, + {"f7", GRUB_TERM_KEY_F7}, + {"f8", GRUB_TERM_KEY_F8}, + {"f9", GRUB_TERM_KEY_F9}, + {"f10", GRUB_TERM_KEY_F10}, + {"f11", GRUB_TERM_KEY_F11}, + {"f12", GRUB_TERM_KEY_F12}, + }; + +/* Add a menu entry to the current menu context (as given by the environment + variable data slot `menu'). As the configuration file is read, the script + parser calls this when a menu entry is to be created. */ +grub_err_t +grub_normal_add_menu_entry (int argc, const char **args, + char **classes, const char *id, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode, + int submenu, int *index, struct bls_entry *bls) +{ + int menu_hotkey = 0; + char **menu_args = NULL; + char *menu_users = NULL; + char *menu_title = NULL; + char *menu_sourcecode = NULL; + char *menu_id = NULL; + struct grub_menu_entry_class *menu_classes = NULL; + + grub_menu_t menu; + grub_menu_entry_t *last; + + menu = grub_env_get_menu (); + if (! menu) + return grub_error (GRUB_ERR_MENU, "no menu context"); + + last = &menu->entry_list; + + menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode); + if (! menu_sourcecode) + return grub_errno; + + if (classes && classes[0]) + { + int i; + for (i = 0; classes[i]; i++); /* count # of menuentry classes */ + menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class) + * (i + 1)); + if (! menu_classes) + goto fail; + + for (i = 0; classes[i]; i++) + { + menu_classes[i].name = grub_strdup (classes[i]); + if (! menu_classes[i].name) + goto fail; + menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL; + } + } + + if (users) + { + menu_users = grub_strdup (users); + if (! menu_users) + goto fail; + } + + if (hotkey) + { + unsigned i; + for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++) + if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0) + { + menu_hotkey = hotkey_aliases[i].key; + break; + } + if (i == ARRAY_SIZE (hotkey_aliases)) + menu_hotkey = hotkey[0]; + } + + if (! argc) + { + grub_error (GRUB_ERR_MENU, "menuentry is missing title"); + goto fail; + } + + menu_title = grub_strdup (args[0]); + if (! menu_title) + goto fail; + + grub_dprintf ("menu", "id:\"%s\"\n", id); + grub_dprintf ("menu", "title:\"%s\"\n", menu_title); + menu_id = grub_strdup (id ? : menu_title); + if (! menu_id) + goto fail; + grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id); + + /* Save argc, args to pass as parameters to block arg later. */ + menu_args = grub_malloc (sizeof (char*) * (argc + 1)); + if (! menu_args) + goto fail; + + { + int i; + for (i = 0; i < argc; i++) + { + menu_args[i] = grub_strdup (args[i]); + if (! menu_args[i]) + goto fail; + } + menu_args[argc] = NULL; + } + + /* Add the menu entry at the end of the list. */ + int ind=0; + while (*last) + { + ind++; + last = &(*last)->next; + } + + *last = grub_zalloc (sizeof (**last)); + if (! *last) + goto fail; + + (*last)->title = menu_title; + (*last)->id = menu_id; + (*last)->hotkey = menu_hotkey; + (*last)->classes = menu_classes; + if (menu_users) + (*last)->restricted = 1; + (*last)->users = menu_users; + (*last)->argc = argc; + (*last)->args = menu_args; + (*last)->sourcecode = menu_sourcecode; + (*last)->submenu = submenu; + (*last)->bls = bls; + + menu->size++; + if (index) + *index = ind; + return GRUB_ERR_NONE; + + fail: + + grub_free (menu_sourcecode); + { + int i; + for (i = 0; menu_classes && menu_classes[i].name; i++) + grub_free (menu_classes[i].name); + grub_free (menu_classes); + } + + { + int i; + for (i = 0; menu_args && menu_args[i]; i++) + grub_free (menu_args[i]); + grub_free (menu_args); + } + + grub_free (menu_users); + grub_free (menu_title); + grub_free (menu_id); + return grub_errno; +} + +static char * +setparams_prefix (int argc, char **args) +{ + int i; + int j; + char *p; + char *result; + grub_size_t len = 10; + + /* Count resulting string length */ + for (i = 0; i < argc; i++) + { + len += 3; /* 3 = 1 space + 2 quotes */ + p = args[i]; + while (*p) + len += (*p++ == '\'' ? 3 : 1); + } + + result = grub_malloc (len + 2); + if (! result) + return 0; + + grub_strcpy (result, "setparams"); + p = result + 9; + + for (j = 0; j < argc; j++) + { + *p++ = ' '; + *p++ = '\''; + p = grub_strchrsub (p, args[j], '\'', "'\\''"); + *p++ = '\''; + } + *p++ = '\n'; + *p = '\0'; + return result; +} + +static grub_err_t +grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) +{ + char ch; + char *src; + char *prefix; + unsigned len; + grub_err_t r; + const char *users; + + if (! argc) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments"); + + if (ctxt->state[3].set && ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions"); + + if (! ctxt->state[3].set && ! ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition"); + + if (ctxt->state[1].set) + users = ctxt->state[1].arg; + else if (ctxt->state[5].set) + users = NULL; + else + users = ""; + + if (! ctxt->script) + return grub_normal_add_menu_entry (argc, (const char **) args, + (ctxt->state[0].set ? ctxt->state[0].args + : NULL), + ctxt->state[4].arg, + users, + ctxt->state[2].arg, 0, + ctxt->state[3].arg, + ctxt->extcmd->cmd->name[0] == 's', + NULL, NULL); + + src = args[argc - 1]; + args[argc - 1] = NULL; + + len = grub_strlen(src); + ch = src[len - 1]; + src[len - 1] = '\0'; + + prefix = setparams_prefix (argc - 1, args); + if (! prefix) + return grub_errno; + + r = grub_normal_add_menu_entry (argc - 1, (const char **) args, + ctxt->state[0].args, ctxt->state[4].arg, + users, + ctxt->state[2].arg, prefix, src + 1, + ctxt->extcmd->cmd->name[0] == 's', NULL, + NULL); + + src[len - 1] = ch; + args[argc - 1] = src; + grub_free (prefix); + return r; +} + +static grub_extcmd_t cmd, cmd_sub; + +void +grub_menu_init (void) +{ + cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry, + GRUB_COMMAND_FLAG_BLOCKS + | GRUB_COMMAND_ACCEPT_DASH + | GRUB_COMMAND_FLAG_EXTRACTOR, + N_("BLOCK"), N_("Define a menu entry."), options); + cmd_sub = grub_register_extcmd ("submenu", grub_cmd_menuentry, + GRUB_COMMAND_FLAG_BLOCKS + | GRUB_COMMAND_ACCEPT_DASH + | GRUB_COMMAND_FLAG_EXTRACTOR, + N_("BLOCK"), N_("Define a submenu."), + options); +} + +void +grub_menu_fini (void) +{ + grub_unregister_extcmd (cmd); + grub_unregister_extcmd (cmd_sub); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/search.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/search.c new file mode 100644 index 0000000..db2eb33 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/search.c @@ -0,0 +1,353 @@ +/* search.c - search devices based on a file or a filesystem label */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static int g_no_vtoyefi_part = 0; +static char g_vtoyefi_dosname[64]; +static char g_vtoyefi_gptname[64]; + +struct cache_entry +{ + struct cache_entry *next; + char *key; + char *value; +}; + +static struct cache_entry *cache; + +/* Context for FUNC_NAME. */ +struct search_ctx +{ + const char *key; + const char *var; + int no_floppy; + char **hints; + unsigned nhints; + int count; + int is_cache; +}; + +/* Helper for FUNC_NAME. */ +static int +iterate_device (const char *name, void *data) +{ + struct search_ctx *ctx = data; + int found = 0; + + /* Skip floppy drives when requested. */ + if (ctx->no_floppy && + name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') + return 0; + + if (g_no_vtoyefi_part && (grub_strcmp(name, g_vtoyefi_dosname) == 0 || grub_strcmp(name, g_vtoyefi_gptname) == 0)) { + return 0; + } + +#ifdef DO_SEARCH_FS_UUID +#define compare_fn grub_strcasecmp +#else +#define compare_fn grub_strcmp +#endif + +#ifdef DO_SEARCH_FILE + { + char *buf; + grub_file_t file; + + buf = grub_xasprintf ("(%s)%s", name, ctx->key); + if (! buf) + return 1; + + file = grub_file_open (buf, GRUB_FILE_TYPE_FS_SEARCH + | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (file) + { + found = 1; + grub_file_close (file); + } + grub_free (buf); + } +#else + { + /* SEARCH_FS_UUID or SEARCH_LABEL */ + grub_device_t dev; + grub_fs_t fs; + char *quid; + + dev = grub_device_open (name); + if (dev) + { + fs = grub_fs_probe (dev); + +#ifdef DO_SEARCH_FS_UUID +#define read_fn fs_uuid +#else +#define read_fn fs_label +#endif + + if (fs && fs->read_fn) + { + fs->read_fn (dev, &quid); + + if (grub_errno == GRUB_ERR_NONE && quid) + { + if (compare_fn (quid, ctx->key) == 0) + found = 1; + + grub_free (quid); + } + } + + grub_device_close (dev); + } + } +#endif + + if (!ctx->is_cache && found && ctx->count == 0) + { + struct cache_entry *cache_ent; + cache_ent = grub_malloc (sizeof (*cache_ent)); + if (cache_ent) + { + cache_ent->key = grub_strdup (ctx->key); + cache_ent->value = grub_strdup (name); + if (cache_ent->value && cache_ent->key) + { + cache_ent->next = cache; + cache = cache_ent; + } + else + { + grub_free (cache_ent->value); + grub_free (cache_ent->key); + grub_free (cache_ent); + grub_errno = GRUB_ERR_NONE; + } + } + else + grub_errno = GRUB_ERR_NONE; + } + + if (found) + { + ctx->count++; + if (ctx->var) + grub_env_set (ctx->var, name); + else + grub_printf (" %s", name); + } + + grub_errno = GRUB_ERR_NONE; + return (found && ctx->var); +} + +/* Helper for FUNC_NAME. */ +static int +part_hook (grub_disk_t disk, const grub_partition_t partition, void *data) +{ + struct search_ctx *ctx = data; + char *partition_name, *devname; + int ret; + + partition_name = grub_partition_get_name (partition); + if (! partition_name) + return 1; + + devname = grub_xasprintf ("%s,%s", disk->name, partition_name); + grub_free (partition_name); + if (!devname) + return 1; + ret = iterate_device (devname, ctx); + grub_free (devname); + + return ret; +} + +/* Helper for FUNC_NAME. */ +static void +try (struct search_ctx *ctx) +{ + unsigned i; + struct cache_entry **prev; + struct cache_entry *cache_ent; + + for (prev = &cache, cache_ent = *prev; cache_ent; + prev = &cache_ent->next, cache_ent = *prev) + if (compare_fn (cache_ent->key, ctx->key) == 0) + break; + if (cache_ent) + { + ctx->is_cache = 1; + if (iterate_device (cache_ent->value, ctx)) + { + ctx->is_cache = 0; + return; + } + ctx->is_cache = 0; + /* Cache entry was outdated. Remove it. */ + if (!ctx->count) + { + *prev = cache_ent->next; + grub_free (cache_ent->key); + grub_free (cache_ent->value); + grub_free (cache_ent); + } + } + + for (i = 0; i < ctx->nhints; i++) + { + char *end; + if (!ctx->hints[i][0]) + continue; + end = ctx->hints[i] + grub_strlen (ctx->hints[i]) - 1; + if (*end == ',') + *end = 0; + if (iterate_device (ctx->hints[i], ctx)) + { + if (!*end) + *end = ','; + return; + } + if (!*end) + { + grub_device_t dev; + int ret; + dev = grub_device_open (ctx->hints[i]); + if (!dev) + { + if (!*end) + *end = ','; + continue; + } + if (!dev->disk) + { + grub_device_close (dev); + if (!*end) + *end = ','; + continue; + } + ret = grub_partition_iterate (dev->disk, part_hook, ctx); + if (!*end) + *end = ','; + grub_device_close (dev); + if (ret) + return; + } + } + grub_device_iterate (iterate_device, ctx); +} + +void +FUNC_NAME (const char *key, const char *var, int no_floppy, + char **hints, unsigned nhints) +{ + struct search_ctx ctx = { + .key = key, + .var = var, + .no_floppy = no_floppy, + .hints = hints, + .nhints = nhints, + .count = 0, + .is_cache = 0 + }; + grub_fs_autoload_hook_t saved_autoload; + + g_no_vtoyefi_part = 0; + if (grub_env_get("VTOY_SEARCH_NO_VTOYEFI")) + { + grub_snprintf(g_vtoyefi_dosname, sizeof(g_vtoyefi_dosname), "%s,msdos2", grub_env_get("vtoydev")); + grub_snprintf(g_vtoyefi_gptname, sizeof(g_vtoyefi_gptname), "%s,gpt2", grub_env_get("vtoydev")); + g_no_vtoyefi_part = 1; + } + + /* First try without autoloading if we're setting variable. */ + if (var) + { + saved_autoload = grub_fs_autoload_hook; + grub_fs_autoload_hook = 0; + try (&ctx); + + /* Restore autoload hook. */ + grub_fs_autoload_hook = saved_autoload; + + /* Retry with autoload if nothing found. */ + if (grub_errno == GRUB_ERR_NONE && ctx.count == 0) + try (&ctx); + } + else + try (&ctx); + + if (grub_errno == GRUB_ERR_NONE && ctx.count == 0) + grub_error (GRUB_ERR_FILE_NOT_FOUND, "no such device: %s", key); +} + +static grub_err_t +grub_cmd_do_search (grub_command_t cmd __attribute__ ((unused)), int argc, + char **args) +{ + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + + FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0, (args + 2), + argc > 2 ? argc - 2 : 0); + + return grub_errno; +} + +static grub_command_t cmd; + +#ifdef DO_SEARCH_FILE +GRUB_MOD_INIT(search_fs_file) +#elif defined (DO_SEARCH_FS_UUID) +GRUB_MOD_INIT(search_fs_uuid) +#else +GRUB_MOD_INIT(search_label) +#endif +{ + cmd = + grub_register_command (COMMAND_NAME, grub_cmd_do_search, + N_("NAME [VARIABLE] [HINTS]"), + HELP_MESSAGE); +} + +#ifdef DO_SEARCH_FILE +GRUB_MOD_FINI(search_fs_file) +#elif defined (DO_SEARCH_FS_UUID) +GRUB_MOD_FINI(search_fs_uuid) +#else +GRUB_MOD_FINI(search_label) +#endif +{ + grub_unregister_command (cmd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/smbios.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/smbios.c new file mode 100644 index 0000000..b196c8d --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/smbios.c @@ -0,0 +1,399 @@ +/* smbios.c - retrieve smbios information. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2019 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* Abstract useful values found in either the SMBIOS3 or SMBIOS EPS. */ +static struct { + grub_addr_t start; + grub_addr_t end; + grub_uint16_t structures; +} table_desc; + +static grub_extcmd_t cmd; + +/* Locate the SMBIOS entry point structure depending on the hardware. */ +struct grub_smbios_eps * +grub_smbios_get_eps (void) +{ + static struct grub_smbios_eps *eps = NULL; + + if (eps != NULL) + return eps; + + eps = grub_machine_smbios_get_eps (); + + return eps; +} + +/* Locate the SMBIOS3 entry point structure depending on the hardware. */ +static struct grub_smbios_eps3 * +grub_smbios_get_eps3 (void) +{ + static struct grub_smbios_eps3 *eps = NULL; + + if (eps != NULL) + return eps; + + eps = grub_machine_smbios_get_eps3 (); + + return eps; +} + +static char * +linux_string (const char *value) +{ + char *out = grub_malloc( grub_strlen (value) + 1); + const char *src = value; + char *dst = out; + + for (; *src; src++) + if (*src > ' ' && *src < 127 && *src != ':') + *dst++ = *src; + + *dst = 0; + return out; +} + +/* + * These functions convert values from the various SMBIOS structure field types + * into a string formatted to be returned to the user. They expect that the + * structure and offset were already validated. When the requested data is + * successfully retrieved and formatted, the pointer to the string is returned; + * otherwise, NULL is returned on failure. Don't free the result. + */ + +static const char * +grub_smbios_format_byte (const grub_uint8_t *structure, grub_uint8_t offset) +{ + static char buffer[sizeof ("255")]; + + grub_snprintf (buffer, sizeof (buffer), "%u", structure[offset]); + + return (const char *)buffer; +} + +static const char * +grub_smbios_format_word (const grub_uint8_t *structure, grub_uint8_t offset) +{ + static char buffer[sizeof ("65535")]; + + grub_uint16_t value = grub_get_unaligned16 (structure + offset); + grub_snprintf (buffer, sizeof (buffer), "%u", value); + + return (const char *)buffer; +} + +static const char * +grub_smbios_format_dword (const grub_uint8_t *structure, grub_uint8_t offset) +{ + static char buffer[sizeof ("4294967295")]; + + grub_uint32_t value = grub_get_unaligned32 (structure + offset); + grub_snprintf (buffer, sizeof (buffer), "%" PRIuGRUB_UINT32_T, value); + + return (const char *)buffer; +} + +static const char * +grub_smbios_format_qword (const grub_uint8_t *structure, grub_uint8_t offset) +{ + static char buffer[sizeof ("18446744073709551615")]; + + grub_uint64_t value = grub_get_unaligned64 (structure + offset); + grub_snprintf (buffer, sizeof (buffer), "%" PRIuGRUB_UINT64_T, value); + + return (const char *)buffer; +} + +static const char * +grub_smbios_get_string (const grub_uint8_t *structure, grub_uint8_t offset) +{ + const grub_uint8_t *ptr = structure + structure[1]; + const grub_uint8_t *table_end = (const grub_uint8_t *)table_desc.end; + const grub_uint8_t referenced_string_number = structure[offset]; + grub_uint8_t i; + + /* A string referenced with zero is interpreted as unset. */ + if (referenced_string_number == 0) + return NULL; + + /* Search the string set. */ + for (i = 1; *ptr != 0 && ptr < table_end; i++) + if (i == referenced_string_number) + { + const char *str = (const char *)ptr; + while (*ptr++ != 0) + if (ptr >= table_end) + return NULL; /* The string isn't terminated. */ + return str; + } + else + while (*ptr++ != 0 && ptr < table_end); + + /* The string number is greater than the number of strings in the set. */ + return NULL; +} + +static const char * +grub_smbios_format_uuid (const grub_uint8_t *structure, grub_uint8_t offset) +{ + static char buffer[sizeof ("ffffffff-ffff-ffff-ffff-ffffffffffff")]; + const grub_uint8_t *f = structure + offset; /* little-endian fields */ + const grub_uint8_t *g = f + 8; /* byte-by-byte fields */ + + grub_snprintf (buffer, sizeof (buffer), + "%02x%02x%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x", + f[3], f[2], f[1], f[0], f[5], f[4], f[7], f[6], + g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7]); + + return (const char *)buffer; +} + +/* List the field formatting functions and the number of bytes they need. */ +static const struct { + const char *(*format) (const grub_uint8_t *structure, grub_uint8_t offset); + grub_uint8_t field_length; +} field_extractors[] = { + {grub_smbios_format_byte, 1}, + {grub_smbios_format_word, 2}, + {grub_smbios_format_dword, 4}, + {grub_smbios_format_qword, 8}, + {grub_smbios_get_string, 1}, + {grub_smbios_format_uuid, 16} +}; + +/* List command options, with structure field getters ordered as above. */ +#define FIRST_GETTER_OPT (3) +#define SETTER_OPT (FIRST_GETTER_OPT + ARRAY_SIZE(field_extractors)) +#define LINUX_OPT (FIRST_GETTER_OPT + ARRAY_SIZE(field_extractors) + 1) + +static const struct grub_arg_option options[] = { + {"type", 't', 0, N_("Match structures with the given type."), + N_("type"), ARG_TYPE_INT}, + {"handle", 'h', 0, N_("Match structures with the given handle."), + N_("handle"), ARG_TYPE_INT}, + {"match", 'm', 0, N_("Select a structure when several match."), + N_("match"), ARG_TYPE_INT}, + {"get-byte", 'b', 0, N_("Get the byte's value at the given offset."), + N_("offset"), ARG_TYPE_INT}, + {"get-word", 'w', 0, N_("Get two bytes' value at the given offset."), + N_("offset"), ARG_TYPE_INT}, + {"get-dword", 'd', 0, N_("Get four bytes' value at the given offset."), + N_("offset"), ARG_TYPE_INT}, + {"get-qword", 'q', 0, N_("Get eight bytes' value at the given offset."), + N_("offset"), ARG_TYPE_INT}, + {"get-string", 's', 0, N_("Get the string specified at the given offset."), + N_("offset"), ARG_TYPE_INT}, + {"get-uuid", 'u', 0, N_("Get the UUID's value at the given offset."), + N_("offset"), ARG_TYPE_INT}, + {"set", '\0', 0, N_("Store the value in the given variable name."), + N_("variable"), ARG_TYPE_STRING}, + {"linux", '\0', 0, N_("Filter the result like linux does."), + N_("variable"), ARG_TYPE_NONE}, + {0, 0, 0, 0, 0, 0} +}; + +/* + * Return a matching SMBIOS structure. + * + * This method can use up to three criteria for selecting a structure: + * - The "type" field (use -1 to ignore) + * - The "handle" field (use -1 to ignore) + * - Which to return if several match (use 0 to ignore) + * + * The return value is a pointer to the first matching structure. If no + * structures match the given parameters, NULL is returned. + */ +static const grub_uint8_t * +grub_smbios_match_structure (const grub_int16_t type, + const grub_int32_t handle, + const grub_uint16_t match) +{ + const grub_uint8_t *ptr = (const grub_uint8_t *)table_desc.start; + const grub_uint8_t *table_end = (const grub_uint8_t *)table_desc.end; + grub_uint16_t structures = table_desc.structures; + grub_uint16_t structure_count = 0; + grub_uint16_t matches = 0; + + while (ptr < table_end + && ptr[1] >= 4 /* Valid structures include the 4-byte header. */ + && (structure_count++ < structures || structures == 0)) + { + grub_uint16_t structure_handle = grub_get_unaligned16 (ptr + 2); + grub_uint8_t structure_type = ptr[0]; + + if ((handle < 0 || handle == structure_handle) + && (type < 0 || type == structure_type) + && (match == 0 || match == ++matches)) + return ptr; + else + { + ptr += ptr[1]; + while ((*ptr++ != 0 || *ptr++ != 0) && ptr < table_end); + } + + if (structure_type == GRUB_SMBIOS_TYPE_END_OF_TABLE) + break; + } + + return NULL; +} + +static grub_err_t +grub_cmd_smbios (grub_extcmd_context_t ctxt, + int argc __attribute__ ((unused)), + char **argv __attribute__ ((unused))) +{ + struct grub_arg_list *state = ctxt->state; + + grub_int16_t type = -1; + grub_int32_t handle = -1; + grub_uint16_t match = 0; + grub_uint8_t offset = 0; + + const grub_uint8_t *structure; + const char *value; + char *modified_value = NULL; + grub_int32_t option; + grub_int8_t field_type = -1; + grub_uint8_t i; + + if (table_desc.start == 0) + return grub_error (GRUB_ERR_IO, + N_("the SMBIOS entry point structure was not found")); + + /* Read the given filtering options. */ + if (state[0].set) + { + option = grub_strtol (state[0].arg, NULL, 0); + if (option < 0 || option > 255) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("the type must be between 0 and 255")); + type = (grub_int16_t)option; + } + if (state[1].set) + { + option = grub_strtol (state[1].arg, NULL, 0); + if (option < 0 || option > 65535) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("the handle must be between 0 and 65535")); + handle = (grub_int32_t)option; + } + if (state[2].set) + { + option = grub_strtol (state[2].arg, NULL, 0); + if (option <= 0 || option > 65535) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("the match must be a positive integer")); + match = (grub_uint16_t)option; + } + + /* Determine the data type of the structure field to retrieve. */ + for (i = 0; i < ARRAY_SIZE(field_extractors); i++) + if (state[FIRST_GETTER_OPT + i].set) + { + if (field_type >= 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("only one --get option is usable at a time")); + field_type = i; + } + + /* Require a choice of a structure field to return. */ + if (field_type < 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("one of the --get options is required")); + + /* Locate a matching SMBIOS structure. */ + structure = grub_smbios_match_structure (type, handle, match); + if (structure == NULL) + return grub_error (GRUB_ERR_IO, + N_("no structure matched the given options")); + + /* Ensure the requested byte offset is inside the structure. */ + option = grub_strtol (state[FIRST_GETTER_OPT + field_type].arg, NULL, 0); + if (option < 0 || option >= structure[1]) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("the given offset is outside the structure")); + + /* Ensure the requested data type at the offset is inside the structure. */ + offset = (grub_uint8_t)option; + if (offset + field_extractors[field_type].field_length > structure[1]) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("the field ends outside the structure")); + + /* Format the requested structure field into a readable string. */ + value = field_extractors[field_type].format (structure, offset); + if (value == NULL) + return grub_error (GRUB_ERR_IO, + N_("failed to retrieve the structure field")); + + if (state[LINUX_OPT].set) + value = modified_value = linux_string (value); + + /* Store or print the formatted value. */ + if (state[SETTER_OPT].set) + grub_env_set (state[SETTER_OPT].arg, value); + else + grub_printf ("%s\n", value); + + grub_free(modified_value); + + return GRUB_ERR_NONE; +} + +GRUB_MOD_INIT(smbios) +{ + struct grub_smbios_eps3 *eps3; + struct grub_smbios_eps *eps; + + if ((eps3 = grub_smbios_get_eps3 ())) + { + table_desc.start = (grub_addr_t)eps3->table_address; + table_desc.end = table_desc.start + eps3->maximum_table_length; + table_desc.structures = 0; /* SMBIOS3 drops the structure count. */ + } + else if ((eps = grub_smbios_get_eps ())) + { + table_desc.start = (grub_addr_t)eps->intermediate.table_address; + table_desc.end = table_desc.start + eps->intermediate.table_length; + table_desc.structures = eps->intermediate.structures; + } + + cmd = grub_register_extcmd ("smbios", grub_cmd_smbios, 0, + N_("[-t type] [-h handle] [-m match] " + "(-b|-w|-d|-q|-s|-u) offset " + "[--set variable]"), + N_("Retrieve SMBIOS information."), options); +} + +GRUB_MOD_FINI(smbios) +{ + grub_unregister_extcmd (cmd); +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/terminal.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/terminal.c new file mode 100644 index 0000000..7a18119 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/terminal.c @@ -0,0 +1,313 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_uint8_t g_terminal_lock = 0; + +struct grub_term_autoload *grub_term_input_autoload = NULL; +struct grub_term_autoload *grub_term_output_autoload = NULL; + +struct abstract_terminal +{ + struct abstract_terminal *next; + struct abstract_terminal *prev; + const char *name; + grub_err_t (*init) (struct abstract_terminal *term); + grub_err_t (*fini) (struct abstract_terminal *term); +}; + +static grub_err_t +handle_command (int argc, char **args, struct abstract_terminal **enabled, + struct abstract_terminal **disabled, + struct grub_term_autoload *autoloads, + const char *active_str, + const char *available_str) +{ + int i; + struct abstract_terminal *term; + struct grub_term_autoload *aut; + + if (argc == 0) + { + grub_puts_ (active_str); + for (term = *enabled; term; term = term->next) + grub_printf ("%s ", term->name); + grub_printf ("\n"); + grub_puts_ (available_str); + for (term = *disabled; term; term = term->next) + grub_printf ("%s ", term->name); + /* This is quadratic but we don't expect mode than 30 terminal + modules ever. */ + for (aut = autoloads; aut; aut = aut->next) + { + for (term = *disabled; term; term = term->next) + if (grub_strcmp (term->name, aut->name) == 0 + || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*' + && grub_memcmp (term->name, aut->name, + grub_strlen (aut->name) - 1) == 0)) + break; + if (!term) + for (term = *enabled; term; term = term->next) + if (grub_strcmp (term->name, aut->name) == 0 + || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*' + && grub_memcmp (term->name, aut->name, + grub_strlen (aut->name) - 1) == 0)) + break; + if (!term) + grub_printf ("%s ", aut->name); + } + grub_printf ("\n"); + return GRUB_ERR_NONE; + } + i = 0; + + if (grub_strcmp (args[0], "--append") == 0 + || grub_strcmp (args[0], "--remove") == 0) + i++; + + if (i == argc) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no terminal specified")); + + for (; i < argc; i++) + { + int again = 0; + while (1) + { + for (term = *disabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) + break; + if (term == 0) + for (term = *enabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) + break; + if (term) + break; + if (again) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("terminal `%s' isn't found"), + args[i]); + for (aut = autoloads; aut; aut = aut->next) + if (grub_strcmp (args[i], aut->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", aut->name) == 0) + || (aut->name[0] && aut->name[grub_strlen (aut->name) - 1] == '*' + && grub_memcmp (args[i], aut->name, + grub_strlen (aut->name) - 1) == 0)) + { + grub_dl_t mod; + mod = grub_dl_load (aut->modname); + if (mod) + grub_dl_ref (mod); + grub_errno = GRUB_ERR_NONE; + break; + } + if (grub_memcmp (args[i], "serial_usb", + sizeof ("serial_usb") - 1) == 0 + && grub_term_poll_usb) + { + grub_term_poll_usb (1); + again = 1; + continue; + } + if (!aut) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("terminal `%s' isn't found"), + args[i]); + again = 1; + } + } + + if (grub_strcmp (args[0], "--append") == 0) + { + for (i = 1; i < argc; i++) + { + for (term = *disabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) + break; + if (term) + { + if (term->init && term->init (term) != GRUB_ERR_NONE) + return grub_errno; + + grub_list_remove (GRUB_AS_LIST (term)); + grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); + } + } + return GRUB_ERR_NONE; + } + + if (grub_strcmp (args[0], "--remove") == 0) + { + for (i = 1; i < argc; i++) + { + for (term = *enabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) + break; + if (term) + { + if (!term->next && term == *enabled) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "can't remove the last terminal"); + grub_list_remove (GRUB_AS_LIST (term)); + if (term->fini) + term->fini (term); + grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); + } + } + return GRUB_ERR_NONE; + } + for (i = 0; i < argc; i++) + { + for (term = *disabled; term; term = term->next) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) + break; + if (term) + { + if (term->init && term->init (term) != GRUB_ERR_NONE) + return grub_errno; + + grub_list_remove (GRUB_AS_LIST (term)); + grub_list_push (GRUB_AS_LIST_P (enabled), GRUB_AS_LIST (term)); + } + } + + { + struct abstract_terminal *next; + for (term = *enabled; term; term = next) + { + next = term->next; + for (i = 0; i < argc; i++) + if (grub_strcmp (args[i], term->name) == 0 + || (grub_strcmp (args[i], "ofconsole") == 0 + && grub_strcmp ("console", term->name) == 0)) + break; + if (i == argc) + { + if (!term->next && term == *enabled) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "can't remove the last terminal"); + grub_list_remove (GRUB_AS_LIST (term)); + if (term->fini) + term->fini (term); + grub_list_push (GRUB_AS_LIST_P (disabled), GRUB_AS_LIST (term)); + } + } + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_terminal_lock (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + (void)argc; + (void)args; + + if (args[0] && args[0][0] == '1') + g_terminal_lock = 1; + else + g_terminal_lock = 0; + + return 0; +} + +static grub_err_t +grub_cmd_terminal_input (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, next); + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, prev); + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, name); + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, init); + (void) GRUB_FIELD_MATCH (grub_term_inputs, struct abstract_terminal *, fini); + + if (g_terminal_lock) return 0; + + return handle_command (argc, args, + (struct abstract_terminal **) (void *) &grub_term_inputs, + (struct abstract_terminal **) (void *) &grub_term_inputs_disabled, + grub_term_input_autoload, + N_ ("Active input terminals:"), + N_ ("Available input terminals:")); +} + +static grub_err_t +grub_cmd_terminal_output (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, next); + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, prev); + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, name); + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, init); + (void) GRUB_FIELD_MATCH (grub_term_outputs, struct abstract_terminal *, fini); + + if (g_terminal_lock) return 0; + + return handle_command (argc, args, + (struct abstract_terminal **) (void *) &grub_term_outputs, + (struct abstract_terminal **) (void *) &grub_term_outputs_disabled, + grub_term_output_autoload, + N_ ("Active output terminals:"), + N_ ("Available output terminals:")); +} + +static grub_command_t cmd_terminal_input, cmd_terminal_output, cmd_lock_terminal; + +GRUB_MOD_INIT(terminal) +{ + cmd_lock_terminal = + grub_register_command ("terminal_lock", grub_cmd_terminal_lock, + 0, N_("lock terminal.")); + + cmd_terminal_input = + grub_register_command ("terminal_input", grub_cmd_terminal_input, + N_("[--append|--remove] " + "[TERMINAL1] [TERMINAL2] ..."), + N_("List or select an input terminal.")); + cmd_terminal_output = + grub_register_command ("terminal_output", grub_cmd_terminal_output, + N_("[--append|--remove] " + "[TERMINAL1] [TERMINAL2] ..."), + N_("List or select an output terminal.")); +} + +GRUB_MOD_FINI(terminal) +{ + grub_unregister_command (cmd_lock_terminal); + grub_unregister_command (cmd_terminal_input); + grub_unregister_command (cmd_terminal_output); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/test.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/test.c new file mode 100644 index 0000000..74ef5f4 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/commands/test.c @@ -0,0 +1,533 @@ +/* test.c -- The test command.. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static int g_test_case_insensitive = 0; + +/* A simple implementation for signed numbers. */ +static int +grub_strtosl (char *arg, char **end, int base) +{ + if (arg[0] == '-') + return -grub_strtoul (arg + 1, end, base); + return grub_strtoul (arg, end, base); +} + +/* Context for test_parse. */ +struct test_parse_ctx +{ + int invert; + int or, and; + int file_exists; + struct grub_dirhook_info file_info; + char *filename; +}; + +/* Take care of discarding and inverting. */ +static void +update_val (int val, struct test_parse_ctx *ctx) +{ + ctx->and = ctx->and && (ctx->invert ? ! val : val); + ctx->invert = 0; +} + +/* A hook for iterating directories. */ +static int +find_file (const char *cur_filename, const struct grub_dirhook_info *info, + void *data) +{ + int case_insensitive = 0; + struct test_parse_ctx *ctx = data; + + if (g_test_case_insensitive || info->case_insensitive) + case_insensitive = 1; + + if ((case_insensitive ? grub_strcasecmp (cur_filename, ctx->filename) + : grub_strcmp (cur_filename, ctx->filename)) == 0) + { + ctx->file_info = *info; + ctx->file_exists = 1; + return 1; + } + return 0; +} + +/* Check if file exists and fetch its information. */ +static void +get_fileinfo (char *path, struct test_parse_ctx *ctx) +{ + char *pathname; + char *device_name; + grub_fs_t fs; + grub_device_t dev; + + ctx->file_exists = 0; + device_name = grub_file_get_device_name (path); + dev = grub_device_open (device_name); + if (! dev) + { + grub_free (device_name); + return; + } + + fs = grub_fs_probe (dev); + if (! fs) + { + grub_free (device_name); + grub_device_close (dev); + return; + } + + pathname = grub_strchr (path, ')'); + if (! pathname) + pathname = path; + else + pathname++; + + /* Remove trailing '/'. */ + while (*pathname && pathname[grub_strlen (pathname) - 1] == '/') + pathname[grub_strlen (pathname) - 1] = 0; + + /* Split into path and filename. */ + ctx->filename = grub_strrchr (pathname, '/'); + if (! ctx->filename) + { + path = grub_strdup ("/"); + ctx->filename = pathname; + } + else + { + ctx->filename++; + path = grub_strdup (pathname); + path[ctx->filename - pathname] = 0; + } + + /* It's the whole device. */ + if (! *pathname) + { + ctx->file_exists = 1; + grub_memset (&ctx->file_info, 0, sizeof (ctx->file_info)); + /* Root is always a directory. */ + ctx->file_info.dir = 1; + + /* Fetch writing time. */ + ctx->file_info.mtimeset = 0; + if (fs->fs_mtime) + { + if (! fs->fs_mtime (dev, &ctx->file_info.mtime)) + ctx->file_info.mtimeset = 1; + grub_errno = GRUB_ERR_NONE; + } + } + else + (fs->fs_dir) (dev, path, find_file, ctx); + + grub_device_close (dev); + grub_free (path); + grub_free (device_name); +} + +/* Parse a test expression starting from *argn. */ +static int +test_parse (char **args, int *argn, int argc) +{ + struct test_parse_ctx ctx = { + .and = 1, + .or = 0, + .invert = 0 + }; + + /* Here we have the real parsing. */ + while (*argn < argc) + { + /* First try 3 argument tests. */ + if (*argn + 2 < argc) + { + /* String tests. */ + if (grub_strcmp (args[*argn + 1], "=") == 0 + || grub_strcmp (args[*argn + 1], "==") == 0) + { + update_val (grub_strcmp (args[*argn], args[*argn + 2]) == 0, + &ctx); + (*argn) += 3; + continue; + } + + if (grub_strcmp (args[*argn + 1], "!=") == 0) + { + update_val (grub_strcmp (args[*argn], args[*argn + 2]) != 0, + &ctx); + (*argn) += 3; + continue; + } + + /* GRUB extension: lexicographical sorting. */ + if (grub_strcmp (args[*argn + 1], "<") == 0) + { + update_val (grub_strcmp (args[*argn], args[*argn + 2]) < 0, + &ctx); + (*argn) += 3; + continue; + } + + if (grub_strcmp (args[*argn + 1], "<=") == 0) + { + update_val (grub_strcmp (args[*argn], args[*argn + 2]) <= 0, + &ctx); + (*argn) += 3; + continue; + } + + if (grub_strcmp (args[*argn + 1], ">") == 0) + { + update_val (grub_strcmp (args[*argn], args[*argn + 2]) > 0, + &ctx); + (*argn) += 3; + continue; + } + + if (grub_strcmp (args[*argn + 1], ">=") == 0) + { + update_val (grub_strcmp (args[*argn], args[*argn + 2]) >= 0, + &ctx); + (*argn) += 3; + continue; + } + + /* Number tests. */ + if (grub_strcmp (args[*argn + 1], "-eq") == 0) + { + update_val (grub_strtosl (args[*argn], 0, 0) + == grub_strtosl (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + if (grub_strcmp (args[*argn + 1], "-EQ") == 0) + { + update_val (grub_strtoull (args[*argn], 0, 0) + == grub_strtoull (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + + if (grub_strcmp (args[*argn + 1], "-ge") == 0) + { + update_val (grub_strtosl (args[*argn], 0, 0) + >= grub_strtosl (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + if (grub_strcmp (args[*argn + 1], "-GE") == 0) + { + update_val (grub_strtoull (args[*argn], 0, 0) + >= grub_strtoull (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + + if (grub_strcmp (args[*argn + 1], "-gt") == 0) + { + update_val (grub_strtosl (args[*argn], 0, 0) + > grub_strtosl (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + if (grub_strcmp (args[*argn + 1], "-GT") == 0) + { + update_val (grub_strtoull (args[*argn], 0, 0) + > grub_strtoull (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + + if (grub_strcmp (args[*argn + 1], "-le") == 0) + { + update_val (grub_strtosl (args[*argn], 0, 0) + <= grub_strtosl (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + if (grub_strcmp (args[*argn + 1], "-LE") == 0) + { + update_val (grub_strtoull (args[*argn], 0, 0) + <= grub_strtoull (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + + if (grub_strcmp (args[*argn + 1], "-lt") == 0) + { + update_val (grub_strtosl (args[*argn], 0, 0) + < grub_strtosl (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + if (grub_strcmp (args[*argn + 1], "-LT") == 0) + { + update_val (grub_strtoull (args[*argn], 0, 0) + < grub_strtoull (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + + if (grub_strcmp (args[*argn + 1], "-ne") == 0) + { + update_val (grub_strtosl (args[*argn], 0, 0) + != grub_strtosl (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + if (grub_strcmp (args[*argn + 1], "-NE") == 0) + { + update_val (grub_strtoull (args[*argn], 0, 0) + != grub_strtoull (args[*argn + 2], 0, 0), &ctx); + (*argn) += 3; + continue; + } + + /* GRUB extension: compare numbers skipping prefixes. + Useful for comparing versions. E.g. vmlinuz-2 -plt vmlinuz-11. */ + if (grub_strcmp (args[*argn + 1], "-pgt") == 0 + || grub_strcmp (args[*argn + 1], "-plt") == 0) + { + int i; + /* Skip common prefix. */ + for (i = 0; args[*argn][i] == args[*argn + 2][i] + && args[*argn][i]; i++); + + /* Go the digits back. */ + i--; + while (grub_isdigit (args[*argn][i]) && i > 0) + i--; + i++; + + if (grub_strcmp (args[*argn + 1], "-pgt") == 0) + update_val (grub_strtoul (args[*argn] + i, 0, 0) + > grub_strtoul (args[*argn + 2] + i, 0, 0), &ctx); + else + update_val (grub_strtoul (args[*argn] + i, 0, 0) + < grub_strtoul (args[*argn + 2] + i, 0, 0), &ctx); + (*argn) += 3; + continue; + } + + /* -nt and -ot tests. GRUB extension: when doing -?t bias + will be added to the first mtime. */ + if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0 + || grub_memcmp (args[*argn + 1], "-ot", 3) == 0) + { + struct grub_dirhook_info file1; + int file1exists; + int bias = 0; + + /* Fetch fileinfo. */ + get_fileinfo (args[*argn], &ctx); + file1 = ctx.file_info; + file1exists = ctx.file_exists; + get_fileinfo (args[*argn + 2], &ctx); + + if (args[*argn + 1][3]) + bias = grub_strtosl (args[*argn + 1] + 3, 0, 0); + + if (grub_memcmp (args[*argn + 1], "-nt", 3) == 0) + update_val ((file1exists && ! ctx.file_exists) + || (file1.mtimeset && ctx.file_info.mtimeset + && file1.mtime + bias > ctx.file_info.mtime), + &ctx); + else + update_val ((! file1exists && ctx.file_exists) + || (file1.mtimeset && ctx.file_info.mtimeset + && file1.mtime + bias < ctx.file_info.mtime), + &ctx); + (*argn) += 3; + continue; + } + } + + /* Two-argument tests. */ + if (*argn + 1 < argc) + { + /* File tests. */ + if (grub_strcmp (args[*argn], "-d") == 0) + { + get_fileinfo (args[*argn + 1], &ctx); + update_val (ctx.file_exists && ctx.file_info.dir, &ctx); + (*argn) += 2; + continue; + } + + if (grub_strcmp (args[*argn], "-D") == 0) + { + g_test_case_insensitive = 1; + get_fileinfo (args[*argn + 1], &ctx); + g_test_case_insensitive = 0; + update_val (ctx.file_exists && ctx.file_info.dir, &ctx); + (*argn) += 2; + continue; + } + + if (grub_strcmp (args[*argn], "-e") == 0) + { + get_fileinfo (args[*argn + 1], &ctx); + update_val (ctx.file_exists, &ctx); + (*argn) += 2; + continue; + } + + if (grub_strcmp (args[*argn], "-E") == 0) + { + g_test_case_insensitive = 1; + get_fileinfo (args[*argn + 1], &ctx); + g_test_case_insensitive = 0; + update_val (ctx.file_exists, &ctx); + (*argn) += 2; + continue; + } + + if (grub_strcmp (args[*argn], "-f") == 0) + { + get_fileinfo (args[*argn + 1], &ctx); + /* FIXME: check for other types. */ + update_val (ctx.file_exists && ! ctx.file_info.dir, &ctx); + (*argn) += 2; + continue; + } + if (grub_strcmp (args[*argn], "-F") == 0) + { + g_test_case_insensitive = 1; + get_fileinfo (args[*argn + 1], &ctx); + g_test_case_insensitive = 0; + /* FIXME: check for other types. */ + update_val (ctx.file_exists && ! ctx.file_info.dir, &ctx); + (*argn) += 2; + continue; + } + + if (grub_strcmp (args[*argn], "-s") == 0) + { + grub_file_t file; + file = grub_file_open (args[*argn + 1], GRUB_FILE_TYPE_GET_SIZE + | GRUB_FILE_TYPE_NO_DECOMPRESS); + update_val (file && (grub_file_size (file) != 0), &ctx); + if (file) + grub_file_close (file); + grub_errno = GRUB_ERR_NONE; + (*argn) += 2; + continue; + } + + /* String tests. */ + if (grub_strcmp (args[*argn], "-n") == 0) + { + update_val (args[*argn + 1][0], &ctx); + + (*argn) += 2; + continue; + } + if (grub_strcmp (args[*argn], "-z") == 0) + { + update_val (! args[*argn + 1][0], &ctx); + (*argn) += 2; + continue; + } + } + + /* Special modifiers. */ + + /* End of expression. return to parent. */ + if (grub_strcmp (args[*argn], ")") == 0) + { + (*argn)++; + return ctx.or || ctx.and; + } + /* Recursively invoke if parenthesis. */ + if (grub_strcmp (args[*argn], "(") == 0) + { + (*argn)++; + update_val (test_parse (args, argn, argc), &ctx); + continue; + } + + if (grub_strcmp (args[*argn], "!") == 0) + { + ctx.invert = ! ctx.invert; + (*argn)++; + continue; + } + if (grub_strcmp (args[*argn], "-a") == 0) + { + (*argn)++; + continue; + } + if (grub_strcmp (args[*argn], "-o") == 0) + { + ctx.or = ctx.or || ctx.and; + ctx.and = 1; + (*argn)++; + continue; + } + + /* No test found. Interpret if as just a string. */ + update_val (args[*argn][0], &ctx); + (*argn)++; + } + return ctx.or || ctx.and; +} + +static grub_err_t +grub_cmd_test (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + int argn = 0; + + if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0) + argc--; + + return test_parse (args, &argn, argc) ? GRUB_ERR_NONE + : grub_error (GRUB_ERR_TEST_FAILURE, N_("false")); +} + +static grub_command_t cmd_1, cmd_2; + +GRUB_MOD_INIT(test) +{ + cmd_1 = grub_register_command ("[", grub_cmd_test, + N_("EXPRESSION ]"), N_("Evaluate an expression.")); + cmd_1->flags |= GRUB_COMMAND_FLAG_EXTRACTOR; + cmd_2 = grub_register_command ("test", grub_cmd_test, + N_("EXPRESSION"), N_("Evaluate an expression.")); + cmd_2->flags |= GRUB_COMMAND_FLAG_EXTRACTOR; +} + +GRUB_MOD_FINI(test) +{ + grub_unregister_command (cmd_1); + grub_unregister_command (cmd_2); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/i386/pc/biosdisk.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/i386/pc/biosdisk.c new file mode 100644 index 0000000..3f7016c --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/i386/pc/biosdisk.c @@ -0,0 +1,764 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static int cd_drive = 0; +static int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap); + +static int grub_biosdisk_get_num_floppies (void) +{ + struct grub_bios_int_registers regs; + int drive; + + /* reset the disk system first */ + regs.eax = 0; + regs.edx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + grub_bios_interrupt (0x13, ®s); + + for (drive = 0; drive < 2; drive++) + { + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT | GRUB_CPU_INT_FLAGS_CARRY; + regs.edx = drive; + + /* call GET DISK TYPE */ + regs.eax = 0x1500; + grub_bios_interrupt (0x13, ®s); + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + break; + + /* check if this drive exists */ + if (!(regs.eax & 0x300)) + break; + } + + return drive; +} + +/* + * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP + * is passed for disk address packet. If an error occurs, return + * non-zero, otherwise zero. + */ + +static int +grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap) +{ + struct grub_bios_int_registers regs; + regs.eax = ah << 8; + /* compute the address of disk_address_packet */ + regs.ds = (((grub_addr_t) dap) & 0xffff0000) >> 4; + regs.esi = (((grub_addr_t) dap) & 0xffff); + regs.edx = drive; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + grub_bios_interrupt (0x13, ®s); + return (regs.eax >> 8) & 0xff; +} + +/* + * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write + * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs, + * return non-zero, otherwise zero. + */ +static int +grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff, + int soff, int nsec, int segment) +{ + int ret, i; + + /* Try 3 times. */ + for (i = 0; i < 3; i++) + { + struct grub_bios_int_registers regs; + + /* set up CHS information */ + /* set %ch to low eight bits of cylinder */ + regs.ecx = (coff << 8) & 0xff00; + /* set bits 6-7 of %cl to high two bits of cylinder */ + regs.ecx |= (coff >> 2) & 0xc0; + /* set bits 0-5 of %cl to sector */ + regs.ecx |= soff & 0x3f; + + /* set %dh to head and %dl to drive */ + regs.edx = (drive & 0xff) | ((hoff << 8) & 0xff00); + /* set %ah to AH */ + regs.eax = (ah << 8) & 0xff00; + /* set %al to NSEC */ + regs.eax |= nsec & 0xff; + + regs.ebx = 0; + regs.es = segment; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + grub_bios_interrupt (0x13, ®s); + /* check if successful */ + if (!(regs.flags & GRUB_CPU_INT_FLAGS_CARRY)) + return 0; + + /* save return value */ + ret = regs.eax >> 8; + + /* if fail, reset the disk system */ + regs.eax = 0; + regs.edx = (drive & 0xff); + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x13, ®s); + } + return ret; +} + +/* + * Check if LBA is supported for DRIVE. If it is supported, then return + * the major version of extensions, otherwise zero. + */ +static int +grub_biosdisk_check_int13_extensions (int drive) +{ + struct grub_bios_int_registers regs; + + regs.edx = drive & 0xff; + regs.eax = 0x4100; + regs.ebx = 0x55aa; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x13, ®s); + + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + return 0; + + if ((regs.ebx & 0xffff) != 0xaa55) + return 0; + + /* check if AH=0x42 is supported */ + if (!(regs.ecx & 1)) + return 0; + + return (regs.eax >> 8) & 0xff; +} + +/* + * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an + * error occurs, then return non-zero, otherwise zero. + */ +static int +grub_biosdisk_get_diskinfo_standard (int drive, + unsigned long *cylinders, + unsigned long *heads, + unsigned long *sectors) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x0800; + regs.edx = drive & 0xff; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x13, ®s); + + /* Check if unsuccessful. Ignore return value if carry isn't set to + workaround some buggy BIOSes. */ + if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0)) + return (regs.eax & 0xff00) >> 8; + + /* bogus BIOSes may not return an error number */ + /* 0 sectors means no disk */ + if (!(regs.ecx & 0x3f)) + /* XXX 0x60 is one of the unused error numbers */ + return 0x60; + + /* the number of heads is counted from zero */ + *heads = ((regs.edx >> 8) & 0xff) + 1; + *cylinders = (((regs.ecx >> 8) & 0xff) | ((regs.ecx << 2) & 0x0300)) + 1; + *sectors = regs.ecx & 0x3f; + return 0; +} + +static int +grub_biosdisk_get_diskinfo_real (int drive, void *drp, grub_uint16_t ax) +{ + struct grub_bios_int_registers regs; + + regs.eax = ax; + + /* compute the address of drive parameters */ + regs.esi = ((grub_addr_t) drp) & 0xf; + regs.ds = ((grub_addr_t) drp) >> 4; + regs.edx = drive & 0xff; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x13, ®s); + + /* Check if unsuccessful. Ignore return value if carry isn't set to + workaround some buggy BIOSes. */ + if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0)) + return (regs.eax & 0xff00) >> 8; + + return 0; +} + +/* + * Return the cdrom information of DRIVE in CDRP. If an error occurs, + * then return non-zero, otherwise zero. + */ +static int +grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp) +{ + return grub_biosdisk_get_diskinfo_real (drive, cdrp, 0x4b01); +} + +/* + * Return the geometry of DRIVE in a drive parameters, DRP. If an error + * occurs, then return non-zero, otherwise zero. + */ +static int +grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp) +{ + return grub_biosdisk_get_diskinfo_real (drive, drp, 0x4800); +} + +static int +grub_biosdisk_get_drive (const char *name) +{ + unsigned long drive; + + if (name[0] == 'c' && name[1] == 'd' && name[2] == 0 && cd_drive) + return cd_drive; + + if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd') + goto fail; + + drive = grub_strtoul (name + 2, 0, 10); + if (grub_errno != GRUB_ERR_NONE) + goto fail; + + if (name[0] == 'h') + drive += 0x80; + + return (int) drive ; + + fail: + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a biosdisk"); + return -1; +} + +static int +grub_biosdisk_call_hook (grub_disk_dev_iterate_hook_t hook, void *hook_data, + int drive) +{ + char name[10]; + + if (cd_drive && drive == cd_drive) + return hook ("cd", hook_data); + + grub_snprintf (name, sizeof (name), + (drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80)); + return hook (name, hook_data); +} + +static int +grub_biosdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + grub_disk_pull_t pull) +{ + int num_floppies; + int drive; + + /* For hard disks, attempt to read the MBR. */ + switch (pull) + { + case GRUB_DISK_PULL_NONE: + for (drive = 0x80; drive < 0x90; drive++) + { + if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1, + GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0) + { + grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive); + break; + } + + if (grub_biosdisk_call_hook (hook, hook_data, drive)) + return 1; + } + return 0; + + case GRUB_DISK_PULL_REMOVABLE: + if (cd_drive) + { + if (grub_biosdisk_call_hook (hook, hook_data, cd_drive)) + return 1; + } + + /* For floppy disks, we can get the number safely. */ + num_floppies = grub_biosdisk_get_num_floppies (); + for (drive = 0; drive < num_floppies; drive++) + if (grub_biosdisk_call_hook (hook, hook_data, drive)) + return 1; + return 0; + default: + return 0; + } + return 0; +} + +#pragma pack(1) +typedef struct ventoy_part_table +{ + grub_uint8_t Active; // 0x00 0x80 + + grub_uint8_t StartHead; + grub_uint16_t StartSector : 6; + grub_uint16_t StartCylinder : 10; + + grub_uint8_t FsFlag; + + grub_uint8_t EndHead; + grub_uint16_t EndSector : 6; + grub_uint16_t EndCylinder : 10; + + grub_uint32_t StartSectorId; + grub_uint32_t SectorCount; +}ventoy_part_table; + +typedef struct ventoy_mbr_head +{ + grub_uint8_t BootCode[446]; + ventoy_part_table PartTbl[4]; + grub_uint8_t Byte55; + grub_uint8_t ByteAA; +}ventoy_mbr_head; +#pragma pack() + +static grub_err_t +grub_biosdisk_rw (int cmd, grub_disk_t disk, + grub_disk_addr_t sector, grub_size_t size, + unsigned segment); + +static int ventoy_is_mbr_match(ventoy_mbr_head *head) +{ + grub_uint32_t PartStartSector; + + if (head->Byte55 != 0x55 || head->ByteAA != 0xAA) { + return 0; + } + + if (head->PartTbl[2].SectorCount > 0 || head->PartTbl[3].SectorCount > 0) { + return 0; + } + + if (head->PartTbl[0].StartSectorId != 2048) { + return 0; + } + + if (head->PartTbl[1].Active != 0x80 || head->PartTbl[1].FsFlag != 0xEF) { + return 0; + } + + PartStartSector = head->PartTbl[0].StartSectorId + head->PartTbl[0].SectorCount; + + if (head->PartTbl[1].StartSectorId != PartStartSector || head->PartTbl[1].SectorCount != 65536) { + return 0; + } + + return 1; +} + +static grub_err_t +grub_biosdisk_open (const char *name, grub_disk_t disk) +{ + grub_uint64_t total_sectors = 0; + int drive; + struct grub_biosdisk_data *data; + + drive = grub_biosdisk_get_drive (name); + if (drive < 0) + return grub_errno; + + disk->id = drive; + + data = (struct grub_biosdisk_data *) grub_zalloc (sizeof (*data)); + if (! data) + return grub_errno; + + data->drive = drive; + + if ((cd_drive) && (drive == cd_drive)) + { + data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM; + data->sectors = 8; + disk->log_sector_size = 11; + /* TODO: get the correct size. */ + total_sectors = GRUB_DISK_SIZE_UNKNOWN; + } + else + { + /* HDD */ + int version; + + disk->log_sector_size = 9; + + version = grub_biosdisk_check_int13_extensions (drive); + if (version) + { + struct grub_biosdisk_drp *drp + = (struct grub_biosdisk_drp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + + /* Clear out the DRP. */ + grub_memset (drp, 0, sizeof (*drp)); + drp->size = sizeof (*drp); + if (! grub_biosdisk_get_diskinfo_int13_extensions (drive, drp)) + { + data->flags = GRUB_BIOSDISK_FLAG_LBA; + + if (drp->total_sectors) + total_sectors = drp->total_sectors; + else + /* Some buggy BIOSes doesn't return the total sectors + correctly but returns zero. So if it is zero, compute + it by C/H/S returned by the LBA BIOS call. */ + total_sectors = ((grub_uint64_t) drp->cylinders) + * drp->heads * drp->sectors; + if (drp->bytes_per_sector + && !(drp->bytes_per_sector & (drp->bytes_per_sector - 1)) + && drp->bytes_per_sector >= 512 + && drp->bytes_per_sector <= 16384) + { + for (disk->log_sector_size = 0; + (1 << disk->log_sector_size) < drp->bytes_per_sector; + disk->log_sector_size++); + } + } + } + } + + if (! (data->flags & GRUB_BIOSDISK_FLAG_CDROM)) + { + if (grub_biosdisk_get_diskinfo_standard (drive, + &data->cylinders, + &data->heads, + &data->sectors) != 0) + { + if (total_sectors && (data->flags & GRUB_BIOSDISK_FLAG_LBA)) + { + data->sectors = 63; + data->heads = 255; + data->cylinders + = grub_divmod64 (total_sectors + + data->heads * data->sectors - 1, + data->heads * data->sectors, 0); + } + else + { + grub_free (data); + return grub_error (GRUB_ERR_BAD_DEVICE, "%s cannot get C/H/S values", disk->name); + } + } + + if (data->sectors == 0) + data->sectors = 63; + if (data->heads == 0) + data->heads = 255; + + if (! total_sectors) + total_sectors = ((grub_uint64_t) data->cylinders) + * data->heads * data->sectors; + } + + disk->total_sectors = total_sectors; + /* Limit the max to 0x7f because of Phoenix EDD. */ + disk->max_agglomerate = 0x7f >> GRUB_DISK_CACHE_BITS; + COMPILE_TIME_ASSERT ((0x7f >> GRUB_DISK_CACHE_BITS + << (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS)) + + sizeof (struct grub_biosdisk_dap) + < GRUB_MEMORY_MACHINE_SCRATCH_SIZE); + + disk->data = data; + + //fixup some buggy bios + if (total_sectors > (16434495 - 2097152) && total_sectors < (16434495 + 2097152) && + (data->flags & GRUB_BIOSDISK_FLAG_LBA) > 0 && (data->flags & GRUB_BIOSDISK_FLAG_CDROM) == 0) { + if (grub_biosdisk_rw(0, disk, 0, 1, GRUB_MEMORY_MACHINE_SCRATCH_SEG) == 0) { + ventoy_mbr_head *mbr = (ventoy_mbr_head *)GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + if (ventoy_is_mbr_match(mbr)) { + total_sectors = mbr->PartTbl[1].StartSectorId + mbr->PartTbl[1].SectorCount + 1; + if (disk->total_sectors < total_sectors) { + disk->total_sectors = total_sectors; + } + } + } + } + + return GRUB_ERR_NONE; +} + +static void +grub_biosdisk_close (grub_disk_t disk) +{ + grub_free (disk->data); +} + +/* For readability. */ +#define GRUB_BIOSDISK_READ 0 +#define GRUB_BIOSDISK_WRITE 1 + +#define GRUB_BIOSDISK_CDROM_RETRY_COUNT 3 + +static grub_err_t +grub_biosdisk_rw (int cmd, grub_disk_t disk, + grub_disk_addr_t sector, grub_size_t size, + unsigned segment) +{ + struct grub_biosdisk_data *data = disk->data; + + /* VirtualBox fails with sectors above 2T on CDs. + Since even BD-ROMS are never that big anyway, return error. */ + if ((data->flags & GRUB_BIOSDISK_FLAG_CDROM) + && (sector >> 32)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("attempt to read or write outside of disk `%s'"), + disk->name); + + if (data->flags & GRUB_BIOSDISK_FLAG_LBA) + { + struct grub_biosdisk_dap *dap; + + dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + + (data->sectors + << disk->log_sector_size)); + dap->length = sizeof (*dap); + dap->reserved = 0; + dap->blocks = size; + dap->buffer = segment << 16; /* The format SEGMENT:ADDRESS. */ + dap->block = sector; + + if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) + { + int i; + + if (cmd) + return grub_error (GRUB_ERR_WRITE_ERROR, N_("cannot write to CD-ROM")); + + for (i = 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++) + if (! grub_biosdisk_rw_int13_extensions (0x42, data->drive, dap)) + break; + + if (i == GRUB_BIOSDISK_CDROM_RETRY_COUNT) + return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx " + "from `%s'"), + (unsigned long long) sector, + disk->name); + } + else + if (grub_biosdisk_rw_int13_extensions (cmd + 0x42, data->drive, dap)) + { + /* Fall back to the CHS mode. */ + data->flags &= ~GRUB_BIOSDISK_FLAG_LBA; + disk->total_sectors = data->cylinders * data->heads * data->sectors; + return grub_biosdisk_rw (cmd, disk, sector, size, segment); + } + } + else + { + unsigned coff, hoff, soff; + unsigned head; + + /* It is impossible to reach over 8064 MiB (a bit less than LBA24) with + the traditional CHS access. */ + if (sector > + 1024 /* cylinders */ * + 256 /* heads */ * + 63 /* spt */) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("attempt to read or write outside of disk `%s'"), + disk->name); + + soff = ((grub_uint32_t) sector) % data->sectors + 1; + head = ((grub_uint32_t) sector) / data->sectors; + hoff = head % data->heads; + coff = head / data->heads; + + if (coff >= data->cylinders) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("attempt to read or write outside of disk `%s'"), + disk->name); + + if (grub_biosdisk_rw_standard (cmd + 0x02, data->drive, + coff, hoff, soff, size, segment)) + { + switch (cmd) + { + case GRUB_BIOSDISK_READ: + return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx " + "from `%s'"), + (unsigned long long) sector, + disk->name); + case GRUB_BIOSDISK_WRITE: + return grub_error (GRUB_ERR_WRITE_ERROR, N_("failure writing sector 0x%llx " + "to `%s'"), + (unsigned long long) sector, + disk->name); + } + } + } + + return GRUB_ERR_NONE; +} + +/* Return the number of sectors which can be read safely at a time. */ +static grub_size_t +get_safe_sectors (grub_disk_t disk, grub_disk_addr_t sector) +{ + grub_size_t size; + grub_uint64_t offset; + struct grub_biosdisk_data *data = disk->data; + grub_uint32_t sectors = data->sectors; + + /* OFFSET = SECTOR % SECTORS */ + grub_divmod64 (sector, sectors, &offset); + + size = sectors - offset; + + return size; +} + +static grub_err_t +grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + while (size) + { + grub_size_t len; + + len = get_safe_sectors (disk, sector); + + if (len > size) + len = size; + + if (grub_biosdisk_rw (GRUB_BIOSDISK_READ, disk, sector, len, + GRUB_MEMORY_MACHINE_SCRATCH_SEG)) + return grub_errno; + + grub_memcpy (buf, (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, + len << disk->log_sector_size); + + buf += len << disk->log_sector_size; + sector += len; + size -= len; + } + + return grub_errno; +} + +static grub_err_t +grub_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, const char *buf) +{ + struct grub_biosdisk_data *data = disk->data; + + if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) + return grub_error (GRUB_ERR_IO, N_("cannot write to CD-ROM")); + + while (size) + { + grub_size_t len; + + len = get_safe_sectors (disk, sector); + if (len > size) + len = size; + + grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf, + len << disk->log_sector_size); + + if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len, + GRUB_MEMORY_MACHINE_SCRATCH_SEG)) + return grub_errno; + + buf += len << disk->log_sector_size; + sector += len; + size -= len; + } + + return grub_errno; +} + +static struct grub_disk_dev grub_biosdisk_dev = + { + .name = "biosdisk", + .id = GRUB_DISK_DEVICE_BIOSDISK_ID, + .disk_iterate = grub_biosdisk_iterate, + .disk_open = grub_biosdisk_open, + .disk_close = grub_biosdisk_close, + .disk_read = grub_biosdisk_read, + .disk_write = grub_biosdisk_write, + .next = 0 + }; + +static void +grub_disk_biosdisk_fini (void) +{ + grub_disk_dev_unregister (&grub_biosdisk_dev); +} + +GRUB_MOD_INIT(biosdisk) +{ + struct grub_biosdisk_cdrp *cdrp + = (struct grub_biosdisk_cdrp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + grub_uint8_t boot_drive; + + if (grub_disk_firmware_is_tainted) + { + grub_puts_ (N_("Native disk drivers are in use. " + "Refusing to use firmware disk interface.")); + return; + } + grub_disk_firmware_fini = grub_disk_biosdisk_fini; + + grub_memset (cdrp, 0, sizeof (*cdrp)); + cdrp->size = sizeof (*cdrp); + cdrp->media_type = 0xFF; + boot_drive = (grub_boot_device >> 24); + if ((! grub_biosdisk_get_cdinfo_int13_extensions (boot_drive, cdrp)) + && ((cdrp->media_type & GRUB_BIOSDISK_CDTYPE_MASK) + == GRUB_BIOSDISK_CDTYPE_NO_EMUL)) + cd_drive = cdrp->drive_no; + /* Since diskboot.S rejects devices over 0x90 it must be a CD booted with + cdboot.S + */ + if (boot_drive >= 0x90) + cd_drive = boot_drive; + + grub_disk_dev_register (&grub_biosdisk_dev); +} + +GRUB_MOD_FINI(biosdisk) +{ + grub_disk_biosdisk_fini (); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/loopback.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/loopback.c new file mode 100644 index 0000000..38ad622 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/disk/loopback.c @@ -0,0 +1,257 @@ +/* loopback.c - command to add loopback devices. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +struct grub_loopback +{ + char *devname; + grub_file_t file; + struct grub_loopback *next; + unsigned long id; + grub_off_t skip; +}; + +static struct grub_loopback *loopback_list; +static unsigned long last_id = 0; + +static const struct grub_arg_option options[] = + { + /* TRANSLATORS: The disk is simply removed from the list of available ones, + not wiped, avoid to scare user. */ + {"delete", 'd', 0, N_("Delete the specified loopback drive."), 0, 0}, + {"skip", 's', 0, "skip sectors of the file.", "SECTORS", ARG_TYPE_INT }, + {0, 0, 0, 0, 0, 0} + }; + +/* Delete the loopback device NAME. */ +static grub_err_t +delete_loopback (const char *name) +{ + struct grub_loopback *dev; + struct grub_loopback **prev; + + /* Search for the device. */ + for (dev = loopback_list, prev = &loopback_list; + dev; + prev = &dev->next, dev = dev->next) + if (grub_strcmp (dev->devname, name) == 0) + break; + + if (! dev) + return grub_error (GRUB_ERR_BAD_DEVICE, "device not found"); + + /* Remove the device from the list. */ + *prev = dev->next; + + grub_free (dev->devname); + grub_file_close (dev->file); + grub_free (dev); + + return 0; +} + +/* The command to add and remove loopback devices. */ +static grub_err_t +grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + grub_file_t file; + struct grub_loopback *newdev; + grub_err_t ret; + grub_off_t skip = 0; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + + /* Check if `-d' was used. */ + if (state[0].set) + return delete_loopback (args[0]); + + if (state[1].set) + skip = (grub_off_t)grub_strtoull(state[1].arg, NULL, 10); + + if (argc < 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + file = grub_file_open (args[1], GRUB_FILE_TYPE_LOOPBACK + | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (! file) + return grub_errno; + + /* First try to replace the old device. */ + for (newdev = loopback_list; newdev; newdev = newdev->next) + if (grub_strcmp (newdev->devname, args[0]) == 0) + break; + + if (newdev) + { + grub_file_close (newdev->file); + newdev->file = file; + newdev->skip = skip; + + return 0; + } + + /* Unable to replace it, make a new entry. */ + newdev = grub_malloc (sizeof (struct grub_loopback)); + if (! newdev) + goto fail; + + newdev->devname = grub_strdup (args[0]); + if (! newdev->devname) + { + grub_free (newdev); + goto fail; + } + + newdev->file = file; + newdev->skip = skip; + newdev->id = last_id++; + + /* Add the new entry to the list. */ + newdev->next = loopback_list; + loopback_list = newdev; + + return 0; + +fail: + ret = grub_errno; + grub_file_close (file); + return ret; +} + + +static int +grub_loopback_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + grub_disk_pull_t pull) +{ + struct grub_loopback *d; + if (pull != GRUB_DISK_PULL_NONE) + return 0; + for (d = loopback_list; d; d = d->next) + { + if (hook (d->devname, hook_data)) + return 1; + } + return 0; +} + +static grub_err_t +grub_loopback_open (const char *name, grub_disk_t disk) +{ + struct grub_loopback *dev; + + for (dev = loopback_list; dev; dev = dev->next) + if (grub_strcmp (dev->devname, name) == 0) + break; + + if (! dev) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + + /* Use the filesize for the disk size, round up to a complete sector. */ + if (dev->file->size != GRUB_FILE_SIZE_UNKNOWN) + disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1) + / GRUB_DISK_SECTOR_SIZE); + else + disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; + /* Avoid reading more than 512M. */ + disk->max_agglomerate = 1 << (29 - GRUB_DISK_SECTOR_BITS + - GRUB_DISK_CACHE_BITS); + + disk->id = dev->id; + + disk->data = dev; + + return 0; +} + +static grub_err_t +grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_size_t size, char *buf) +{ + grub_file_t file = ((struct grub_loopback *) disk->data)->file; + grub_off_t skip = ((struct grub_loopback *) disk->data)->skip; + grub_off_t pos; + + grub_file_seek (file, (sector + skip) << GRUB_DISK_SECTOR_BITS); + + grub_file_read (file, buf, size << GRUB_DISK_SECTOR_BITS); + if (grub_errno) + return grub_errno; + + /* In case there is more data read than there is available, in case + of files that are not a multiple of GRUB_DISK_SECTOR_SIZE, fill + the rest with zeros. */ + pos = (sector + skip + size) << GRUB_DISK_SECTOR_BITS; + if (pos > file->size) + { + grub_size_t amount = pos - file->size; + grub_memset (buf + (size << GRUB_DISK_SECTOR_BITS) - amount, 0, amount); + } + + return 0; +} + +static grub_err_t +grub_loopback_write (grub_disk_t disk __attribute ((unused)), + grub_disk_addr_t sector __attribute ((unused)), + grub_size_t size __attribute ((unused)), + const char *buf __attribute ((unused))) +{ + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "loopback write is not supported"); +} + +static struct grub_disk_dev grub_loopback_dev = + { + .name = "loopback", + .id = GRUB_DISK_DEVICE_LOOPBACK_ID, + .disk_iterate = grub_loopback_iterate, + .disk_open = grub_loopback_open, + .disk_read = grub_loopback_read, + .disk_write = grub_loopback_write, + .next = 0 + }; + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(loopback) +{ + cmd = grub_register_extcmd ("loopback", grub_cmd_loopback, 0, + N_("[-d] DEVICENAME FILE."), + /* TRANSLATORS: The file itself is not destroyed + or transformed into drive. */ + N_("Make a virtual drive from a file."), options); + grub_disk_dev_register (&grub_loopback_dev); +} + +GRUB_MOD_FINI(loopback) +{ + grub_unregister_extcmd (cmd); + grub_disk_dev_unregister (&grub_loopback_dev); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/font/font.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/font/font.c new file mode 100644 index 0000000..99bceb3 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/font/font.c @@ -0,0 +1,1603 @@ +/* font.c - Font API and font file loader. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#if HAVE_FONT_SOURCE +#include "ascii.h" +#endif + +#ifndef FONT_DEBUG +#define FONT_DEBUG 0 +#endif + +struct char_index_entry +{ + grub_uint32_t code; + grub_uint8_t storage_flags; + grub_uint32_t offset; + + /* Glyph if loaded, or NULL otherwise. */ + struct grub_font_glyph *glyph; +}; + +#define FONT_WEIGHT_NORMAL 100 +#define FONT_WEIGHT_BOLD 200 +#define ASCII_BITMAP_SIZE 16 + +/* Definition of font registry. */ +struct grub_font_node *grub_font_list; + +static int register_font (grub_font_t font); +static void font_init (grub_font_t font); +static void free_font (grub_font_t font); +static void remove_font (grub_font_t font); + +struct font_file_section +{ + /* The file this section is in. */ + grub_file_t file; + + /* FOURCC name of the section. */ + char name[4]; + + /* Length of the section contents. */ + grub_uint32_t length; + + /* Set by open_section() on EOF. */ + int eof; +}; + +/* Replace unknown glyphs with a rounded question mark. */ +static grub_uint8_t unknown_glyph_bitmap[] = { + /* 76543210 */ + 0x7C, /* ooooo */ + 0x82, /* o o */ + 0xBA, /* o ooo o */ + 0xAA, /* o o o o */ + 0xAA, /* o o o o */ + 0x8A, /* o o o */ + 0x9A, /* o oo o */ + 0x92, /* o o o */ + 0x92, /* o o o */ + 0x92, /* o o o */ + 0x92, /* o o o */ + 0x82, /* o o */ + 0x92, /* o o o */ + 0x82, /* o o */ + 0x7C, /* ooooo */ + 0x00 /* */ +}; + +/* The "unknown glyph" glyph, used as a last resort. */ +static struct grub_font_glyph *unknown_glyph; + +/* The font structure used when no other font is loaded. This functions + as a "Null Object" pattern, so that code everywhere does not have to + check for a NULL grub_font_t to avoid dereferencing a null pointer. */ +static struct grub_font null_font; + +/* Flag to ensure module is initialized only once. */ +static grub_uint8_t font_loader_initialized; + +#if HAVE_FONT_SOURCE +static struct grub_font_glyph *ascii_font_glyph[0x80]; +#endif + +static struct grub_font_glyph * +ascii_glyph_lookup (grub_uint32_t code) +{ +#if HAVE_FONT_SOURCE + static int ascii_failback_initialized = 0; + + if (code >= 0x80) + return NULL; + + if (ascii_failback_initialized == 0) + { + int current; + for (current = 0; current < 0x80; current++) + { + ascii_font_glyph[current] = + grub_malloc (sizeof (struct grub_font_glyph) + ASCII_BITMAP_SIZE); + + ascii_font_glyph[current]->width = 8; + ascii_font_glyph[current]->height = 16; + ascii_font_glyph[current]->offset_x = 0; + ascii_font_glyph[current]->offset_y = -2; + ascii_font_glyph[current]->device_width = 8; + ascii_font_glyph[current]->font = NULL; + + grub_memcpy (ascii_font_glyph[current]->bitmap, + &ascii_bitmaps[current * ASCII_BITMAP_SIZE], + ASCII_BITMAP_SIZE); + } + + ascii_failback_initialized = 1; + } + + return ascii_font_glyph[code]; +#else + (void) code; + return NULL; +#endif +} + +void +grub_font_loader_init (void) +{ + /* Only initialize font loader once. */ + if (font_loader_initialized) + return; + + /* Make glyph for unknown glyph. */ + unknown_glyph = grub_malloc (sizeof (struct grub_font_glyph) + + sizeof (unknown_glyph_bitmap)); + if (!unknown_glyph) + return; + + unknown_glyph->width = 8; + unknown_glyph->height = 16; + unknown_glyph->offset_x = 0; + unknown_glyph->offset_y = -3; + unknown_glyph->device_width = 8; + grub_memcpy (unknown_glyph->bitmap, + unknown_glyph_bitmap, sizeof (unknown_glyph_bitmap)); + + /* Initialize the null font. */ + font_init (&null_font); + /* FIXME: Fix this slightly improper cast. */ + null_font.name = (char *) ""; + null_font.ascent = unknown_glyph->height - 3; + null_font.descent = 3; + null_font.max_char_width = unknown_glyph->width; + null_font.max_char_height = unknown_glyph->height; + + font_loader_initialized = 1; +} + +/* Initialize the font object with initial default values. */ +static void +font_init (grub_font_t font) +{ + font->name = 0; + font->file = 0; + font->family = 0; + font->point_size = 0; + font->weight = 0; + + /* Default leading value, not in font file yet. */ + font->leading = 1; + + font->max_char_width = 0; + font->max_char_height = 0; + font->ascent = 0; + font->descent = 0; + font->num_chars = 0; + font->char_index = 0; + font->bmp_idx = 0; +} + +/* Open the next section in the file. + + On success, the section name is stored in section->name and the length in + section->length, and 0 is returned. On failure, 1 is returned and + grub_errno is set appropriately with an error message. + + If 1 is returned due to being at the end of the file, then section->eof is + set to 1; otherwise, section->eof is set to 0. */ +static int +open_section (grub_file_t file, struct font_file_section *section) +{ + grub_ssize_t retval; + grub_uint32_t raw_length; + + section->file = file; + section->eof = 0; + + /* Read the FOURCC section name. */ + retval = grub_file_read (file, section->name, 4); + if (retval >= 0 && retval < 4) + { + /* EOF encountered. */ + section->eof = 1; + return 1; + } + else if (retval < 0) + { + /* Read error. */ + return 1; + } + + /* Read the big-endian 32-bit section length. */ + retval = grub_file_read (file, &raw_length, 4); + if (retval >= 0 && retval < 4) + { + /* EOF encountered. */ + section->eof = 1; + return 1; + } + else if (retval < 0) + { + /* Read error. */ + return 1; + } + + /* Convert byte-order and store in *length. */ + section->length = grub_be_to_cpu32 (raw_length); + + return 0; +} + +/* Size in bytes of each character index (CHIX section) + entry in the font file. */ +#define FONT_CHAR_INDEX_ENTRY_SIZE (4 + 1 + 4) + +/* Load the character index (CHIX) section contents from the font file. This + presumes that the position of FILE is positioned immediately after the + section length for the CHIX section (i.e., at the start of the section + contents). Returns 0 upon success, nonzero for failure (in which case + grub_errno is set appropriately). */ +static int +load_font_index (grub_file_t file, grub_uint32_t sect_length, struct + grub_font *font) +{ + unsigned i; + grub_uint32_t last_code; + +#if FONT_DEBUG >= 2 + grub_dprintf ("font", "load_font_index(sect_length=%d)\n", sect_length); +#endif + + /* Sanity check: ensure section length is divisible by the entry size. */ + if ((sect_length % FONT_CHAR_INDEX_ENTRY_SIZE) != 0) + { + grub_error (GRUB_ERR_BAD_FONT, + "font file format error: character index length %d " + "is not a multiple of the entry size %d", + sect_length, FONT_CHAR_INDEX_ENTRY_SIZE); + return 1; + } + + /* Calculate the number of characters. */ + font->num_chars = sect_length / FONT_CHAR_INDEX_ENTRY_SIZE; + + /* Allocate the character index array. */ + font->char_index = grub_malloc (font->num_chars + * sizeof (struct char_index_entry)); + if (!font->char_index) + return 1; + font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t)); + if (!font->bmp_idx) + return 1; + grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t)); + + +#if FONT_DEBUG >= 2 + grub_dprintf ("font", "num_chars=%d)\n", font->num_chars); +#endif + + last_code = 0; + + /* Load the character index data from the file. */ + for (i = 0; i < font->num_chars; i++) + { + struct char_index_entry *entry = &font->char_index[i]; + + /* Read code point value; convert to native byte order. */ + if (grub_file_read (file, &entry->code, 4) != 4) + return 1; + entry->code = grub_be_to_cpu32 (entry->code); + + /* Verify that characters are in ascending order. */ + if (i != 0 && entry->code <= last_code) + { + grub_error (GRUB_ERR_BAD_FONT, + "font characters not in ascending order: %u <= %u", + entry->code, last_code); + return 1; + } + + if (entry->code < 0x10000) + font->bmp_idx[entry->code] = i; + + last_code = entry->code; + + /* Read storage flags byte. */ + if (grub_file_read (file, &entry->storage_flags, 1) != 1) + return 1; + + /* Read glyph data offset; convert to native byte order. */ + if (grub_file_read (file, &entry->offset, 4) != 4) + return 1; + entry->offset = grub_be_to_cpu32 (entry->offset); + + /* No glyph loaded. Will be loaded on demand and cached thereafter. */ + entry->glyph = 0; + +#if FONT_DEBUG >= 5 + /* Print the 1st 10 characters. */ + if (i < 10) + grub_dprintf ("font", "c=%d o=%d\n", entry->code, entry->offset); +#endif + } + + return 0; +} + +/* Read the contents of the specified section as a string, which is + allocated on the heap. Returns 0 if there is an error. */ +static char * +read_section_as_string (struct font_file_section *section) +{ + char *str; + grub_ssize_t ret; + + str = grub_malloc (section->length + 1); + if (!str) + return 0; + + ret = grub_file_read (section->file, str, section->length); + if (ret < 0 || ret != (grub_ssize_t) section->length) + { + grub_free (str); + return 0; + } + + str[section->length] = '\0'; + return str; +} + +/* Read the contents of the current section as a 16-bit integer value, + which is stored into *VALUE. + Returns 0 upon success, nonzero upon failure. */ +static int +read_section_as_short (struct font_file_section *section, + grub_int16_t * value) +{ + grub_uint16_t raw_value; + + if (section->length != 2) + { + grub_error (GRUB_ERR_BAD_FONT, + "font file format error: section %c%c%c%c length " + "is %d but should be 2", + section->name[0], section->name[1], + section->name[2], section->name[3], section->length); + return 1; + } + if (grub_file_read (section->file, &raw_value, 2) != 2) + return 1; + + *value = grub_be_to_cpu16 (raw_value); + return 0; +} + +/* Load a font and add it to the beginning of the global font list. + Returns 0 upon success, nonzero upon failure. */ +grub_font_t +grub_font_load (const char *filename) +{ + grub_file_t file = 0; + struct font_file_section section; + char magic[4]; + grub_font_t font = 0; + +#if FONT_DEBUG >= 1 + grub_dprintf ("font", "add_font(%s)\n", filename); +#endif + + if (filename[0] == '(' || filename[0] == '/' || filename[0] == '+') + file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024); + else if (grub_strncmp(filename, "mem:", 4) == 0) + file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024); + else + { + const char *prefix = grub_env_get ("prefix"); + char *fullname, *ptr; + if (!prefix) + { + grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), + "prefix"); + goto fail; + } + fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1 + + sizeof ("/fonts/") + sizeof (".pf2")); + if (!fullname) + goto fail; + ptr = grub_stpcpy (fullname, prefix); + ptr = grub_stpcpy (ptr, "/fonts/"); + ptr = grub_stpcpy (ptr, filename); + ptr = grub_stpcpy (ptr, ".pf2"); + *ptr = 0; + file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024); + grub_free (fullname); + } + if (!file) + goto fail; + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "file opened\n"); +#endif + + /* Read the FILE section. It indicates the file format. */ + if (open_section (file, §ion) != 0) + goto fail; + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "opened FILE section\n"); +#endif + if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FILE, + sizeof (FONT_FORMAT_SECTION_NAMES_FILE) - 1) != 0) + { + grub_error (GRUB_ERR_BAD_FONT, + "font file format error: 1st section must be FILE"); + goto fail; + } + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "section name ok\n"); +#endif + if (section.length != 4) + { + grub_error (GRUB_ERR_BAD_FONT, + "font file format error (file type ID length is %d " + "but should be 4)", section.length); + goto fail; + } + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "section length ok\n"); +#endif + /* Check the file format type code. */ + if (grub_file_read (file, magic, 4) != 4) + goto fail; + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "read magic ok\n"); +#endif + + if (grub_memcmp (magic, FONT_FORMAT_PFF2_MAGIC, 4) != 0) + { + grub_error (GRUB_ERR_BAD_FONT, "invalid font magic %x %x %x %x", + magic[0], magic[1], magic[2], magic[3]); + goto fail; + } + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "compare magic ok\n"); +#endif + + /* Allocate the font object. */ + font = (grub_font_t) grub_zalloc (sizeof (struct grub_font)); + if (!font) + goto fail; + + font_init (font); + font->file = file; + +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "allocate font ok; loading font info\n"); +#endif + + /* Load the font information. */ + while (1) + { + if (open_section (file, §ion) != 0) + { + if (section.eof) + break; /* Done reading the font file. */ + else + goto fail; + } + +#if FONT_DEBUG >= 2 + grub_dprintf ("font", "opened section %c%c%c%c ok\n", + section.name[0], section.name[1], + section.name[2], section.name[3]); +#endif + + if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_FONT_NAME, + sizeof (FONT_FORMAT_SECTION_NAMES_FONT_NAME) - 1) == 0) + { + font->name = read_section_as_string (§ion); + if (!font->name) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_POINT_SIZE, + sizeof (FONT_FORMAT_SECTION_NAMES_POINT_SIZE) - + 1) == 0) + { + if (read_section_as_short (§ion, &font->point_size) != 0) + goto fail; + } + else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_WEIGHT, + sizeof (FONT_FORMAT_SECTION_NAMES_WEIGHT) - 1) + == 0) + { + char *wt; + wt = read_section_as_string (§ion); + if (!wt) + continue; + /* Convert the weight string 'normal' or 'bold' into a number. */ + if (grub_strcmp (wt, "normal") == 0) + font->weight = FONT_WEIGHT_NORMAL; + else if (grub_strcmp (wt, "bold") == 0) + font->weight = FONT_WEIGHT_BOLD; + grub_free (wt); + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH, + sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_WIDTH) + - 1) == 0) + { + if (read_section_as_short (§ion, &font->max_char_width) != 0) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT, + sizeof (FONT_FORMAT_SECTION_NAMES_MAX_CHAR_HEIGHT) + - 1) == 0) + { + if (read_section_as_short (§ion, &font->max_char_height) != 0) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_ASCENT, + sizeof (FONT_FORMAT_SECTION_NAMES_ASCENT) - 1) + == 0) + { + if (read_section_as_short (§ion, &font->ascent) != 0) + goto fail; + } + else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DESCENT, + sizeof (FONT_FORMAT_SECTION_NAMES_DESCENT) - 1) + == 0) + { + if (read_section_as_short (§ion, &font->descent) != 0) + goto fail; + } + else if (grub_memcmp (section.name, + FONT_FORMAT_SECTION_NAMES_CHAR_INDEX, + sizeof (FONT_FORMAT_SECTION_NAMES_CHAR_INDEX) - + 1) == 0) + { + if (load_font_index (file, section.length, font) != 0) + goto fail; + } + else if (grub_memcmp (section.name, FONT_FORMAT_SECTION_NAMES_DATA, + sizeof (FONT_FORMAT_SECTION_NAMES_DATA) - 1) == 0) + { + /* When the DATA section marker is reached, we stop reading. */ + break; + } + else + { + /* Unhandled section type, simply skip past it. */ +#if FONT_DEBUG >= 3 + grub_dprintf ("font", "Unhandled section type, skipping.\n"); +#endif + grub_off_t section_end = grub_file_tell (file) + section.length; + if ((int) grub_file_seek (file, section_end) == -1) + goto fail; + } + } + + if (!font->name) + { + grub_dprintf ("font", "Font has no name.\n"); + font->name = grub_strdup ("Unknown"); + } + +#if FONT_DEBUG >= 1 + grub_dprintf ("font", "Loaded font `%s'.\n" + "Ascent=%d Descent=%d MaxW=%d MaxH=%d Number of characters=%d.\n", + font->name, + font->ascent, font->descent, + font->max_char_width, font->max_char_height, font->num_chars); +#endif + + if (font->max_char_width == 0 + || font->max_char_height == 0 + || font->num_chars == 0 + || font->char_index == 0 || font->ascent == 0 || font->descent == 0) + { + grub_error (GRUB_ERR_BAD_FONT, + "invalid font file: missing some required data"); + goto fail; + } + + /* Add the font to the global font registry. */ + if (register_font (font) != 0) + goto fail; + + return font; + +fail: + if (file) + grub_file_close (file); + if (font) + font->file = 0; + + free_font (font); + return 0; +} + +/* Read a 16-bit big-endian integer from FILE, convert it to native byte + order, and store it in *VALUE. + Returns 0 on success, 1 on failure. */ +static int +read_be_uint16 (grub_file_t file, grub_uint16_t * value) +{ + if (grub_file_read (file, value, 2) != 2) + return 1; + *value = grub_be_to_cpu16 (*value); + return 0; +} + +static int +read_be_int16 (grub_file_t file, grub_int16_t * value) +{ + /* For the signed integer version, use the same code as for unsigned. */ + return read_be_uint16 (file, (grub_uint16_t *) value); +} + +/* Return a pointer to the character index entry for the glyph corresponding to + the codepoint CODE in the font FONT. If not found, return zero. */ +static inline struct char_index_entry * +find_glyph (const grub_font_t font, grub_uint32_t code) +{ + struct char_index_entry *table; + grub_size_t lo; + grub_size_t hi; + grub_size_t mid; + + table = font->char_index; + + /* Use BMP index if possible. */ + if (code < 0x10000 && font->bmp_idx) + { + if (font->bmp_idx[code] == 0xffff) + return 0; + return &table[font->bmp_idx[code]]; + } + + /* Do a binary search in `char_index', which is ordered by code point. */ + lo = 0; + hi = font->num_chars - 1; + + if (!table) + return 0; + + while (lo <= hi) + { + mid = lo + (hi - lo) / 2; + if (code < table[mid].code) + hi = mid - 1; + else if (code > table[mid].code) + lo = mid + 1; + else + return &table[mid]; + } + + return 0; +} + +/* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded + from the font file if has not been loaded yet. + Returns a pointer to the glyph if found, or 0 if it is not found. */ +static struct grub_font_glyph * +grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) +{ + struct char_index_entry *index_entry; + + index_entry = find_glyph (font, code); + if (index_entry) + { + struct grub_font_glyph *glyph = 0; + grub_uint16_t width; + grub_uint16_t height; + grub_int16_t xoff; + grub_int16_t yoff; + grub_int16_t dwidth; + int len; + + if (index_entry->glyph) + /* Return cached glyph. */ + return index_entry->glyph; + + if (!font->file) + /* No open file, can't load any glyphs. */ + return 0; + + /* Make sure we can find glyphs for error messages. Push active + error message to error stack and reset error message. */ + grub_error_push (); + + grub_file_seek (font->file, index_entry->offset); + + /* Read the glyph width, height, and baseline. */ + if (read_be_uint16 (font->file, &width) != 0 + || read_be_uint16 (font->file, &height) != 0 + || read_be_int16 (font->file, &xoff) != 0 + || read_be_int16 (font->file, &yoff) != 0 + || read_be_int16 (font->file, &dwidth) != 0) + { + remove_font (font); + return 0; + } + + len = (width * height + 7) / 8; + glyph = grub_malloc (sizeof (struct grub_font_glyph) + len); + if (!glyph) + { + remove_font (font); + return 0; + } + + glyph->font = font; + glyph->width = width; + glyph->height = height; + glyph->offset_x = xoff; + glyph->offset_y = yoff; + glyph->device_width = dwidth; + + /* Don't try to read empty bitmaps (e.g., space characters). */ + if (len != 0) + { + if (grub_file_read (font->file, glyph->bitmap, len) != len) + { + remove_font (font); + grub_free (glyph); + return 0; + } + } + + /* Restore old error message. */ + grub_error_pop (); + + /* Cache the glyph. */ + index_entry->glyph = glyph; + + return glyph; + } + + return 0; +} + +/* Free the memory used by FONT. + This should not be called if the font has been made available to + users (once it is added to the global font list), since there would + be the possibility of a dangling pointer. */ +static void +free_font (grub_font_t font) +{ + if (font) + { + if (font->file) + grub_file_close (font->file); + grub_free (font->name); + grub_free (font->family); + grub_free (font->char_index); + grub_free (font->bmp_idx); + grub_free (font); + } +} + +/* Add FONT to the global font registry. + Returns 0 upon success, nonzero on failure + (the font was not registered). */ +static int +register_font (grub_font_t font) +{ + struct grub_font_node *node = 0; + + node = grub_malloc (sizeof (struct grub_font_node)); + if (!node) + return 1; + + node->value = font; + node->next = grub_font_list; + grub_font_list = node; + + return 0; +} + +/* Remove the font from the global font list. We don't actually free the + font's memory since users could be holding references to the font. */ +static void +remove_font (grub_font_t font) +{ + struct grub_font_node **nextp, *cur; + + for (nextp = &grub_font_list, cur = *nextp; + cur; nextp = &cur->next, cur = cur->next) + { + if (cur->value == font) + { + *nextp = cur->next; + + /* Free the node, but not the font itself. */ + grub_free (cur); + + return; + } + } +} + +/* Get a font from the list of loaded fonts. This function will return + another font if the requested font is not available. If no fonts are + loaded, then a special 'null font' is returned, which contains no glyphs, + but is not a null pointer so the caller may omit checks for NULL. */ +grub_font_t +grub_font_get (const char *font_name) +{ + struct grub_font_node *node; + + for (node = grub_font_list; node; node = node->next) + { + grub_font_t font = node->value; + if (grub_strcmp (font->name, font_name) == 0) + return font; + } + + /* If no font by that name is found, return the first font in the list + as a fallback. */ + if (grub_font_list && grub_font_list->value) + return grub_font_list->value; + else + /* The null_font is a last resort. */ + return &null_font; +} + +/* Get the full name of the font. */ +const char * +grub_font_get_name (grub_font_t font) +{ + return font->name; +} + +/* Get the maximum width of any character in the font in pixels. */ +int +grub_font_get_max_char_width (grub_font_t font) +{ + return font->max_char_width; +} + +/* Get the distance in pixels from the baseline to the lowest descenders + (for instance, in a lowercase 'y', 'g', etc.). */ +int +grub_font_get_descent (grub_font_t font) +{ + return font->descent; +} + +/* FIXME: not correct for all fonts. */ +int +grub_font_get_xheight (grub_font_t font) +{ + return font->ascent / 2; +} + +/* Get the *standard leading* of the font in pixel, which is the spacing + between two lines of text. Specifically, it is the space between the + descent of one line and the ascent of the next line. This is included + in the *height* metric. */ +int +grub_font_get_leading (grub_font_t font) +{ + return font->leading; +} + +/* Get the distance in pixels between baselines of adjacent lines of text. */ +int +grub_font_get_height (grub_font_t font) +{ + return font->ascent + font->descent + font->leading; +} + +/* Get the glyph for FONT corresponding to the Unicode code point CODE. + Returns the ASCII glyph for the code if no other fonts are available. + The glyphs are cached once loaded. */ +struct grub_font_glyph * +grub_font_get_glyph (grub_font_t font, grub_uint32_t code) +{ + struct grub_font_glyph *glyph = 0; + if (font) + glyph = grub_font_get_glyph_internal (font, code); + if (glyph == 0) + { + glyph = ascii_glyph_lookup (code); + } + return glyph; +} + + +/* Calculate a subject value representing "how similar" two fonts are. + This is used to prioritize the order that fonts are scanned for missing + glyphs. The object is to select glyphs from the most similar font + possible, for the best appearance. + The heuristic is crude, but it helps greatly when fonts of similar + sizes are used so that tiny 8 point glyphs are not mixed into a string + of 24 point text unless there is no other choice. */ +static int +get_font_diversity (grub_font_t a, grub_font_t b) +{ + int d; + + d = 0; + + if (a->ascent && b->ascent) + d += grub_abs (a->ascent - b->ascent) * 8; + else + /* Penalty for missing attributes. */ + d += 50; + + if (a->max_char_height && b->max_char_height) + d += grub_abs (a->max_char_height - b->max_char_height) * 8; + else + /* Penalty for missing attributes. */ + d += 50; + + /* Weight is a minor factor. */ + d += (a->weight != b->weight) ? 5 : 0; + + return d; +} + +/* Get a glyph corresponding to the codepoint CODE. If FONT contains the + specified glyph, then it is returned. Otherwise, all other loaded fonts + are searched until one is found that contains a glyph for CODE. + If no glyph is available for CODE in the loaded fonts, then a glyph + representing an unknown character is returned. + This function never returns NULL. + The returned glyph is owned by the font manager and should not be freed + by the caller. The glyphs are cached. */ +struct grub_font_glyph * +grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code) +{ + struct grub_font_glyph *glyph; + struct grub_font_node *node; + /* Keep track of next node, in case there's an I/O error in + grub_font_get_glyph_internal() and the font is removed from the list. */ + struct grub_font_node *next; + /* Information on the best glyph found so far, to help find the glyph in + the best matching to the requested one. */ + int best_diversity; + struct grub_font_glyph *best_glyph; + + if (font) + { + /* First try to get the glyph from the specified font. */ + glyph = grub_font_get_glyph_internal (font, code); + if (glyph) + return glyph; + } + + /* Otherwise, search all loaded fonts for the glyph and use the one from + the font that best matches the requested font. */ + best_diversity = 10000; + best_glyph = 0; + + for (node = grub_font_list; node; node = next) + { + grub_font_t curfont; + + curfont = node->value; + next = node->next; + + glyph = grub_font_get_glyph_internal (curfont, code); + if (glyph && !font) + return glyph; + if (glyph) + { + int d; + + d = get_font_diversity (curfont, font); + if (d < best_diversity) + { + best_diversity = d; + best_glyph = glyph; + } + } + } + + return best_glyph; +} + +#if 0 +static struct grub_font_glyph * +grub_font_dup_glyph (struct grub_font_glyph *glyph) +{ + static struct grub_font_glyph *ret; + ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8); + if (!ret) + return NULL; + grub_memcpy (ret, glyph, sizeof (*ret) + + (glyph->width * glyph->height + 7) / 8); + return ret; +} +#endif + +/* FIXME: suboptimal. */ +static void +grub_font_blit_glyph (struct grub_font_glyph *target, + struct grub_font_glyph *src, unsigned dx, unsigned dy) +{ + unsigned src_bit, tgt_bit, src_byte, tgt_byte; + unsigned i, j; + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i) % 8; + src_byte = (src->width * i) / 8; + tgt_bit = (target->width * (dy + i) + dx) % 8; + tgt_byte = (target->width * (dy + i) + dx) / 8; + for (j = 0; j < src->width; j++) + { + target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit) + & 0x80) >> tgt_bit; + src_bit++; + tgt_bit++; + if (src_bit == 8) + { + src_byte++; + src_bit = 0; + } + if (tgt_bit == 8) + { + tgt_byte++; + tgt_bit = 0; + } + } + } +} + +static void +grub_font_blit_glyph_mirror (struct grub_font_glyph *target, + struct grub_font_glyph *src, + unsigned dx, unsigned dy) +{ + unsigned tgt_bit, src_byte, tgt_byte; + signed src_bit; + unsigned i, j; + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i + src->width - 1) % 8; + src_byte = (src->width * i + src->width - 1) / 8; + tgt_bit = (target->width * (dy + i) + dx) % 8; + tgt_byte = (target->width * (dy + i) + dx) / 8; + for (j = 0; j < src->width; j++) + { + target->bitmap[tgt_byte] |= ((src->bitmap[src_byte] << src_bit) + & 0x80) >> tgt_bit; + src_bit--; + tgt_bit++; + if (src_bit == -1) + { + src_byte--; + src_bit = 7; + } + if (tgt_bit == 8) + { + tgt_byte++; + tgt_bit = 0; + } + } + } +} + +/* Context for blit_comb. */ +struct blit_comb_ctx +{ + struct grub_font_glyph *glyph; + int *device_width; + struct grub_video_signed_rect bounds; +}; + +/* Helper for blit_comb. */ +static void +do_blit (struct grub_font_glyph *src, signed dx, signed dy, + struct blit_comb_ctx *ctx) +{ + if (ctx->glyph) + grub_font_blit_glyph (ctx->glyph, src, dx - ctx->glyph->offset_x, + (ctx->glyph->height + ctx->glyph->offset_y) + dy); + if (dx < ctx->bounds.x) + { + ctx->bounds.width += ctx->bounds.x - dx; + ctx->bounds.x = dx; + } + if (ctx->bounds.y > -src->height - dy) + { + ctx->bounds.height += ctx->bounds.y - (-src->height - dy); + ctx->bounds.y = (-src->height - dy); + } + if (dx + src->width - ctx->bounds.x >= (signed) ctx->bounds.width) + ctx->bounds.width = dx + src->width - ctx->bounds.x + 1; + if ((signed) ctx->bounds.height < src->height + (-src->height - dy) + - ctx->bounds.y) + ctx->bounds.height = src->height + (-src->height - dy) - ctx->bounds.y; +} + +/* Helper for blit_comb. */ +static inline void +add_device_width (int val, struct blit_comb_ctx *ctx) +{ + if (ctx->glyph) + ctx->glyph->device_width += val; + if (ctx->device_width) + *ctx->device_width += val; +} + +static void +blit_comb (const struct grub_unicode_glyph *glyph_id, + struct grub_font_glyph *glyph, + struct grub_video_signed_rect *bounds_out, + struct grub_font_glyph *main_glyph, + struct grub_font_glyph **combining_glyphs, int *device_width) +{ + struct blit_comb_ctx ctx = { + .glyph = glyph, + .device_width = device_width + }; + unsigned i; + signed above_rightx, above_righty; + signed above_leftx, above_lefty; + signed below_rightx, below_righty; + signed min_devwidth = 0; + const struct grub_unicode_combining *comb; + + if (glyph) + glyph->device_width = main_glyph->device_width; + if (device_width) + *device_width = main_glyph->device_width; + + ctx.bounds.x = main_glyph->offset_x; + ctx.bounds.y = main_glyph->offset_y; + ctx.bounds.width = main_glyph->width; + ctx.bounds.height = main_glyph->height; + + above_rightx = main_glyph->offset_x + main_glyph->width; + above_righty = ctx.bounds.y + ctx.bounds.height; + + above_leftx = main_glyph->offset_x; + above_lefty = ctx.bounds.y + ctx.bounds.height; + + below_rightx = ctx.bounds.x + ctx.bounds.width; + below_righty = ctx.bounds.y; + + comb = grub_unicode_get_comb (glyph_id); + + for (i = 0; i < glyph_id->ncomb; i++) + { + grub_int16_t space = 0; + /* Center by default. */ + grub_int16_t targetx; + + if (!combining_glyphs[i]) + continue; + targetx = (ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x; + /* CGJ is to avoid diacritics reordering. */ + if (comb[i].code + == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER) + continue; + switch (comb[i].type) + { + case GRUB_UNICODE_COMB_OVERLAY: + do_blit (combining_glyphs[i], + targetx, + (ctx.bounds.height - combining_glyphs[i]->height) / 2 + - (ctx.bounds.height + ctx.bounds.y), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_ATTACHED_ABOVE_RIGHT: + do_blit (combining_glyphs[i], above_rightx, -above_righty, &ctx); + above_rightx += combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_ABOVE_RIGHT: + do_blit (combining_glyphs[i], above_rightx, + -(above_righty + combining_glyphs[i]->height), &ctx); + above_rightx += combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_ABOVE_LEFT: + above_leftx -= combining_glyphs[i]->width; + do_blit (combining_glyphs[i], above_leftx, + -(above_lefty + combining_glyphs[i]->height), &ctx); + break; + + case GRUB_UNICODE_COMB_BELOW_RIGHT: + do_blit (combining_glyphs[i], below_rightx, below_righty, &ctx); + below_rightx += combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_HEBREW_HOLAM: + if (glyph_id->base != GRUB_UNICODE_HEBREW_WAW) + targetx = + main_glyph->offset_x - combining_glyphs[i]->width - + (combining_glyphs[i]->width + 3) / 4; + goto above_on_main; + + case GRUB_UNICODE_COMB_HEBREW_SIN_DOT: + targetx = main_glyph->offset_x + combining_glyphs[i]->width / 4; + goto above_on_main; + + case GRUB_UNICODE_COMB_HEBREW_SHIN_DOT: + targetx = + main_glyph->width + main_glyph->offset_x - + combining_glyphs[i]->width; + above_on_main: + space = combining_glyphs[i]->offset_y + - grub_font_get_xheight (combining_glyphs[i]->font) - 1; + if (space <= 0) + space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8; + do_blit (combining_glyphs[i], targetx, + -(main_glyph->height + main_glyph->offset_y + space + + combining_glyphs[i]->height), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + /* TODO: Put dammah, fathah and alif nearer to shadda. */ + case GRUB_UNICODE_COMB_SYRIAC_SUPERSCRIPT_ALAPH: + case GRUB_UNICODE_COMB_ARABIC_DAMMAH: + case GRUB_UNICODE_COMB_ARABIC_DAMMATAN: + case GRUB_UNICODE_COMB_ARABIC_FATHATAN: + case GRUB_UNICODE_COMB_ARABIC_FATHAH: + case GRUB_UNICODE_COMB_ARABIC_SUPERSCRIPT_ALIF: + case GRUB_UNICODE_COMB_ARABIC_SUKUN: + case GRUB_UNICODE_COMB_ARABIC_SHADDA: + case GRUB_UNICODE_COMB_HEBREW_RAFE: + case GRUB_UNICODE_STACK_ABOVE: + stacked_above: + space = combining_glyphs[i]->offset_y + - grub_font_get_xheight (combining_glyphs[i]->font) - 1; + if (space <= 0) + space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8; + /* Fallthrough. */ + case GRUB_UNICODE_STACK_ATTACHED_ABOVE: + do_blit (combining_glyphs[i], targetx, + -(ctx.bounds.height + ctx.bounds.y + space + + combining_glyphs[i]->height), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_HEBREW_DAGESH: + do_blit (combining_glyphs[i], targetx, + -(ctx.bounds.height / 2 + ctx.bounds.y + + combining_glyphs[i]->height / 2), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_HEBREW_SHEVA: + case GRUB_UNICODE_COMB_HEBREW_HIRIQ: + case GRUB_UNICODE_COMB_HEBREW_QAMATS: + case GRUB_UNICODE_COMB_HEBREW_TSERE: + case GRUB_UNICODE_COMB_HEBREW_SEGOL: + /* TODO: placement in final kaf and under reish. */ + + case GRUB_UNICODE_COMB_HEBREW_HATAF_SEGOL: + case GRUB_UNICODE_COMB_HEBREW_HATAF_PATAH: + case GRUB_UNICODE_COMB_HEBREW_HATAF_QAMATS: + case GRUB_UNICODE_COMB_HEBREW_PATAH: + case GRUB_UNICODE_COMB_HEBREW_QUBUTS: + case GRUB_UNICODE_COMB_HEBREW_METEG: + /* TODO: Put kasra and kasratan under shadda. */ + case GRUB_UNICODE_COMB_ARABIC_KASRA: + case GRUB_UNICODE_COMB_ARABIC_KASRATAN: + /* I don't know how ypogegrammeni differs from subscript. */ + case GRUB_UNICODE_COMB_YPOGEGRAMMENI: + case GRUB_UNICODE_STACK_BELOW: + stacked_below: + space = -(combining_glyphs[i]->offset_y + + combining_glyphs[i]->height); + if (space <= 0) + space = 1 + (grub_font_get_xheight (main_glyph->font)) / 8; + /* Fallthrough. */ + + case GRUB_UNICODE_STACK_ATTACHED_BELOW: + do_blit (combining_glyphs[i], targetx, -(ctx.bounds.y - space), + &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; + + case GRUB_UNICODE_COMB_MN: + switch (comb[i].code) + { + case GRUB_UNICODE_THAANA_ABAFILI: + case GRUB_UNICODE_THAANA_AABAAFILI: + case GRUB_UNICODE_THAANA_UBUFILI: + case GRUB_UNICODE_THAANA_OOBOOFILI: + case GRUB_UNICODE_THAANA_EBEFILI: + case GRUB_UNICODE_THAANA_EYBEYFILI: + case GRUB_UNICODE_THAANA_OBOFILI: + case GRUB_UNICODE_THAANA_OABOAFILI: + case GRUB_UNICODE_THAANA_SUKUN: + goto stacked_above; + case GRUB_UNICODE_THAANA_IBIFILI: + case GRUB_UNICODE_THAANA_EEBEEFILI: + goto stacked_below; + } + /* Fall through. */ + default: + { + /* Default handling. Just draw combining character on top + of base character. + FIXME: support more unicode types correctly. + */ + do_blit (combining_glyphs[i], + main_glyph->device_width + + combining_glyphs[i]->offset_x, + -(combining_glyphs[i]->height + + combining_glyphs[i]->offset_y), &ctx); + add_device_width (combining_glyphs[i]->device_width, &ctx); + } + } + } + add_device_width ((above_rightx > + below_rightx ? above_rightx : below_rightx) - + (main_glyph->offset_x + main_glyph->width), &ctx); + add_device_width (above_leftx - main_glyph->offset_x, &ctx); + if (glyph && glyph->device_width < min_devwidth) + glyph->device_width = min_devwidth; + if (device_width && *device_width < min_devwidth) + *device_width = min_devwidth; + + if (bounds_out) + *bounds_out = ctx.bounds; +} + +static struct grub_font_glyph * +grub_font_construct_dry_run (grub_font_t hinted_font, + const struct grub_unicode_glyph *glyph_id, + struct grub_video_signed_rect *bounds, + struct grub_font_glyph **combining_glyphs, + int *device_width) +{ + struct grub_font_glyph *main_glyph = NULL; + grub_uint32_t desired_attributes = 0; + unsigned i; + grub_uint32_t base = glyph_id->base; + const struct grub_unicode_combining *comb; + + if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED) + desired_attributes |= GRUB_FONT_CODE_RIGHT_JOINED; + + if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED) + desired_attributes |= GRUB_FONT_CODE_LEFT_JOINED; + + comb = grub_unicode_get_comb (glyph_id); + + if (base == 'i' || base == 'j') + { + for (i = 0; i < glyph_id->ncomb; i++) + if (comb[i].type == GRUB_UNICODE_STACK_ABOVE) + break; + if (i < glyph_id->ncomb && base == 'i') + base = GRUB_UNICODE_DOTLESS_LOWERCASE_I; + if (i < glyph_id->ncomb && base == 'j') + base = GRUB_UNICODE_DOTLESS_LOWERCASE_J; + } + + main_glyph = grub_font_get_glyph_with_fallback (hinted_font, base + | desired_attributes); + + if (!main_glyph) + main_glyph = grub_font_get_glyph_with_fallback (hinted_font, + base); + + /* Glyph not available in any font. Use ASCII fallback. */ + if (!main_glyph) + main_glyph = ascii_glyph_lookup (base); + + /* Glyph not available in any font. Return unknown glyph. */ + if (!main_glyph) + return NULL; + + if (device_width) + *device_width = main_glyph->device_width; + + if (!glyph_id->ncomb && !glyph_id->attributes) + return main_glyph; + + if (glyph_id->ncomb && !combining_glyphs) + { + grub_errno = GRUB_ERR_NONE; + return main_glyph; + } + + for (i = 0; i < glyph_id->ncomb; i++) + combining_glyphs[i] + = grub_font_get_glyph_with_fallback (main_glyph->font, + comb[i].code); + + blit_comb (glyph_id, NULL, bounds, main_glyph, combining_glyphs, + device_width); + + return main_glyph; +} + +static struct grub_font_glyph **render_combining_glyphs = 0; +static grub_size_t render_max_comb_glyphs = 0; + +static void +ensure_comb_space (const struct grub_unicode_glyph *glyph_id) +{ + if (glyph_id->ncomb <= render_max_comb_glyphs) + return; + + render_max_comb_glyphs = 2 * glyph_id->ncomb; + if (render_max_comb_glyphs < 8) + render_max_comb_glyphs = 8; + grub_free (render_combining_glyphs); + render_combining_glyphs = grub_malloc (render_max_comb_glyphs + * sizeof (render_combining_glyphs[0])); + if (!render_combining_glyphs) + grub_errno = 0; +} + +int +grub_font_get_constructed_device_width (grub_font_t hinted_font, + const struct grub_unicode_glyph + *glyph_id) +{ + int ret; + struct grub_font_glyph *main_glyph; + + ensure_comb_space (glyph_id); + + main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id, NULL, + render_combining_glyphs, &ret); + if (!main_glyph) + return unknown_glyph->device_width; + return ret; +} + +struct grub_font_glyph * +grub_font_construct_glyph (grub_font_t hinted_font, + const struct grub_unicode_glyph *glyph_id) +{ + struct grub_font_glyph *main_glyph; + struct grub_video_signed_rect bounds; + static struct grub_font_glyph *glyph = 0; + static grub_size_t max_glyph_size = 0; + + ensure_comb_space (glyph_id); + + main_glyph = grub_font_construct_dry_run (hinted_font, glyph_id, + &bounds, render_combining_glyphs, + NULL); + + if (!main_glyph) + return unknown_glyph; + + if (!render_combining_glyphs && glyph_id->ncomb) + return main_glyph; + + if (!glyph_id->ncomb && !glyph_id->attributes) + return main_glyph; + + if (max_glyph_size < sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) + { + grub_free (glyph); + max_glyph_size = (sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) * 2; + if (max_glyph_size < 8) + max_glyph_size = 8; + glyph = grub_malloc (max_glyph_size); + } + if (!glyph) + { + grub_errno = GRUB_ERR_NONE; + return main_glyph; + } + + grub_memset (glyph, 0, sizeof (*glyph) + + (bounds.width * bounds.height + + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT); + + glyph->font = main_glyph->font; + glyph->width = bounds.width; + glyph->height = bounds.height; + glyph->offset_x = bounds.x; + glyph->offset_y = bounds.y; + + if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR) + grub_font_blit_glyph_mirror (glyph, main_glyph, + main_glyph->offset_x - glyph->offset_x, + (glyph->height + glyph->offset_y) + - (main_glyph->height + + main_glyph->offset_y)); + else + grub_font_blit_glyph (glyph, main_glyph, + main_glyph->offset_x - glyph->offset_x, + (glyph->height + glyph->offset_y) + - (main_glyph->height + main_glyph->offset_y)); + + blit_comb (glyph_id, glyph, NULL, main_glyph, render_combining_glyphs, NULL); + + return glyph; +} + +/* Draw the specified glyph at (x, y). The y coordinate designates the + baseline of the character, while the x coordinate designates the left + side location of the character. */ +grub_err_t +grub_font_draw_glyph (struct grub_font_glyph * glyph, + grub_video_color_t color, int left_x, int baseline_y) +{ + struct grub_video_bitmap glyph_bitmap; + + /* Don't try to draw empty glyphs (U+0020, etc.). */ + if (glyph->width == 0 || glyph->height == 0) + return GRUB_ERR_NONE; + + glyph_bitmap.mode_info.width = glyph->width; + glyph_bitmap.mode_info.height = glyph->height; + glyph_bitmap.mode_info.mode_type + = (1 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP; + glyph_bitmap.mode_info.blit_format = GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED; + glyph_bitmap.mode_info.bpp = 1; + + /* Really 1 bit per pixel. */ + glyph_bitmap.mode_info.bytes_per_pixel = 0; + + /* Packed densely as bits. */ + glyph_bitmap.mode_info.pitch = glyph->width; + + glyph_bitmap.mode_info.number_of_colors = 2; + glyph_bitmap.mode_info.bg_red = 0; + glyph_bitmap.mode_info.bg_green = 0; + glyph_bitmap.mode_info.bg_blue = 0; + glyph_bitmap.mode_info.bg_alpha = 0; + grub_video_unmap_color (color, + &glyph_bitmap.mode_info.fg_red, + &glyph_bitmap.mode_info.fg_green, + &glyph_bitmap.mode_info.fg_blue, + &glyph_bitmap.mode_info.fg_alpha); + glyph_bitmap.data = glyph->bitmap; + + int bitmap_left = left_x + glyph->offset_x; + int bitmap_bottom = baseline_y - glyph->offset_y; + int bitmap_top = bitmap_bottom - glyph->height; + + return grub_video_blit_bitmap (&glyph_bitmap, GRUB_VIDEO_BLIT_BLEND, + bitmap_left, bitmap_top, + 0, 0, glyph->width, glyph->height); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/font/font_cmd.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/font/font_cmd.c new file mode 100644 index 0000000..f7e1113 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/font/font_cmd.c @@ -0,0 +1,117 @@ +/* font_cmd.c - Font command definition. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +static grub_uint8_t g_font_lock = 0; + +static grub_err_t +loadfont_command (grub_command_t cmd __attribute__ ((unused)), + int argc, + char **args) +{ + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + if (g_font_lock) return 0; + + while (argc--) + if (grub_font_load (*args++) == 0) + { + if (!grub_errno) + return grub_error (GRUB_ERR_BAD_FONT, "invalid font"); + return grub_errno; + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +lsfonts_command (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + struct grub_font_node *node; + + grub_puts_ (N_("Loaded fonts:")); + for (node = grub_font_list; node; node = node->next) + { + grub_font_t font = node->value; + grub_printf ("%s\n", grub_font_get_name (font)); + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +lockfont_command (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) +{ + if (args[0] && args[0][0] == '1') + { + g_font_lock = 1; + } + else + { + g_font_lock = 0; + } + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_loadfont, cmd_lsfonts, cmd_lockfont; + +#if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_COREBOOT) +void grub_font_init (void) +#else +GRUB_MOD_INIT(font) +#endif +{ + grub_font_loader_init (); + + cmd_loadfont = + grub_register_command ("loadfont", loadfont_command, + N_("FILE..."), + N_("Specify one or more font files to load.")); + cmd_lsfonts = + grub_register_command ("lsfonts", lsfonts_command, + 0, N_("List the loaded fonts.")); + cmd_lockfont = + grub_register_command ("lockfont", lockfont_command, + 0, N_("Lock fonts.")); +} + +#if defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_COREBOOT) +void grub_font_fini (void) +#else +GRUB_MOD_FINI(font) +#endif +{ + /* TODO: Determine way to free allocated resources. + Warning: possible pointer references could be in use. */ + + grub_unregister_command (cmd_loadfont); + grub_unregister_command (cmd_lsfonts); + grub_unregister_command (cmd_lockfont); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/btrfs.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/btrfs.c new file mode 100644 index 0000000..37b18c9 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/btrfs.c @@ -0,0 +1,2282 @@ +/* btrfs.c - B-tree file system. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2011,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +/* + * Tell zstd to expose functions that aren't part of the stable API, which + * aren't safe to use when linking against a dynamic library. We vendor in a + * specific zstd version, so we know what we're getting. We need these unstable + * functions to provide our own allocator, which uses grub_malloc(), to zstd. + */ +#define ZSTD_STATIC_LINKING_ONLY + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define GRUB_BTRFS_SIGNATURE "_BHRfS_M" + +/* From http://www.oberhumer.com/opensource/lzo/lzofaq.php + * LZO will expand incompressible data by a little amount. I still haven't + * computed the exact values, but I suggest using these formulas for + * a worst-case expansion calculation: + * + * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3 + * */ +#define GRUB_BTRFS_LZO_BLOCK_SIZE 4096 +#define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \ + (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3) + +#define ZSTD_BTRFS_MAX_WINDOWLOG 17 +#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG) + +typedef grub_uint8_t grub_btrfs_checksum_t[0x20]; +typedef grub_uint16_t grub_btrfs_uuid_t[8]; + +struct grub_btrfs_device +{ + grub_uint64_t device_id; + grub_uint64_t size; + grub_uint8_t dummy[0x62 - 0x10]; +} GRUB_PACKED; + +struct grub_btrfs_superblock +{ + grub_btrfs_checksum_t checksum; + grub_btrfs_uuid_t uuid; + grub_uint8_t dummy[0x10]; + grub_uint8_t signature[sizeof (GRUB_BTRFS_SIGNATURE) - 1]; + grub_uint64_t generation; + grub_uint64_t root_tree; + grub_uint64_t chunk_tree; + grub_uint8_t dummy2[0x20]; + grub_uint64_t root_dir_objectid; + grub_uint8_t dummy3[0x41]; + struct grub_btrfs_device this_device; + char label[0x100]; + grub_uint8_t dummy4[0x100]; + grub_uint8_t bootstrap_mapping[0x800]; +} GRUB_PACKED; + +struct btrfs_header +{ + grub_btrfs_checksum_t checksum; + grub_btrfs_uuid_t uuid; + grub_uint64_t bytenr; + grub_uint8_t dummy[0x28]; + grub_uint32_t nitems; + grub_uint8_t level; +} GRUB_PACKED; + +struct grub_btrfs_device_desc +{ + grub_device_t dev; + grub_uint64_t id; +}; + +struct grub_btrfs_data +{ + struct grub_btrfs_superblock sblock; + grub_uint64_t tree; + grub_uint64_t inode; + + struct grub_btrfs_device_desc *devices_attached; + unsigned n_devices_attached; + unsigned n_devices_allocated; + + /* Cached extent data. */ + grub_uint64_t extstart; + grub_uint64_t extend; + grub_uint64_t extino; + grub_uint64_t exttree; + grub_size_t extsize; + struct grub_btrfs_extent_data *extent; +}; + +struct grub_btrfs_chunk_item +{ + grub_uint64_t size; + grub_uint64_t dummy; + grub_uint64_t stripe_length; + grub_uint64_t type; +#define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07 +#define GRUB_BTRFS_CHUNK_TYPE_SINGLE 0x00 +#define GRUB_BTRFS_CHUNK_TYPE_RAID0 0x08 +#define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10 +#define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED 0x20 +#define GRUB_BTRFS_CHUNK_TYPE_RAID10 0x40 +#define GRUB_BTRFS_CHUNK_TYPE_RAID5 0x80 +#define GRUB_BTRFS_CHUNK_TYPE_RAID6 0x100 + grub_uint8_t dummy2[0xc]; + grub_uint16_t nstripes; + grub_uint16_t nsubstripes; +} GRUB_PACKED; + +struct grub_btrfs_chunk_stripe +{ + grub_uint64_t device_id; + grub_uint64_t offset; + grub_btrfs_uuid_t device_uuid; +} GRUB_PACKED; + +struct grub_btrfs_leaf_node +{ + struct grub_btrfs_key key; + grub_uint32_t offset; + grub_uint32_t size; +} GRUB_PACKED; + +struct grub_btrfs_internal_node +{ + struct grub_btrfs_key key; + grub_uint64_t addr; + grub_uint64_t dummy; +} GRUB_PACKED; + +struct grub_btrfs_dir_item +{ + struct grub_btrfs_key key; + grub_uint8_t dummy[8]; + grub_uint16_t m; + grub_uint16_t n; +#define GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR 1 +#define GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY 2 +#define GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK 7 + grub_uint8_t type; + char name[0]; +} GRUB_PACKED; + +struct grub_btrfs_leaf_descriptor +{ + unsigned depth; + unsigned allocated; + struct + { + grub_disk_addr_t addr; + unsigned iter; + unsigned maxiter; + int leaf; + } *data; +}; + +struct grub_btrfs_time +{ + grub_int64_t sec; + grub_uint32_t nanosec; +} GRUB_PACKED; + +struct grub_btrfs_inode +{ + grub_uint8_t dummy1[0x10]; + grub_uint64_t size; + grub_uint8_t dummy2[0x70]; + struct grub_btrfs_time mtime; +} GRUB_PACKED; + +struct grub_btrfs_extent_data +{ + grub_uint64_t dummy; + grub_uint64_t size; + grub_uint8_t compression; + grub_uint8_t encryption; + grub_uint16_t encoding; + grub_uint8_t type; + union + { + char inl[0]; + struct + { + grub_uint64_t laddr; + grub_uint64_t compressed_size; + grub_uint64_t offset; + grub_uint64_t filled; + }; + }; +} GRUB_PACKED; + +#define GRUB_BTRFS_EXTENT_INLINE 0 +#define GRUB_BTRFS_EXTENT_REGULAR 1 + +#define GRUB_BTRFS_COMPRESSION_NONE 0 +#define GRUB_BTRFS_COMPRESSION_ZLIB 1 +#define GRUB_BTRFS_COMPRESSION_LZO 2 +#define GRUB_BTRFS_COMPRESSION_ZSTD 3 + +#define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 + +static grub_uint64_t g_last_chunk_type = 0; +static grub_uint8_t g_last_compress_type = 0; + + +static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2, + 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2 +}; + +static grub_err_t +grub_btrfs_read_logical (struct grub_btrfs_data *data, + grub_disk_addr_t addr, void *buf, grub_size_t size, + int recursion_depth); + +static grub_err_t +read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb) +{ + struct grub_btrfs_superblock sblock; + unsigned i; + grub_err_t err = GRUB_ERR_NONE; + for (i = 0; i < ARRAY_SIZE (superblock_sectors); i++) + { + /* Don't try additional superblocks beyond device size. */ + if (i && (grub_le_to_cpu64 (sblock.this_device.size) + >> GRUB_DISK_SECTOR_BITS) <= superblock_sectors[i]) + break; + err = grub_disk_read (disk, superblock_sectors[i], 0, + sizeof (sblock), &sblock); + if (err == GRUB_ERR_OUT_OF_RANGE) + break; + + if (grub_memcmp ((char *) sblock.signature, GRUB_BTRFS_SIGNATURE, + sizeof (GRUB_BTRFS_SIGNATURE) - 1) != 0) + break; + if (i == 0 || grub_le_to_cpu64 (sblock.generation) + > grub_le_to_cpu64 (sb->generation)) + grub_memcpy (sb, &sblock, sizeof (sblock)); + } + + if ((err == GRUB_ERR_OUT_OF_RANGE || !err) && i == 0) + return grub_error (GRUB_ERR_BAD_FS, "not a Btrfs filesystem"); + + if (err == GRUB_ERR_OUT_OF_RANGE) + grub_errno = err = GRUB_ERR_NONE; + + return err; +} + +static int +key_cmp (const struct grub_btrfs_key *a, const struct grub_btrfs_key *b) +{ + if (grub_le_to_cpu64 (a->object_id) < grub_le_to_cpu64 (b->object_id)) + return -1; + if (grub_le_to_cpu64 (a->object_id) > grub_le_to_cpu64 (b->object_id)) + return +1; + + if (a->type < b->type) + return -1; + if (a->type > b->type) + return +1; + + if (grub_le_to_cpu64 (a->offset) < grub_le_to_cpu64 (b->offset)) + return -1; + if (grub_le_to_cpu64 (a->offset) > grub_le_to_cpu64 (b->offset)) + return +1; + return 0; +} + +static void +free_iterator (struct grub_btrfs_leaf_descriptor *desc) +{ + grub_free (desc->data); +} + +static grub_err_t +check_btrfs_header (struct grub_btrfs_data *data, struct btrfs_header *header, + grub_disk_addr_t addr) +{ + if (grub_le_to_cpu64 (header->bytenr) != addr) + { + grub_dprintf ("btrfs", "btrfs_header.bytenr is not equal node addr\n"); + return grub_error (GRUB_ERR_BAD_FS, + "header bytenr is not equal node addr"); + } + if (grub_memcmp (data->sblock.uuid, header->uuid, sizeof(grub_btrfs_uuid_t))) + { + grub_dprintf ("btrfs", "btrfs_header.uuid doesn't match sblock uuid\n"); + return grub_error (GRUB_ERR_BAD_FS, + "header uuid doesn't match sblock uuid"); + } + return GRUB_ERR_NONE; +} + +static grub_err_t +save_ref (struct grub_btrfs_leaf_descriptor *desc, + grub_disk_addr_t addr, unsigned i, unsigned m, int l) +{ + desc->depth++; + if (desc->allocated < desc->depth) + { + void *newdata; + desc->allocated *= 2; + newdata = grub_realloc (desc->data, sizeof (desc->data[0]) + * desc->allocated); + if (!newdata) + return grub_errno; + desc->data = newdata; + } + desc->data[desc->depth - 1].addr = addr; + desc->data[desc->depth - 1].iter = i; + desc->data[desc->depth - 1].maxiter = m; + desc->data[desc->depth - 1].leaf = l; + return GRUB_ERR_NONE; +} + +static int +next (struct grub_btrfs_data *data, + struct grub_btrfs_leaf_descriptor *desc, + grub_disk_addr_t * outaddr, grub_size_t * outsize, + struct grub_btrfs_key *key_out) +{ + grub_err_t err; + struct grub_btrfs_leaf_node leaf; + + for (; desc->depth > 0; desc->depth--) + { + desc->data[desc->depth - 1].iter++; + if (desc->data[desc->depth - 1].iter + < desc->data[desc->depth - 1].maxiter) + break; + } + if (desc->depth == 0) + return 0; + while (!desc->data[desc->depth - 1].leaf) + { + struct grub_btrfs_internal_node node; + struct btrfs_header head; + + err = grub_btrfs_read_logical (data, desc->data[desc->depth - 1].iter + * sizeof (node) + + sizeof (struct btrfs_header) + + desc->data[desc->depth - 1].addr, + &node, sizeof (node), 0); + if (err) + return -err; + + err = grub_btrfs_read_logical (data, grub_le_to_cpu64 (node.addr), + &head, sizeof (head), 0); + check_btrfs_header (data, &head, grub_le_to_cpu64 (node.addr)); + if (err) + return -err; + + save_ref (desc, grub_le_to_cpu64 (node.addr), 0, + grub_le_to_cpu32 (head.nitems), !head.level); + } + err = grub_btrfs_read_logical (data, desc->data[desc->depth - 1].iter + * sizeof (leaf) + + sizeof (struct btrfs_header) + + desc->data[desc->depth - 1].addr, &leaf, + sizeof (leaf), 0); + if (err) + return -err; + *outsize = grub_le_to_cpu32 (leaf.size); + *outaddr = desc->data[desc->depth - 1].addr + sizeof (struct btrfs_header) + + grub_le_to_cpu32 (leaf.offset); + *key_out = leaf.key; + return 1; +} + +static grub_err_t +lower_bound (struct grub_btrfs_data *data, + const struct grub_btrfs_key *key_in, + struct grub_btrfs_key *key_out, + grub_uint64_t root, + grub_disk_addr_t *outaddr, grub_size_t *outsize, + struct grub_btrfs_leaf_descriptor *desc, + int recursion_depth) +{ + grub_disk_addr_t addr = grub_le_to_cpu64 (root); + int depth = -1; + + if (desc) + { + desc->allocated = 16; + desc->depth = 0; + desc->data = grub_malloc (sizeof (desc->data[0]) * desc->allocated); + if (!desc->data) + return grub_errno; + } + + /* > 2 would work as well but be robust and allow a bit more just in case. + */ + if (recursion_depth > 10) + return grub_error (GRUB_ERR_BAD_FS, "too deep btrfs virtual nesting"); + + grub_dprintf ("btrfs", + "retrieving %" PRIxGRUB_UINT64_T + " %x %" PRIxGRUB_UINT64_T "\n", + key_in->object_id, key_in->type, key_in->offset); + + while (1) + { + grub_err_t err; + struct btrfs_header head; + + reiter: + depth++; + /* FIXME: preread few nodes into buffer. */ + err = grub_btrfs_read_logical (data, addr, &head, sizeof (head), + recursion_depth + 1); + check_btrfs_header (data, &head, addr); + if (err) + return err; + addr += sizeof (head); + if (head.level) + { + unsigned i; + struct grub_btrfs_internal_node node, node_last; + int have_last = 0; + grub_memset (&node_last, 0, sizeof (node_last)); + for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++) + { + err = grub_btrfs_read_logical (data, addr + i * sizeof (node), + &node, sizeof (node), + recursion_depth + 1); + if (err) + return err; + + grub_dprintf ("btrfs", + "internal node (depth %d) %" PRIxGRUB_UINT64_T + " %x %" PRIxGRUB_UINT64_T "\n", depth, + node.key.object_id, node.key.type, + node.key.offset); + + if (key_cmp (&node.key, key_in) == 0) + { + err = GRUB_ERR_NONE; + if (desc) + err = save_ref (desc, addr - sizeof (head), i, + grub_le_to_cpu32 (head.nitems), 0); + if (err) + return err; + addr = grub_le_to_cpu64 (node.addr); + goto reiter; + } + if (key_cmp (&node.key, key_in) > 0) + break; + node_last = node; + have_last = 1; + } + if (have_last) + { + err = GRUB_ERR_NONE; + if (desc) + err = save_ref (desc, addr - sizeof (head), i - 1, + grub_le_to_cpu32 (head.nitems), 0); + if (err) + return err; + addr = grub_le_to_cpu64 (node_last.addr); + goto reiter; + } + *outsize = 0; + *outaddr = 0; + grub_memset (key_out, 0, sizeof (*key_out)); + if (desc) + return save_ref (desc, addr - sizeof (head), -1, + grub_le_to_cpu32 (head.nitems), 0); + return GRUB_ERR_NONE; + } + { + unsigned i; + struct grub_btrfs_leaf_node leaf, leaf_last; + int have_last = 0; + for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++) + { + err = grub_btrfs_read_logical (data, addr + i * sizeof (leaf), + &leaf, sizeof (leaf), + recursion_depth + 1); + if (err) + return err; + + grub_dprintf ("btrfs", + "leaf (depth %d) %" PRIxGRUB_UINT64_T + " %x %" PRIxGRUB_UINT64_T "\n", depth, + leaf.key.object_id, leaf.key.type, leaf.key.offset); + + if (key_cmp (&leaf.key, key_in) == 0) + { + grub_memcpy (key_out, &leaf.key, sizeof (*key_out)); + *outsize = grub_le_to_cpu32 (leaf.size); + *outaddr = addr + grub_le_to_cpu32 (leaf.offset); + if (desc) + return save_ref (desc, addr - sizeof (head), i, + grub_le_to_cpu32 (head.nitems), 1); + return GRUB_ERR_NONE; + } + + if (key_cmp (&leaf.key, key_in) > 0) + break; + + have_last = 1; + leaf_last = leaf; + } + + if (have_last) + { + grub_memcpy (key_out, &leaf_last.key, sizeof (*key_out)); + *outsize = grub_le_to_cpu32 (leaf_last.size); + *outaddr = addr + grub_le_to_cpu32 (leaf_last.offset); + if (desc) + return save_ref (desc, addr - sizeof (head), i - 1, + grub_le_to_cpu32 (head.nitems), 1); + return GRUB_ERR_NONE; + } + *outsize = 0; + *outaddr = 0; + grub_memset (key_out, 0, sizeof (*key_out)); + if (desc) + return save_ref (desc, addr - sizeof (head), -1, + grub_le_to_cpu32 (head.nitems), 1); + return GRUB_ERR_NONE; + } + } +} + +/* Context for find_device. */ +struct find_device_ctx +{ + struct grub_btrfs_data *data; + grub_uint64_t id; + grub_device_t dev_found; +}; + +/* Helper for find_device. */ +static int +find_device_iter (const char *name, void *data) +{ + struct find_device_ctx *ctx = data; + grub_device_t dev; + grub_err_t err; + struct grub_btrfs_superblock sb; + + dev = grub_device_open (name); + if (!dev) + return 0; + if (!dev->disk) + { + grub_device_close (dev); + return 0; + } + err = read_sblock (dev->disk, &sb); + if (err == GRUB_ERR_BAD_FS) + { + grub_device_close (dev); + grub_errno = GRUB_ERR_NONE; + return 0; + } + if (err) + { + grub_device_close (dev); + grub_print_error (); + return 0; + } + if (grub_memcmp (ctx->data->sblock.uuid, sb.uuid, sizeof (sb.uuid)) != 0 + || sb.this_device.device_id != ctx->id) + { + grub_device_close (dev); + return 0; + } + + ctx->dev_found = dev; + return 1; +} + +static grub_device_t +find_device (struct grub_btrfs_data *data, grub_uint64_t id) +{ + struct find_device_ctx ctx = { + .data = data, + .id = id, + .dev_found = NULL + }; + unsigned i; + + for (i = 0; i < data->n_devices_attached; i++) + if (id == data->devices_attached[i].id) + return data->devices_attached[i].dev; + + grub_device_iterate (find_device_iter, &ctx); + + data->n_devices_attached++; + if (data->n_devices_attached > data->n_devices_allocated) + { + void *tmp; + data->n_devices_allocated = 2 * data->n_devices_attached + 1; + data->devices_attached + = grub_realloc (tmp = data->devices_attached, + data->n_devices_allocated + * sizeof (data->devices_attached[0])); + if (!data->devices_attached) + { + if (ctx.dev_found) + grub_device_close (ctx.dev_found); + data->devices_attached = tmp; + return NULL; + } + } + data->devices_attached[data->n_devices_attached - 1].id = id; + data->devices_attached[data->n_devices_attached - 1].dev = ctx.dev_found; + return ctx.dev_found; +} + +static grub_err_t +btrfs_read_from_chunk (struct grub_btrfs_data *data, + struct grub_btrfs_chunk_item *chunk, + grub_uint64_t stripen, grub_uint64_t stripe_offset, + int redundancy, grub_uint64_t csize, + void *buf) +{ + struct grub_btrfs_chunk_stripe *stripe; + grub_disk_addr_t paddr; + grub_device_t dev; + grub_err_t err; + + stripe = (struct grub_btrfs_chunk_stripe *) (chunk + 1); + /* Right now the redundancy handling is easy. + With RAID5-like it will be more difficult. */ + stripe += stripen + redundancy; + + paddr = grub_le_to_cpu64 (stripe->offset) + stripe_offset; + + grub_dprintf ("btrfs", "stripe %" PRIxGRUB_UINT64_T + " maps to 0x%" PRIxGRUB_UINT64_T "\n" + "reading paddr 0x%" PRIxGRUB_UINT64_T "\n", + stripen, stripe->offset, paddr); + + dev = find_device (data, stripe->device_id); + if (!dev) + { + grub_dprintf ("btrfs", + "couldn't find a necessary member device " + "of multi-device filesystem\n"); + grub_errno = GRUB_ERR_NONE; + return GRUB_ERR_READ_ERROR; + } + + err = grub_disk_read (dev->disk, paddr >> GRUB_DISK_SECTOR_BITS, + paddr & (GRUB_DISK_SECTOR_SIZE - 1), + csize, buf); + return err; +} + +struct raid56_buffer { + void *buf; + int data_is_valid; +}; + +static void +rebuild_raid5 (char *dest, struct raid56_buffer *buffers, + grub_uint64_t nstripes, grub_uint64_t csize) +{ + grub_uint64_t i; + int first; + + for(i = 0; buffers[i].data_is_valid && i < nstripes; i++); + + if (i == nstripes) + { + grub_dprintf ("btrfs", "called rebuild_raid5(), but all disks are OK\n"); + return; + } + + grub_dprintf ("btrfs", "rebuilding RAID 5 stripe #%" PRIuGRUB_UINT64_T "\n", i); + + for (i = 0, first = 1; i < nstripes; i++) + { + if (!buffers[i].data_is_valid) + continue; + + if (first) { + grub_memcpy(dest, buffers[i].buf, csize); + first = 0; + } else + grub_crypto_xor (dest, dest, buffers[i].buf, csize); + } +} + +static grub_err_t +raid6_recover_read_buffer (void *data, int disk_nr, + grub_uint64_t addr __attribute__ ((unused)), + void *dest, grub_size_t size) +{ + struct raid56_buffer *buffers = data; + + if (!buffers[disk_nr].data_is_valid) + return grub_errno = GRUB_ERR_READ_ERROR; + + grub_memcpy(dest, buffers[disk_nr].buf, size); + + return grub_errno = GRUB_ERR_NONE; +} + +static void +rebuild_raid6 (struct raid56_buffer *buffers, grub_uint64_t nstripes, + grub_uint64_t csize, grub_uint64_t parities_pos, void *dest, + grub_uint64_t stripen) + +{ + grub_raid6_recover_gen (buffers, nstripes, stripen, parities_pos, + dest, 0, csize, 0, raid6_recover_read_buffer); +} + +static grub_err_t +raid56_read_retry (struct grub_btrfs_data *data, + struct grub_btrfs_chunk_item *chunk, + grub_uint64_t stripe_offset, grub_uint64_t stripen, + grub_uint64_t csize, void *buf, grub_uint64_t parities_pos) +{ + struct raid56_buffer *buffers; + grub_uint64_t nstripes = grub_le_to_cpu16 (chunk->nstripes); + grub_uint64_t chunk_type = grub_le_to_cpu64 (chunk->type); + grub_err_t ret = GRUB_ERR_OUT_OF_MEMORY; + grub_uint64_t i, failed_devices; + + buffers = grub_zalloc (sizeof(*buffers) * nstripes); + if (!buffers) + goto cleanup; + + for (i = 0; i < nstripes; i++) + { + buffers[i].buf = grub_zalloc (csize); + if (!buffers[i].buf) + goto cleanup; + } + + for (failed_devices = 0, i = 0; i < nstripes; i++) + { + struct grub_btrfs_chunk_stripe *stripe; + grub_disk_addr_t paddr; + grub_device_t dev; + grub_err_t err; + + /* + * The struct grub_btrfs_chunk_stripe array lives + * behind struct grub_btrfs_chunk_item. + */ + stripe = (struct grub_btrfs_chunk_stripe *) (chunk + 1) + i; + + paddr = grub_le_to_cpu64 (stripe->offset) + stripe_offset; + grub_dprintf ("btrfs", "reading paddr %" PRIxGRUB_UINT64_T + " from stripe ID %" PRIxGRUB_UINT64_T "\n", + paddr, stripe->device_id); + + dev = find_device (data, stripe->device_id); + if (!dev) + { + grub_dprintf ("btrfs", "stripe %" PRIuGRUB_UINT64_T " FAILED (dev ID %" + PRIxGRUB_UINT64_T ")\n", i, stripe->device_id); + failed_devices++; + continue; + } + + err = grub_disk_read (dev->disk, paddr >> GRUB_DISK_SECTOR_BITS, + paddr & (GRUB_DISK_SECTOR_SIZE - 1), + csize, buffers[i].buf); + if (err == GRUB_ERR_NONE) + { + buffers[i].data_is_valid = 1; + grub_dprintf ("btrfs", "stripe %" PRIuGRUB_UINT64_T " OK (dev ID %" + PRIxGRUB_UINT64_T ")\n", i, stripe->device_id); + } + else + { + grub_dprintf ("btrfs", "stripe %" PRIuGRUB_UINT64_T + " READ FAILED (dev ID %" PRIxGRUB_UINT64_T ")\n", + i, stripe->device_id); + failed_devices++; + } + } + + if (failed_devices > 1 && (chunk_type & GRUB_BTRFS_CHUNK_TYPE_RAID5)) + { + grub_dprintf ("btrfs", "not enough disks for RAID 5: total %" PRIuGRUB_UINT64_T + ", missing %" PRIuGRUB_UINT64_T "\n", + nstripes, failed_devices); + ret = GRUB_ERR_READ_ERROR; + goto cleanup; + } + else if (failed_devices > 2 && (chunk_type & GRUB_BTRFS_CHUNK_TYPE_RAID6)) + { + grub_dprintf ("btrfs", "not enough disks for RAID 6: total %" PRIuGRUB_UINT64_T + ", missing %" PRIuGRUB_UINT64_T "\n", + nstripes, failed_devices); + ret = GRUB_ERR_READ_ERROR; + goto cleanup; + } + else + grub_dprintf ("btrfs", "enough disks for RAID 5: total %" + PRIuGRUB_UINT64_T ", missing %" PRIuGRUB_UINT64_T "\n", + nstripes, failed_devices); + + /* We have enough disks. So, rebuild the data. */ + if (chunk_type & GRUB_BTRFS_CHUNK_TYPE_RAID5) + rebuild_raid5 (buf, buffers, nstripes, csize); + else + rebuild_raid6 (buffers, nstripes, csize, parities_pos, buf, stripen); + + ret = GRUB_ERR_NONE; + cleanup: + if (buffers) + for (i = 0; i < nstripes; i++) + grub_free (buffers[i].buf); + grub_free (buffers); + + return ret; +} + +static grub_err_t +grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + void *buf, grub_size_t size, int recursion_depth) +{ + while (size > 0) + { + grub_uint8_t *ptr; + struct grub_btrfs_key *key; + struct grub_btrfs_chunk_item *chunk; + grub_uint64_t csize; + grub_err_t err = 0; + struct grub_btrfs_key key_out; + int challoc = 0; + struct grub_btrfs_key key_in; + grub_size_t chsize; + grub_disk_addr_t chaddr; + + grub_dprintf ("btrfs", "searching for laddr %" PRIxGRUB_UINT64_T "\n", + addr); + for (ptr = data->sblock.bootstrap_mapping; + ptr < data->sblock.bootstrap_mapping + + sizeof (data->sblock.bootstrap_mapping) + - sizeof (struct grub_btrfs_key);) + { + key = (struct grub_btrfs_key *) ptr; + if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK) + break; + chunk = (struct grub_btrfs_chunk_item *) (key + 1); + grub_dprintf ("btrfs", + "%" PRIxGRUB_UINT64_T " %" PRIxGRUB_UINT64_T " \n", + grub_le_to_cpu64 (key->offset), + grub_le_to_cpu64 (chunk->size)); + if (grub_le_to_cpu64 (key->offset) <= addr + && addr < grub_le_to_cpu64 (key->offset) + + grub_le_to_cpu64 (chunk->size)) + goto chunk_found; + ptr += sizeof (*key) + sizeof (*chunk) + + sizeof (struct grub_btrfs_chunk_stripe) + * grub_le_to_cpu16 (chunk->nstripes); + } + + key_in.object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); + key_in.type = GRUB_BTRFS_ITEM_TYPE_CHUNK; + key_in.offset = grub_cpu_to_le64 (addr); + err = lower_bound (data, &key_in, &key_out, + data->sblock.chunk_tree, + &chaddr, &chsize, NULL, recursion_depth); + if (err) + return err; + key = &key_out; + if (key->type != GRUB_BTRFS_ITEM_TYPE_CHUNK + || !(grub_le_to_cpu64 (key->offset) <= addr)) + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; + + challoc = 1; + err = grub_btrfs_read_logical (data, chaddr, chunk, chsize, + recursion_depth); + if (err) + { + grub_free (chunk); + return err; + } + + chunk_found: + { + grub_uint64_t stripen; + grub_uint64_t stripe_offset; + grub_uint64_t off = addr - grub_le_to_cpu64 (key->offset); + grub_uint64_t chunk_stripe_length; + grub_uint16_t nstripes; + unsigned redundancy = 1; + unsigned i, j; + int is_raid56; + grub_uint64_t parities_pos = 0; + + is_raid56 = !!(grub_le_to_cpu64 (chunk->type) & + (GRUB_BTRFS_CHUNK_TYPE_RAID5 | + GRUB_BTRFS_CHUNK_TYPE_RAID6)); + + if (grub_le_to_cpu64 (chunk->size) <= off) + { + grub_dprintf ("btrfs", "no chunk\n"); + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + } + + nstripes = grub_le_to_cpu16 (chunk->nstripes) ? : 1; + chunk_stripe_length = grub_le_to_cpu64 (chunk->stripe_length) ? : 512; + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T + "+0x%" PRIxGRUB_UINT64_T + " (%d stripes (%d substripes) of %" + PRIxGRUB_UINT64_T ")\n", + grub_le_to_cpu64 (key->offset), + grub_le_to_cpu64 (chunk->size), + nstripes, + grub_le_to_cpu16 (chunk->nsubstripes), + chunk_stripe_length); + + g_last_chunk_type = grub_le_to_cpu64 (chunk->type) & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE; + + switch (grub_le_to_cpu64 (chunk->type) + & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE) + { + case GRUB_BTRFS_CHUNK_TYPE_SINGLE: + { + grub_uint64_t stripe_length; + grub_dprintf ("btrfs", "single\n"); + stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), + nstripes, + NULL); + if (stripe_length == 0) + stripe_length = 512; + stripen = grub_divmod64 (off, stripe_length, &stripe_offset); + csize = (stripen + 1) * stripe_length - off; + break; + } + case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED: + case GRUB_BTRFS_CHUNK_TYPE_RAID1: + { + grub_dprintf ("btrfs", "RAID1\n"); + stripen = 0; + stripe_offset = off; + csize = grub_le_to_cpu64 (chunk->size) - off; + redundancy = 2; + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID0: + { + grub_uint64_t middle, high; + grub_uint64_t low; + grub_dprintf ("btrfs", "RAID0\n"); + middle = grub_divmod64 (off, + chunk_stripe_length, + &low); + + high = grub_divmod64 (middle, nstripes, + &stripen); + stripe_offset = + low + chunk_stripe_length * high; + csize = chunk_stripe_length - low; + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID10: + { + grub_uint64_t middle, high; + grub_uint64_t low; + grub_uint16_t nsubstripes; + nsubstripes = grub_le_to_cpu16 (chunk->nsubstripes) ? : 1; + middle = grub_divmod64 (off, + chunk_stripe_length, + &low); + + high = grub_divmod64 (middle, + nstripes / nsubstripes ? : 1, + &stripen); + stripen *= nsubstripes; + redundancy = nsubstripes; + stripe_offset = low + chunk_stripe_length + * high; + csize = chunk_stripe_length - low; + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID5: + case GRUB_BTRFS_CHUNK_TYPE_RAID6: + { + grub_uint64_t nparities, stripe_nr, high, low; + + redundancy = 1; /* no redundancy for now */ + + if (grub_le_to_cpu64 (chunk->type) & GRUB_BTRFS_CHUNK_TYPE_RAID5) + { + grub_dprintf ("btrfs", "RAID5\n"); + nparities = 1; + } + else + { + grub_dprintf ("btrfs", "RAID6\n"); + nparities = 2; + } + + /* + * RAID 6 layout consists of several stripes spread over + * the disks, e.g.: + * + * Disk_0 Disk_1 Disk_2 Disk_3 + * A0 B0 P0 Q0 + * Q1 A1 B1 P1 + * P2 Q2 A2 B2 + * + * Note: placement of the parities depend on row number. + * + * Pay attention that the btrfs terminology may differ from + * terminology used in other RAID implementations, e.g. LVM, + * dm or md. The main difference is that btrfs calls contiguous + * block of data on a given disk, e.g. A0, stripe instead of chunk. + * + * The variables listed below have following meaning: + * - stripe_nr is the stripe number excluding the parities + * (A0 = 0, B0 = 1, A1 = 2, B1 = 3, etc.), + * - high is the row number (0 for A0...Q0, 1 for Q1...P1, etc.), + * - stripen is the disk number in a row (0 for A0, Q1, P2, + * 1 for B0, A1, Q2, etc.), + * - off is the logical address to read, + * - chunk_stripe_length is the size of a stripe (typically 64 KiB), + * - nstripes is the number of disks in a row, + * - low is the offset of the data inside a stripe, + * - stripe_offset is the data offset in an array, + * - csize is the "potential" data to read; it will be reduced + * to size if the latter is smaller, + * - nparities is the number of parities (1 for RAID 5, 2 for + * RAID 6); used only in RAID 5/6 code. + */ + stripe_nr = grub_divmod64 (off, chunk_stripe_length, &low); + + /* + * stripen is computed without the parities + * (0 for A0, A1, A2, 1 for B0, B1, B2, etc.). + */ + high = grub_divmod64 (stripe_nr, nstripes - nparities, &stripen); + + /* + * The stripes are spread over the disks. Every each row their + * positions are shifted by 1 place. So, the real disks number + * change. Hence, we have to take into account current row number + * modulo nstripes (0 for A0, 1 for A1, 2 for A2, etc.). + */ + grub_divmod64 (high + stripen, nstripes, &stripen); + + /* + * parities_pos is equal to ((high - nparities) % nstripes) + * (see the diagram above). However, (high - nparities) can + * be negative, e.g. when high == 0, leading to an incorrect + * results. (high + nstripes - nparities) is always positive and + * modulo nstripes is equal to ((high - nparities) % nstripes). + */ + grub_divmod64 (high + nstripes - nparities, nstripes, &parities_pos); + + stripe_offset = chunk_stripe_length * high + low; + csize = chunk_stripe_length - low; + + break; + } + default: + grub_dprintf ("btrfs", "unsupported RAID\n"); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported RAID flags %" PRIxGRUB_UINT64_T, + grub_le_to_cpu64 (chunk->type)); + } + if (csize == 0) + return grub_error (GRUB_ERR_BUG, + "couldn't find the chunk descriptor"); + if (csize > (grub_uint64_t) size) + csize = size; + + for (j = 0; j < 2; j++) + { + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T + "+0x%" PRIxGRUB_UINT64_T + " (%d stripes (%d substripes) of %" + PRIxGRUB_UINT64_T ")\n", + grub_le_to_cpu64 (key->offset), + grub_le_to_cpu64 (chunk->size), + grub_le_to_cpu16 (chunk->nstripes), + grub_le_to_cpu16 (chunk->nsubstripes), + grub_le_to_cpu64 (chunk->stripe_length)); + grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n", + addr); + + if (is_raid56) + { + err = btrfs_read_from_chunk (data, chunk, stripen, + stripe_offset, + 0, /* no mirror */ + csize, buf); + grub_errno = GRUB_ERR_NONE; + if (err) + err = raid56_read_retry (data, chunk, stripe_offset, + stripen, csize, buf, parities_pos); + } + else + for (i = 0; i < redundancy; i++) + { + err = btrfs_read_from_chunk (data, chunk, stripen, + stripe_offset, + i, /* redundancy */ + csize, buf); + if (!err) + break; + grub_errno = GRUB_ERR_NONE; + } + if (!err) + break; + } + if (err) + return grub_errno = err; + } + size -= csize; + buf = (grub_uint8_t *) buf + csize; + addr += csize; + if (challoc) + grub_free (chunk); + } + return GRUB_ERR_NONE; +} + +static struct grub_btrfs_data * +grub_btrfs_mount (grub_device_t dev) +{ + struct grub_btrfs_data *data; + grub_err_t err; + + if (!dev->disk) + { + grub_error (GRUB_ERR_BAD_FS, "not BtrFS"); + return NULL; + } + + data = grub_zalloc (sizeof (*data)); + if (!data) + return NULL; + + err = read_sblock (dev->disk, &data->sblock); + if (err) + { + grub_free (data); + return NULL; + } + + data->n_devices_allocated = 16; + data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) + * data->n_devices_allocated); + if (!data->devices_attached) + { + grub_free (data); + return NULL; + } + data->n_devices_attached = 1; + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; + + return data; +} + +static void +grub_btrfs_unmount (struct grub_btrfs_data *data) +{ + unsigned i; + /* The device 0 is closed one layer upper. */ + for (i = 1; i < data->n_devices_attached; i++) + if (data->devices_attached[i].dev) + grub_device_close (data->devices_attached[i].dev); + grub_free (data->devices_attached); + grub_free (data->extent); + grub_free (data); +} + +static grub_err_t +grub_btrfs_read_inode (struct grub_btrfs_data *data, + struct grub_btrfs_inode *inode, grub_uint64_t num, + grub_uint64_t tree) +{ + struct grub_btrfs_key key_in, key_out; + grub_disk_addr_t elemaddr; + grub_size_t elemsize; + grub_err_t err; + + key_in.object_id = num; + key_in.type = GRUB_BTRFS_ITEM_TYPE_INODE_ITEM; + key_in.offset = 0; + + err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL, + 0); + if (err) + return err; + if (num != key_out.object_id + || key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_ITEM) + return grub_error (GRUB_ERR_BAD_FS, "inode not found"); + + return grub_btrfs_read_logical (data, elemaddr, inode, sizeof (*inode), 0); +} + +static void *grub_zstd_malloc (void *state __attribute__((unused)), size_t size) +{ + return grub_malloc (size); +} + +static void grub_zstd_free (void *state __attribute__((unused)), void *address) +{ + return grub_free (address); +} + +static ZSTD_customMem grub_zstd_allocator (void) +{ + ZSTD_customMem allocator; + + allocator.customAlloc = &grub_zstd_malloc; + allocator.customFree = &grub_zstd_free; + allocator.opaque = NULL; + + return allocator; +} + +static grub_ssize_t +grub_btrfs_zstd_decompress (char *ibuf, grub_size_t isize, grub_off_t off, + char *obuf, grub_size_t osize) +{ + void *allocated = NULL; + char *otmpbuf = obuf; + grub_size_t otmpsize = osize; + ZSTD_DCtx *dctx = NULL; + grub_size_t zstd_ret; + grub_ssize_t ret = -1; + + /* + * Zstd will fail if it can't fit the entire output in the destination + * buffer, so if osize isn't large enough, allocate a temporary buffer. + */ + if (otmpsize < ZSTD_BTRFS_MAX_INPUT) + { + allocated = grub_malloc (ZSTD_BTRFS_MAX_INPUT); + if (!allocated) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed allocate a zstd buffer"); + goto err; + } + otmpbuf = (char *) allocated; + otmpsize = ZSTD_BTRFS_MAX_INPUT; + } + + /* Create the ZSTD_DCtx. */ + dctx = ZSTD_createDCtx_advanced (grub_zstd_allocator ()); + if (!dctx) + { + /* ZSTD_createDCtx_advanced() only fails if it is out of memory. */ + grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed to create a zstd context"); + goto err; + } + + /* + * Get the real input size, there may be junk at the + * end of the frame. + */ + isize = ZSTD_findFrameCompressedSize (ibuf, isize); + if (ZSTD_isError (isize)) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "zstd data corrupted"); + goto err; + } + + /* Decompress and check for errors. */ + zstd_ret = ZSTD_decompressDCtx (dctx, otmpbuf, otmpsize, ibuf, isize); + if (ZSTD_isError (zstd_ret)) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "zstd data corrupted"); + goto err; + } + + /* + * Move the requested data into the obuf. obuf may be equal + * to otmpbuf, which is why grub_memmove() is required. + */ + grub_memmove (obuf, otmpbuf + off, osize); + ret = osize; + +err: + grub_free (allocated); + ZSTD_freeDCtx (dctx); + + return ret; +} + +static grub_ssize_t +grub_btrfs_lzo_decompress(char *ibuf, grub_size_t isize, grub_off_t off, + char *obuf, grub_size_t osize) +{ + grub_uint32_t total_size, cblock_size; + grub_size_t ret = 0; + char *ibuf0 = ibuf; + + total_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf)); + ibuf += sizeof (total_size); + + if (isize < total_size) + return -1; + + /* Jump forward to first block with requested data. */ + while (off >= GRUB_BTRFS_LZO_BLOCK_SIZE) + { + /* Don't let following uint32_t cross the page boundary. */ + if (((ibuf - ibuf0) & 0xffc) == 0xffc) + ibuf = ((ibuf - ibuf0 + 3) & ~3) + ibuf0; + + cblock_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf)); + ibuf += sizeof (cblock_size); + + if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE) + return -1; + + off -= GRUB_BTRFS_LZO_BLOCK_SIZE; + ibuf += cblock_size; + } + + while (osize > 0) + { + lzo_uint usize = GRUB_BTRFS_LZO_BLOCK_SIZE; + + /* Don't let following uint32_t cross the page boundary. */ + if (((ibuf - ibuf0) & 0xffc) == 0xffc) + ibuf = ((ibuf - ibuf0 + 3) & ~3) + ibuf0; + + cblock_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf)); + ibuf += sizeof (cblock_size); + + if (cblock_size > GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE) + return -1; + + /* Block partially filled with requested data. */ + if (off > 0 || osize < GRUB_BTRFS_LZO_BLOCK_SIZE) + { + grub_size_t to_copy = GRUB_BTRFS_LZO_BLOCK_SIZE - off; + grub_uint8_t *buf; + + if (to_copy > osize) + to_copy = osize; + + buf = grub_malloc (GRUB_BTRFS_LZO_BLOCK_SIZE); + if (!buf) + return -1; + + if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, buf, &usize, + NULL) != LZO_E_OK) + { + grub_free (buf); + return -1; + } + + if (to_copy > usize) + to_copy = usize; + grub_memcpy(obuf, buf + off, to_copy); + + osize -= to_copy; + ret += to_copy; + obuf += to_copy; + ibuf += cblock_size; + off = 0; + + grub_free (buf); + continue; + } + + /* Decompress whole block directly to output buffer. */ + if (lzo1x_decompress_safe ((lzo_bytep)ibuf, cblock_size, (lzo_bytep)obuf, + &usize, NULL) != LZO_E_OK) + return -1; + + osize -= usize; + ret += usize; + obuf += usize; + ibuf += cblock_size; + } + + return ret; +} + +static grub_ssize_t +grub_btrfs_extent_read (struct grub_btrfs_data *data, + grub_uint64_t ino, grub_uint64_t tree, + grub_off_t pos0, char *buf, grub_size_t len) +{ + grub_off_t pos = pos0; + while (len) + { + grub_size_t csize; + grub_err_t err; + grub_off_t extoff; + if (!data->extent || data->extstart > pos || data->extino != ino + || data->exttree != tree || data->extend <= pos) + { + struct grub_btrfs_key key_in, key_out; + grub_disk_addr_t elemaddr; + grub_size_t elemsize; + + grub_free (data->extent); + key_in.object_id = ino; + key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM; + key_in.offset = grub_cpu_to_le64 (pos); + err = lower_bound (data, &key_in, &key_out, tree, + &elemaddr, &elemsize, NULL, 0); + if (err) + return -1; + if (key_out.object_id != ino + || key_out.type != GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM) + { + grub_error (GRUB_ERR_BAD_FS, "extent not found"); + return -1; + } + if ((grub_ssize_t) elemsize < ((char *) &data->extent->inl + - (char *) data->extent)) + { + grub_error (GRUB_ERR_BAD_FS, "extent descriptor is too short"); + return -1; + } + data->extstart = grub_le_to_cpu64 (key_out.offset); + data->extsize = elemsize; + data->extent = grub_malloc (elemsize); + data->extino = ino; + data->exttree = tree; + if (!data->extent) + return grub_errno; + + err = grub_btrfs_read_logical (data, elemaddr, data->extent, + elemsize, 0); + if (err) + return err; + + data->extend = data->extstart + grub_le_to_cpu64 (data->extent->size); + if (data->extent->type == GRUB_BTRFS_EXTENT_REGULAR + && (char *) data->extent + elemsize + >= (char *) &data->extent->filled + sizeof (data->extent->filled)) + data->extend = + data->extstart + grub_le_to_cpu64 (data->extent->filled); + + grub_dprintf ("btrfs", "regular extent 0x%" PRIxGRUB_UINT64_T "+0x%" + PRIxGRUB_UINT64_T "\n", + grub_le_to_cpu64 (key_out.offset), + grub_le_to_cpu64 (data->extent->size)); + if (data->extend <= pos) + { + grub_error (GRUB_ERR_BAD_FS, "extent not found"); + return -1; + } + } + csize = data->extend - pos; + extoff = pos - data->extstart; + if (csize > len) + csize = len; + + if (data->extent->encryption) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "encryption not supported"); + return -1; + } + + g_last_compress_type = data->extent->compression; + + if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE + && data->extent->compression != GRUB_BTRFS_COMPRESSION_ZLIB + && data->extent->compression != GRUB_BTRFS_COMPRESSION_LZO + && data->extent->compression != GRUB_BTRFS_COMPRESSION_ZSTD) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "compression type 0x%x not supported", + data->extent->compression); + return -1; + } + + if (data->extent->encoding) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "encoding not supported"); + return -1; + } + + switch (data->extent->type) + { + case GRUB_BTRFS_EXTENT_INLINE: + if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB) + { + if (grub_zlib_decompress (data->extent->inl, data->extsize - + ((grub_uint8_t *) data->extent->inl + - (grub_uint8_t *) data->extent), + extoff, buf, csize) + != (grub_ssize_t) csize) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, + "premature end of compressed"); + return -1; + } + } + else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_LZO) + { + if (grub_btrfs_lzo_decompress(data->extent->inl, data->extsize - + ((grub_uint8_t *) data->extent->inl + - (grub_uint8_t *) data->extent), + extoff, buf, csize) + != (grub_ssize_t) csize) + return -1; + } + else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZSTD) + { + if (grub_btrfs_zstd_decompress (data->extent->inl, data->extsize - + ((grub_uint8_t *) data->extent->inl + - (grub_uint8_t *) data->extent), + extoff, buf, csize) + != (grub_ssize_t) csize) + return -1; + } + else + grub_memcpy (buf, data->extent->inl + extoff, csize); + break; + case GRUB_BTRFS_EXTENT_REGULAR: + if (!data->extent->laddr) + { + grub_memset (buf, 0, csize); + break; + } + + if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE) + { + char *tmp; + grub_uint64_t zsize; + grub_ssize_t ret; + + zsize = grub_le_to_cpu64 (data->extent->compressed_size); + tmp = grub_malloc (zsize); + if (!tmp) + return -1; + err = grub_btrfs_read_logical (data, + grub_le_to_cpu64 (data->extent->laddr), + tmp, zsize, 0); + if (err) + { + grub_free (tmp); + return -1; + } + + if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB) + ret = grub_zlib_decompress (tmp, zsize, extoff + + grub_le_to_cpu64 (data->extent->offset), + buf, csize); + else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_LZO) + ret = grub_btrfs_lzo_decompress (tmp, zsize, extoff + + grub_le_to_cpu64 (data->extent->offset), + buf, csize); + else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZSTD) + ret = grub_btrfs_zstd_decompress (tmp, zsize, extoff + + grub_le_to_cpu64 (data->extent->offset), + buf, csize); + else + ret = -1; + + grub_free (tmp); + + if (ret != (grub_ssize_t) csize) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, + "premature end of compressed"); + return -1; + } + + break; + } + err = grub_btrfs_read_logical (data, + grub_le_to_cpu64 (data->extent->laddr) + + grub_le_to_cpu64 (data->extent->offset) + + extoff, buf, csize, 0); + if (err) + return -1; + break; + default: + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported extent type 0x%x", data->extent->type); + return -1; + } + buf += csize; + pos += csize; + len -= csize; + } + return pos - pos0; +} + +static grub_err_t +get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, + grub_uint64_t *tree, grub_uint8_t *type) +{ + grub_err_t err; + grub_disk_addr_t elemaddr; + grub_size_t elemsize; + struct grub_btrfs_key key_out, key_in; + struct grub_btrfs_root_item ri; + + key_in.object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_ROOT_VOL_OBJECTID); + key_in.offset = 0; + key_in.type = GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM; + err = lower_bound (data, &key_in, &key_out, + data->sblock.root_tree, + &elemaddr, &elemsize, NULL, 0); + if (err) + return err; + if (key_in.object_id != key_out.object_id + || key_in.type != key_out.type + || key_in.offset != key_out.offset) + return grub_error (GRUB_ERR_BAD_FS, "no root"); + err = grub_btrfs_read_logical (data, elemaddr, &ri, + sizeof (ri), 0); + if (err) + return err; + key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + key->offset = 0; + key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); + *tree = ri.tree; + *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; + return GRUB_ERR_NONE; +} + +static grub_err_t +find_path (struct grub_btrfs_data *data, + const char *path, struct grub_btrfs_key *key, + grub_uint64_t *tree, grub_uint8_t *type) +{ + const char *slash = path; + grub_err_t err; + grub_disk_addr_t elemaddr; + grub_size_t elemsize; + grub_size_t allocated = 0; + struct grub_btrfs_dir_item *direl = NULL; + struct grub_btrfs_key key_out; + const char *ctoken; + grub_size_t ctokenlen; + char *path_alloc = NULL; + char *origpath = NULL; + unsigned symlinks_max = 32; + + err = get_root (data, key, tree, type); + if (err) + return err; + + origpath = grub_strdup (path); + if (!origpath) + return grub_errno; + + while (1) + { + while (path[0] == '/') + path++; + if (!path[0]) + break; + slash = grub_strchr (path, '/'); + if (!slash) + slash = path + grub_strlen (path); + ctoken = path; + ctokenlen = slash - path; + + if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + { + grub_free (path_alloc); + grub_free (origpath); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); + } + + if (ctokenlen == 1 && ctoken[0] == '.') + { + path = slash; + continue; + } + if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.') + { + key->type = GRUB_BTRFS_ITEM_TYPE_INODE_REF; + key->offset = -1; + + err = lower_bound (data, key, &key_out, *tree, &elemaddr, &elemsize, + NULL, 0); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + + if (key_out.type != key->type + || key->object_id != key_out.object_id) + { + grub_free (direl); + grub_free (path_alloc); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), origpath); + grub_free (origpath); + return err; + } + + *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; + key->object_id = key_out.offset; + + path = slash; + + continue; + } + + key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + key->offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen)); + + err = lower_bound (data, key, &key_out, *tree, &elemaddr, &elemsize, + NULL, 0); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + if (key_cmp (key, &key_out) != 0) + { + grub_free (direl); + grub_free (path_alloc); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), origpath); + grub_free (origpath); + return err; + } + + struct grub_btrfs_dir_item *cdirel; + if (elemsize > allocated) + { + allocated = 2 * elemsize; + grub_free (direl); + direl = grub_malloc (allocated + 1); + if (!direl) + { + grub_free (path_alloc); + grub_free (origpath); + return grub_errno; + } + } + + err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + + for (cdirel = direl; + (grub_uint8_t *) cdirel - (grub_uint8_t *) direl + < (grub_ssize_t) elemsize; + cdirel = (void *) ((grub_uint8_t *) (direl + 1) + + grub_le_to_cpu16 (cdirel->n) + + grub_le_to_cpu16 (cdirel->m))) + { + if (ctokenlen == grub_le_to_cpu16 (cdirel->n) + && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0) + break; + } + if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl + >= (grub_ssize_t) elemsize) + { + grub_free (direl); + grub_free (path_alloc); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), origpath); + grub_free (origpath); + return err; + } + + path = slash; + if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK) + { + struct grub_btrfs_inode inode; + char *tmp; + if (--symlinks_max == 0) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return grub_error (GRUB_ERR_SYMLINK_LOOP, + N_("too deep nesting of symlinks")); + } + + err = grub_btrfs_read_inode (data, &inode, + cdirel->key.object_id, *tree); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + tmp = grub_malloc (grub_le_to_cpu64 (inode.size) + + grub_strlen (path) + 1); + if (!tmp) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return grub_errno; + } + + if (grub_btrfs_extent_read (data, cdirel->key.object_id, + *tree, 0, tmp, + grub_le_to_cpu64 (inode.size)) + != (grub_ssize_t) grub_le_to_cpu64 (inode.size)) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + grub_free (tmp); + return grub_errno; + } + grub_memcpy (tmp + grub_le_to_cpu64 (inode.size), path, + grub_strlen (path) + 1); + grub_free (path_alloc); + path = path_alloc = tmp; + if (path[0] == '/') + { + err = get_root (data, key, tree, type); + if (err) + return err; + } + continue; + } + *type = cdirel->type; + + switch (cdirel->key.type) + { + case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM: + { + struct grub_btrfs_root_item ri; + err = lower_bound (data, &cdirel->key, &key_out, + data->sblock.root_tree, + &elemaddr, &elemsize, NULL, 0); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + if (cdirel->key.object_id != key_out.object_id + || cdirel->key.type != key_out.type) + { + grub_free (direl); + grub_free (path_alloc); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), origpath); + grub_free (origpath); + return err; + } + err = grub_btrfs_read_logical (data, elemaddr, &ri, + sizeof (ri), 0); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } + key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + key->offset = 0; + key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); + *tree = ri.tree; + break; + } + case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM: + if (*slash && *type == GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR) + { + grub_free (direl); + grub_free (path_alloc); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), origpath); + grub_free (origpath); + return err; + } + *key = cdirel->key; + if (*type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; + break; + default: + grub_free (path_alloc); + grub_free (origpath); + grub_free (direl); + return grub_error (GRUB_ERR_BAD_FS, "unrecognised object type 0x%x", + cdirel->key.type); + } + } + + grub_free (direl); + grub_free (origpath); + grub_free (path_alloc); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_btrfs_dir (grub_device_t device, const char *path, + grub_fs_dir_hook_t hook, void *hook_data) +{ + struct grub_btrfs_data *data = grub_btrfs_mount (device); + struct grub_btrfs_key key_in, key_out; + grub_err_t err; + grub_disk_addr_t elemaddr; + grub_size_t elemsize; + grub_size_t allocated = 0; + struct grub_btrfs_dir_item *direl = NULL; + struct grub_btrfs_leaf_descriptor desc; + int r = 0; + grub_uint64_t tree; + grub_uint8_t type; + + if (!data) + return grub_errno; + + err = find_path (data, path, &key_in, &tree, &type); + if (err) + { + grub_btrfs_unmount (data); + return err; + } + if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + { + grub_btrfs_unmount (data); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); + } + + err = lower_bound (data, &key_in, &key_out, tree, + &elemaddr, &elemsize, &desc, 0); + if (err) + { + grub_btrfs_unmount (data); + return err; + } + if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM + || key_out.object_id != key_in.object_id) + { + r = next (data, &desc, &elemaddr, &elemsize, &key_out); + if (r <= 0) + goto out; + } + do + { + struct grub_btrfs_dir_item *cdirel; + if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM + || key_out.object_id != key_in.object_id) + { + r = 0; + break; + } + if (elemsize > allocated) + { + allocated = 2 * elemsize; + grub_free (direl); + direl = grub_malloc (allocated + 1); + if (!direl) + { + r = -grub_errno; + break; + } + } + + err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0); + if (err) + { + r = -err; + break; + } + + for (cdirel = direl; + (grub_uint8_t *) cdirel - (grub_uint8_t *) direl + < (grub_ssize_t) elemsize; + cdirel = (void *) ((grub_uint8_t *) (direl + 1) + + grub_le_to_cpu16 (cdirel->n) + + grub_le_to_cpu16 (cdirel->m))) + { + char c; + struct grub_btrfs_inode inode; + struct grub_dirhook_info info; + err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, + tree); + grub_memset (&info, 0, sizeof (info)); + if (err) + grub_errno = GRUB_ERR_NONE; + else + { + info.mtime = grub_le_to_cpu64 (inode.mtime.sec); + info.mtimeset = 1; + } + c = cdirel->name[grub_le_to_cpu16 (cdirel->n)]; + cdirel->name[grub_le_to_cpu16 (cdirel->n)] = 0; + info.dir = (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY); + if (hook (cdirel->name, &info, hook_data)) + goto out; + cdirel->name[grub_le_to_cpu16 (cdirel->n)] = c; + } + r = next (data, &desc, &elemaddr, &elemsize, &key_out); + } + while (r > 0); + +out: + grub_free (direl); + + free_iterator (&desc); + grub_btrfs_unmount (data); + + return -r; +} + +static grub_err_t +grub_btrfs_open (struct grub_file *file, const char *name) +{ + struct grub_btrfs_data *data = grub_btrfs_mount (file->device); + grub_err_t err; + struct grub_btrfs_inode inode; + grub_uint8_t type; + struct grub_btrfs_key key_in; + + if (!data) + return grub_errno; + + err = find_path (data, name, &key_in, &data->tree, &type); + if (err) + { + grub_btrfs_unmount (data); + return err; + } + if (type != GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR) + { + grub_btrfs_unmount (data); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file")); + } + + data->inode = key_in.object_id; + err = grub_btrfs_read_inode (data, &inode, data->inode, data->tree); + if (err) + { + grub_btrfs_unmount (data); + return err; + } + + file->data = data; + file->size = grub_le_to_cpu64 (inode.size); + + return err; +} + +static grub_err_t +grub_btrfs_close (grub_file_t file) +{ + grub_btrfs_unmount (file->data); + + return GRUB_ERR_NONE; +} + +static grub_ssize_t +grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_btrfs_data *data = file->data; + + return grub_btrfs_extent_read (data, data->inode, + data->tree, file->offset, buf, len); +} + +static grub_err_t +grub_btrfs_uuid (grub_device_t device, char **uuid) +{ + struct grub_btrfs_data *data; + + *uuid = NULL; + + data = grub_btrfs_mount (device); + if (!data) + return grub_errno; + + *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + grub_be_to_cpu16 (data->sblock.uuid[0]), + grub_be_to_cpu16 (data->sblock.uuid[1]), + grub_be_to_cpu16 (data->sblock.uuid[2]), + grub_be_to_cpu16 (data->sblock.uuid[3]), + grub_be_to_cpu16 (data->sblock.uuid[4]), + grub_be_to_cpu16 (data->sblock.uuid[5]), + grub_be_to_cpu16 (data->sblock.uuid[6]), + grub_be_to_cpu16 (data->sblock.uuid[7])); + + grub_btrfs_unmount (data); + + return grub_errno; +} + +static grub_err_t +grub_btrfs_label (grub_device_t device, char **label) +{ + struct grub_btrfs_data *data; + + *label = NULL; + + data = grub_btrfs_mount (device); + if (!data) + return grub_errno; + + *label = grub_strndup (data->sblock.label, sizeof (data->sblock.label)); + + grub_btrfs_unmount (data); + + return grub_errno; +} + +int grub_btrfs_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list) +{ + grub_uint32_t i = 0; + grub_off_t size = 0; + grub_off_t read = 0; + grub_disk_t disk = NULL; + char *buf = NULL; + void *read_hook_data = NULL; + grub_disk_read_hook_t read_hook = NULL; + struct grub_btrfs_data *data = (struct grub_btrfs_data *)file->data; + + if (data->n_devices_attached != 1) + { + chunk_list->err_code = VTOY_CHUNK_ERR_MULTI_DEV; + return 1; + } + + buf = (char *)grub_malloc(VTOY_CHUNK_BUF_SIZE); + if (!buf) + { + return 1; + } + + + //trigger read + grub_file_read(file, buf, 512); + grub_file_seek(file, 0); + + if (g_last_chunk_type != GRUB_BTRFS_CHUNK_TYPE_SINGLE) + { + chunk_list->err_code = VTOY_CHUNK_ERR_RAID; + grub_free(buf); + return 1; + } + else if (g_last_compress_type != GRUB_BTRFS_COMPRESSION_NONE) + { + chunk_list->err_code = VTOY_CHUNK_ERR_COMPRESS; + grub_free(buf); + return 1; + } + + disk = data->devices_attached[0].dev->disk; + read_hook = disk->read_hook; + read_hook_data = disk->read_hook_data; + + disk->read_hook = (grub_disk_read_hook_t)(void *)grub_disk_blocklist_read2; + disk->read_hook_data = chunk_list; + + chunk_list->buf = buf; + chunk_list->last_off = 0; + chunk_list->err_code = 0; + + for (size = file->size; size > 0 && chunk_list->err_code == 0; size -= read) + { + read = (size > VTOY_CHUNK_BUF_SIZE) ? VTOY_CHUNK_BUF_SIZE : size; + grub_file_read(file, buf, read); + } + + disk->read_hook = read_hook; + disk->read_hook_data = read_hook_data; + + chunk_list->buf = NULL; + chunk_list->last_off = 0; + + grub_free(buf); + + for (i = 0; i < chunk_list->cur_chunk; i++) + { + chunk_list->chunk[i].disk_start_sector += part_start; + chunk_list->chunk[i].disk_end_sector += part_start; + } + + return 0; +} + + + +#ifdef GRUB_UTIL +static grub_err_t +grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + unsigned int *nsectors, + unsigned int max_nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors) +{ + unsigned i; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "BtrFS currently supports only PC-BIOS embedding"); + + if (64 * 2 - 1 < *nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("your core.img is unusually large. " + "It won't fit in the embedding area")); + + *nsectors = 64 * 2 - 1; + if (*nsectors > max_nsectors) + *nsectors = max_nsectors; + *sectors = grub_malloc (*nsectors * sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = i + 1; + + return GRUB_ERR_NONE; +} +#endif + +static struct grub_fs grub_btrfs_fs = { + .name = "btrfs", + .fs_dir = grub_btrfs_dir, + .fs_open = grub_btrfs_open, + .fs_read = grub_btrfs_read, + .fs_close = grub_btrfs_close, + .fs_uuid = grub_btrfs_uuid, + .fs_label = grub_btrfs_label, +#ifdef GRUB_UTIL + .fs_embed = grub_btrfs_embed, + .reserved_first_sector = 1, + .blocklist_install = 0, +#endif +}; + +GRUB_MOD_INIT (btrfs) +{ + grub_fs_register (&grub_btrfs_fs); +} + +GRUB_MOD_FINI (btrfs) +{ + grub_fs_unregister (&grub_btrfs_fs); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ext2.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ext2.c new file mode 100644 index 0000000..d7cfe2c --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ext2.c @@ -0,0 +1,1149 @@ +/* ext2.c - Second Extended filesystem */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +/* Magic value used to identify an ext2 filesystem. */ +#define EXT2_MAGIC 0xEF53 +/* Amount of indirect blocks in an inode. */ +#define INDIRECT_BLOCKS 12 + +/* The good old revision and the default inode size. */ +#define EXT2_GOOD_OLD_REVISION 0 +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +/* Filetype used in directory entry. */ +#define FILETYPE_UNKNOWN 0 +#define FILETYPE_REG 1 +#define FILETYPE_DIRECTORY 2 +#define FILETYPE_SYMLINK 7 + +/* Filetype information as used in inodes. */ +#define FILETYPE_INO_MASK 0170000 +#define FILETYPE_INO_REG 0100000 +#define FILETYPE_INO_DIRECTORY 0040000 +#define FILETYPE_INO_SYMLINK 0120000 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* Log2 size of ext2 block in 512 blocks. */ +#define LOG2_EXT2_BLOCK_SIZE(data) \ + (grub_le_to_cpu32 (data->sblock.log2_block_size) + 1) + +/* Log2 size of ext2 block in bytes. */ +#define LOG2_BLOCK_SIZE(data) \ + (grub_le_to_cpu32 (data->sblock.log2_block_size) + 10) + +/* The size of an ext2 block in bytes. */ +#define EXT2_BLOCK_SIZE(data) (1U << LOG2_BLOCK_SIZE (data)) + +/* The revision level. */ +#define EXT2_REVISION(data) grub_le_to_cpu32 (data->sblock.revision_level) + +/* The inode size. */ +#define EXT2_INODE_SIZE(data) \ + (data->sblock.revision_level \ + == grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION) \ + ? EXT2_GOOD_OLD_INODE_SIZE \ + : grub_le_to_cpu16 (data->sblock.inode_size)) + +/* Superblock filesystem feature flags (RW compatible) + * A filesystem with any of these enabled can be read and written by a driver + * that does not understand them without causing metadata/data corruption. */ +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010 +#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 +/* Superblock filesystem feature flags (RO compatible) + * A filesystem with any of these enabled can be safely read by a driver that + * does not understand them, but should not be written to, usually because + * additional metadata is required. */ +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 +#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 +/* Superblock filesystem feature flags (back-incompatible) + * A filesystem with any of these enabled should not be attempted to be read + * by a driver that does not understand them, since they usually indicate + * metadata format changes that might confuse the reader. */ +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Volume is journal device */ +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* Extents used */ +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 +#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 +#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000 +#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 + +/* The set of back-incompatible features this driver DOES support. Add (OR) + * flags here as the related features are implemented into the driver. */ +#define EXT2_DRIVER_SUPPORTED_INCOMPAT ( EXT2_FEATURE_INCOMPAT_FILETYPE \ + | EXT4_FEATURE_INCOMPAT_EXTENTS \ + | EXT4_FEATURE_INCOMPAT_FLEX_BG \ + | EXT2_FEATURE_INCOMPAT_META_BG \ + | EXT4_FEATURE_INCOMPAT_64BIT \ + | EXT4_FEATURE_INCOMPAT_ENCRYPT) +/* List of rationales for the ignored "incompatible" features: + * needs_recovery: Not really back-incompatible - was added as such to forbid + * ext2 drivers from mounting an ext3 volume with a dirty + * journal because they will ignore the journal, but the next + * ext3 driver to mount the volume will find the journal and + * replay it, potentially corrupting the metadata written by + * the ext2 drivers. Safe to ignore for this RO driver. + * mmp: Not really back-incompatible - was added as such to + * avoid multiple read-write mounts. Safe to ignore for this + * RO driver. + * checksum seed: Not really back-incompatible - was added to allow tools + * such as tune2fs to change the UUID on a mounted metadata + * checksummed filesystem. Safe to ignore for now since the + * driver doesn't support checksum verification. But it must + * be removed from this list if that support is added later. + * + */ +#define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \ + | EXT4_FEATURE_INCOMPAT_MMP \ + | EXT4_FEATURE_INCOMPAT_CSUM_SEED) + + +#define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U + +#define EXT3_JOURNAL_DESCRIPTOR_BLOCK 1 +#define EXT3_JOURNAL_COMMIT_BLOCK 2 +#define EXT3_JOURNAL_SUPERBLOCK_V1 3 +#define EXT3_JOURNAL_SUPERBLOCK_V2 4 +#define EXT3_JOURNAL_REVOKE_BLOCK 5 + +#define EXT3_JOURNAL_FLAG_ESCAPE 1 +#define EXT3_JOURNAL_FLAG_SAME_UUID 2 +#define EXT3_JOURNAL_FLAG_DELETED 4 +#define EXT3_JOURNAL_FLAG_LAST_TAG 8 + +#define EXT4_ENCRYPT_FLAG 0x800 +#define EXT4_EXTENTS_FLAG 0x80000 + +/* The ext2 superblock. */ +struct grub_ext2_sblock +{ + grub_uint32_t total_inodes; + grub_uint32_t total_blocks; + grub_uint32_t reserved_blocks; + grub_uint32_t free_blocks; + grub_uint32_t free_inodes; + grub_uint32_t first_data_block; + grub_uint32_t log2_block_size; + grub_uint32_t log2_fragment_size; + grub_uint32_t blocks_per_group; + grub_uint32_t fragments_per_group; + grub_uint32_t inodes_per_group; + grub_uint32_t mtime; + grub_uint32_t utime; + grub_uint16_t mnt_count; + grub_uint16_t max_mnt_count; + grub_uint16_t magic; + grub_uint16_t fs_state; + grub_uint16_t error_handling; + grub_uint16_t minor_revision_level; + grub_uint32_t lastcheck; + grub_uint32_t checkinterval; + grub_uint32_t creator_os; + grub_uint32_t revision_level; + grub_uint16_t uid_reserved; + grub_uint16_t gid_reserved; + grub_uint32_t first_inode; + grub_uint16_t inode_size; + grub_uint16_t block_group_number; + grub_uint32_t feature_compatibility; + grub_uint32_t feature_incompat; + grub_uint32_t feature_ro_compat; + grub_uint16_t uuid[8]; + char volume_name[16]; + char last_mounted_on[64]; + grub_uint32_t compression_info; + grub_uint8_t prealloc_blocks; + grub_uint8_t prealloc_dir_blocks; + grub_uint16_t reserved_gdt_blocks; + grub_uint8_t journal_uuid[16]; + grub_uint32_t journal_inum; + grub_uint32_t journal_dev; + grub_uint32_t last_orphan; + grub_uint32_t hash_seed[4]; + grub_uint8_t def_hash_version; + grub_uint8_t jnl_backup_type; + grub_uint16_t group_desc_size; + grub_uint32_t default_mount_opts; + grub_uint32_t first_meta_bg; + grub_uint32_t mkfs_time; + grub_uint32_t jnl_blocks[17]; +}; + +/* The ext2 blockgroup. */ +struct grub_ext2_block_group +{ + grub_uint32_t block_id; + grub_uint32_t inode_id; + grub_uint32_t inode_table_id; + grub_uint16_t free_blocks; + grub_uint16_t free_inodes; + grub_uint16_t used_dirs; + grub_uint16_t pad; + grub_uint32_t reserved[3]; + grub_uint32_t block_id_hi; + grub_uint32_t inode_id_hi; + grub_uint32_t inode_table_id_hi; + grub_uint16_t free_blocks_hi; + grub_uint16_t free_inodes_hi; + grub_uint16_t used_dirs_hi; + grub_uint16_t pad2; + grub_uint32_t reserved2[3]; +}; + +/* The ext2 inode. */ +struct grub_ext2_inode +{ + grub_uint16_t mode; + grub_uint16_t uid; + grub_uint32_t size; + grub_uint32_t atime; + grub_uint32_t ctime; + grub_uint32_t mtime; + grub_uint32_t dtime; + grub_uint16_t gid; + grub_uint16_t nlinks; + grub_uint32_t blockcnt; /* Blocks of 512 bytes!! */ + grub_uint32_t flags; + grub_uint32_t osd1; + union + { + struct datablocks + { + grub_uint32_t dir_blocks[INDIRECT_BLOCKS]; + grub_uint32_t indir_block; + grub_uint32_t double_indir_block; + grub_uint32_t triple_indir_block; + } blocks; + char symlink[60]; + }; + grub_uint32_t version; + grub_uint32_t acl; + grub_uint32_t size_high; + grub_uint32_t fragment_addr; + grub_uint32_t osd2[3]; +}; + +/* The header of an ext2 directory entry. */ +struct ext2_dirent +{ + grub_uint32_t inode; + grub_uint16_t direntlen; +#define MAX_NAMELEN 255 + grub_uint8_t namelen; + grub_uint8_t filetype; +}; + +struct grub_ext3_journal_header +{ + grub_uint32_t magic; + grub_uint32_t block_type; + grub_uint32_t sequence; +}; + +struct grub_ext3_journal_revoke_header +{ + struct grub_ext3_journal_header header; + grub_uint32_t count; + grub_uint32_t data[0]; +}; + +struct grub_ext3_journal_block_tag +{ + grub_uint32_t block; + grub_uint32_t flags; +}; + +struct grub_ext3_journal_sblock +{ + struct grub_ext3_journal_header header; + grub_uint32_t block_size; + grub_uint32_t maxlen; + grub_uint32_t first; + grub_uint32_t sequence; + grub_uint32_t start; +}; + +#define EXT4_EXT_MAGIC 0xf30a + +struct grub_ext4_extent_header +{ + grub_uint16_t magic; + grub_uint16_t entries; + grub_uint16_t max; + grub_uint16_t depth; + grub_uint32_t generation; +}; + +struct grub_ext4_extent +{ + grub_uint32_t block; + grub_uint16_t len; + grub_uint16_t start_hi; + grub_uint32_t start; +}; + +struct grub_ext4_extent_idx +{ + grub_uint32_t block; + grub_uint32_t leaf; + grub_uint16_t leaf_hi; + grub_uint16_t unused; +}; + +struct grub_fshelp_node +{ + struct grub_ext2_data *data; + struct grub_ext2_inode inode; + int ino; + int inode_read; +}; + +/* Information about a "mounted" ext2 filesystem. */ +struct grub_ext2_data +{ + struct grub_ext2_sblock sblock; + int log_group_desc_size; + grub_disk_t disk; + struct grub_ext2_inode *inode; + struct grub_fshelp_node diropen; +}; + +static grub_dl_t my_mod; + +static int g_ventoy_block_count; + +/* Check is a = b^x for some x. */ +static inline int +is_power_of (grub_uint64_t a, grub_uint32_t b) +{ + grub_uint64_t c; + /* Prevent overflow assuming b < 8. */ + if (a >= (1LL << 60)) + return 0; + for (c = 1; c <= a; c *= b); + return (c == a); +} + + +static inline int +group_has_super_block (struct grub_ext2_data *data, grub_uint64_t group) +{ + if (!(data->sblock.feature_ro_compat + & grub_cpu_to_le32_compile_time(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))) + return 1; + /* Algorithm looked up in Linux source. */ + if (group <= 1) + return 1; + /* Even number is never a power of odd number. */ + if (!(group & 1)) + return 0; + return (is_power_of(group, 7) || is_power_of(group, 5) || + is_power_of(group, 3)); +} + +/* Read into BLKGRP the blockgroup descriptor of blockgroup GROUP of + the mounted filesystem DATA. */ +inline static grub_err_t +grub_ext2_blockgroup (struct grub_ext2_data *data, grub_uint64_t group, + struct grub_ext2_block_group *blkgrp) +{ + grub_uint64_t full_offset = (group << data->log_group_desc_size); + grub_uint64_t block, offset; + block = (full_offset >> LOG2_BLOCK_SIZE (data)); + offset = (full_offset & ((1 << LOG2_BLOCK_SIZE (data)) - 1)); + if ((data->sblock.feature_incompat + & grub_cpu_to_le32_compile_time (EXT2_FEATURE_INCOMPAT_META_BG)) + && block >= grub_le_to_cpu32(data->sblock.first_meta_bg)) + { + grub_uint64_t first_block_group; + /* Find the first block group for which a descriptor + is stored in given block. */ + first_block_group = (block << (LOG2_BLOCK_SIZE (data) + - data->log_group_desc_size)); + + block = (first_block_group + * grub_le_to_cpu32(data->sblock.blocks_per_group)); + + if (group_has_super_block (data, first_block_group)) + block++; + } + else + /* Superblock. */ + block++; + return grub_disk_read (data->disk, + ((grub_le_to_cpu32 (data->sblock.first_data_block) + + block) + << LOG2_EXT2_BLOCK_SIZE (data)), offset, + sizeof (struct grub_ext2_block_group), blkgrp); +} + +static struct grub_ext4_extent_header * +grub_ext4_find_leaf (struct grub_ext2_data *data, + struct grub_ext4_extent_header *ext_block, + grub_uint32_t fileblock) +{ + struct grub_ext4_extent_idx *index; + void *buf = NULL; + + while (1) + { + int i; + grub_disk_addr_t block; + + index = (struct grub_ext4_extent_idx *) (ext_block + 1); + + if (ext_block->magic != grub_cpu_to_le16_compile_time (EXT4_EXT_MAGIC)) + goto fail; + + if (ext_block->depth == 0) + return ext_block; + + for (i = 0; i < grub_le_to_cpu16 (ext_block->entries); i++) + { + if (fileblock < grub_le_to_cpu32(index[i].block)) + break; + } + + if (--i < 0) + goto fail; + + block = grub_le_to_cpu16 (index[i].leaf_hi); + block = (block << 32) | grub_le_to_cpu32 (index[i].leaf); + if (!buf) + buf = grub_malloc (EXT2_BLOCK_SIZE(data)); + if (!buf) + goto fail; + if (grub_disk_read (data->disk, + block << LOG2_EXT2_BLOCK_SIZE (data), + 0, EXT2_BLOCK_SIZE(data), buf)) + goto fail; + + ext_block = buf; + } + fail: + grub_free (buf); + return 0; +} + +static grub_disk_addr_t +grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) +{ + struct grub_ext2_data *data = node->data; + struct grub_ext2_inode *inode = &node->inode; + unsigned int blksz = EXT2_BLOCK_SIZE (data); + grub_disk_addr_t blksz_quarter = blksz / 4; + int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data); + int log_perblock = log2_blksz + 9 - 2; + grub_uint32_t indir; + int shift; + + if (inode->flags & grub_cpu_to_le32_compile_time (EXT4_EXTENTS_FLAG)) + { + struct grub_ext4_extent_header *leaf; + struct grub_ext4_extent *ext; + int i; + grub_disk_addr_t ret; + + leaf = grub_ext4_find_leaf (data, (struct grub_ext4_extent_header *) inode->blocks.dir_blocks, fileblock); + if (! leaf) + { + grub_error (GRUB_ERR_BAD_FS, "invalid extent"); + return -1; + } + + ext = (struct grub_ext4_extent *) (leaf + 1); + for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++) + { + if (fileblock < grub_le_to_cpu32 (ext[i].block)) + break; + } + + if (--i >= 0) + { + fileblock -= grub_le_to_cpu32 (ext[i].block); + if (fileblock >= grub_le_to_cpu16 (ext[i].len)) + ret = 0; + else + { + grub_disk_addr_t start; + + start = grub_le_to_cpu16 (ext[i].start_hi); + start = (start << 32) + grub_le_to_cpu32 (ext[i].start); + + g_ventoy_block_count = (int)(grub_le_to_cpu16 (ext[i].len) - fileblock); + ret = fileblock + start; + } + } + else + { + grub_error (GRUB_ERR_BAD_FS, "something wrong with extent"); + ret = -1; + } + + if (leaf != (struct grub_ext4_extent_header *) inode->blocks.dir_blocks) + grub_free (leaf); + + return ret; + } + + /* Direct blocks. */ + if (fileblock < INDIRECT_BLOCKS) + return grub_le_to_cpu32 (inode->blocks.dir_blocks[fileblock]); + fileblock -= INDIRECT_BLOCKS; + /* Indirect. */ + if (fileblock < blksz_quarter) + { + indir = inode->blocks.indir_block; + shift = 0; + goto indirect; + } + fileblock -= blksz_quarter; + /* Double indirect. */ + if (fileblock < blksz_quarter * blksz_quarter) + { + indir = inode->blocks.double_indir_block; + shift = 1; + goto indirect; + } + fileblock -= blksz_quarter * blksz_quarter; + /* Triple indirect. */ + if (fileblock < blksz_quarter * blksz_quarter * (blksz_quarter + 1)) + { + indir = inode->blocks.triple_indir_block; + shift = 2; + goto indirect; + } + grub_error (GRUB_ERR_BAD_FS, + "ext2fs doesn't support quadruple indirect blocks"); + return -1; + +indirect: + do { + /* If the indirect block is zero, all child blocks are absent + (i.e. filled with zeros.) */ + if (indir == 0) + return 0; + if (grub_disk_read (data->disk, + ((grub_disk_addr_t) grub_le_to_cpu32 (indir)) + << log2_blksz, + ((fileblock >> (log_perblock * shift)) + & ((1 << log_perblock) - 1)) + * sizeof (indir), + sizeof (indir), &indir)) + return -1; + } while (shift--); + + return grub_le_to_cpu32 (indir); +} + +/* Read LEN bytes from the file described by DATA starting with byte + POS. Return the amount of read bytes in READ. */ +static grub_ssize_t +grub_ext2_read_file (grub_fshelp_node_t node, + grub_disk_read_hook_t read_hook, void *read_hook_data, + grub_off_t pos, grub_size_t len, char *buf) +{ + return grub_fshelp_read_file (node->data->disk, node, + read_hook, read_hook_data, + pos, len, buf, grub_ext2_read_block, + grub_cpu_to_le32 (node->inode.size) + | (((grub_off_t) grub_cpu_to_le32 (node->inode.size_high)) << 32), + LOG2_EXT2_BLOCK_SIZE (node->data), 0); + +} + + +/* Read the inode INO for the file described by DATA into INODE. */ +static grub_err_t +grub_ext2_read_inode (struct grub_ext2_data *data, + int ino, struct grub_ext2_inode *inode) +{ + struct grub_ext2_block_group blkgrp; + struct grub_ext2_sblock *sblock = &data->sblock; + int inodes_per_block; + unsigned int blkno; + unsigned int blkoff; + grub_disk_addr_t base; + + /* It is easier to calculate if the first inode is 0. */ + ino--; + + grub_ext2_blockgroup (data, + ino / grub_le_to_cpu32 (sblock->inodes_per_group), + &blkgrp); + if (grub_errno) + return grub_errno; + + inodes_per_block = EXT2_BLOCK_SIZE (data) / EXT2_INODE_SIZE (data); + blkno = (ino % grub_le_to_cpu32 (sblock->inodes_per_group)) + / inodes_per_block; + blkoff = (ino % grub_le_to_cpu32 (sblock->inodes_per_group)) + % inodes_per_block; + + base = grub_le_to_cpu32 (blkgrp.inode_table_id); + if (data->log_group_desc_size >= 6) + base |= (((grub_disk_addr_t) grub_le_to_cpu32 (blkgrp.inode_table_id_hi)) + << 32); + + /* Read the inode. */ + if (grub_disk_read (data->disk, + ((base + blkno) << LOG2_EXT2_BLOCK_SIZE (data)), + EXT2_INODE_SIZE (data) * blkoff, + sizeof (struct grub_ext2_inode), inode)) + return grub_errno; + + return 0; +} + +static struct grub_ext2_data * +grub_ext2_mount (grub_disk_t disk) +{ + struct grub_ext2_data *data; + + data = grub_malloc (sizeof (struct grub_ext2_data)); + if (!data) + return 0; + + /* Read the superblock. */ + grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_ext2_sblock), + &data->sblock); + if (grub_errno) + goto fail; + + /* Make sure this is an ext2 filesystem. */ + if (data->sblock.magic != grub_cpu_to_le16_compile_time (EXT2_MAGIC) + || grub_le_to_cpu32 (data->sblock.log2_block_size) >= 16 + || data->sblock.inodes_per_group == 0 + /* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */ + || grub_le_to_cpu32 (data->sblock.log2_block_size) > 20 + || EXT2_INODE_SIZE (data) == 0 + || EXT2_BLOCK_SIZE (data) / EXT2_INODE_SIZE (data) == 0) + { + grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem"); + goto fail; + } + + /* Check the FS doesn't have feature bits enabled that we don't support. */ + if (data->sblock.revision_level != grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION) + && (data->sblock.feature_incompat + & grub_cpu_to_le32_compile_time (~(EXT2_DRIVER_SUPPORTED_INCOMPAT + | EXT2_DRIVER_IGNORED_INCOMPAT)))) + { + grub_error (GRUB_ERR_BAD_FS, "filesystem has unsupported incompatible features"); + goto fail; + } + + if (data->sblock.revision_level != grub_cpu_to_le32_compile_time (EXT2_GOOD_OLD_REVISION) + && (data->sblock.feature_incompat + & grub_cpu_to_le32_compile_time (EXT4_FEATURE_INCOMPAT_64BIT)) + && data->sblock.group_desc_size != 0 + && ((data->sblock.group_desc_size & (data->sblock.group_desc_size - 1)) + == 0) + && (data->sblock.group_desc_size & grub_cpu_to_le16_compile_time (0x1fe0))) + { + grub_uint16_t b = grub_le_to_cpu16 (data->sblock.group_desc_size); + for (data->log_group_desc_size = 0; b != (1 << data->log_group_desc_size); + data->log_group_desc_size++); + } + else + data->log_group_desc_size = 5; + + data->disk = disk; + + data->diropen.data = data; + data->diropen.ino = 2; + data->diropen.inode_read = 1; + + data->inode = &data->diropen.inode; + + grub_ext2_read_inode (data, 2, data->inode); + if (grub_errno) + goto fail; + + return data; + + fail: + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_error (GRUB_ERR_BAD_FS, "not an ext2 filesystem"); + + grub_free (data); + return 0; +} + +static char * +grub_ext2_read_symlink (grub_fshelp_node_t node) +{ + char *symlink; + struct grub_fshelp_node *diro = node; + + if (! diro->inode_read) + { + grub_ext2_read_inode (diro->data, diro->ino, &diro->inode); + if (grub_errno) + return 0; + + if (diro->inode.flags & grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG)) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "symlink is encrypted"); + return 0; + } + } + + symlink = grub_malloc (grub_le_to_cpu32 (diro->inode.size) + 1); + if (! symlink) + return 0; + + /* + * If the filesize of the symlink is equal to or bigger than 60 the symlink + * is stored in a separate block, otherwise it is stored in the inode. + */ + if (grub_le_to_cpu32 (diro->inode.size) < sizeof (diro->inode.symlink)) + grub_memcpy (symlink, + diro->inode.symlink, + grub_le_to_cpu32 (diro->inode.size)); + else + { + grub_ext2_read_file (diro, 0, 0, 0, + grub_le_to_cpu32 (diro->inode.size), + symlink); + if (grub_errno) + { + grub_free (symlink); + return 0; + } + } + + symlink[grub_le_to_cpu32 (diro->inode.size)] = '\0'; + return symlink; +} + +static int +grub_ext2_iterate_dir (grub_fshelp_node_t dir, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) +{ + unsigned int fpos = 0; + struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir; + + if (! diro->inode_read) + { + grub_ext2_read_inode (diro->data, diro->ino, &diro->inode); + if (grub_errno) + return 0; + } + + if (diro->inode.flags & grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG)) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "directory is encrypted"); + return 0; + } + + /* Search the file. */ + while (fpos < grub_le_to_cpu32 (diro->inode.size)) + { + struct ext2_dirent dirent; + + grub_ext2_read_file (diro, 0, 0, fpos, sizeof (struct ext2_dirent), + (char *) &dirent); + if (grub_errno) + return 0; + + if (dirent.direntlen == 0) + return 0; + + if (dirent.inode != 0 && dirent.namelen != 0) + { + char filename[MAX_NAMELEN + 1]; + struct grub_fshelp_node *fdiro; + enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN; + + grub_ext2_read_file (diro, 0, 0, fpos + sizeof (struct ext2_dirent), + dirent.namelen, filename); + if (grub_errno) + return 0; + + fdiro = grub_malloc (sizeof (struct grub_fshelp_node)); + if (! fdiro) + return 0; + + fdiro->data = diro->data; + fdiro->ino = grub_le_to_cpu32 (dirent.inode); + + filename[dirent.namelen] = '\0'; + + if (dirent.filetype != FILETYPE_UNKNOWN) + { + fdiro->inode_read = 0; + + if (dirent.filetype == FILETYPE_DIRECTORY) + type = GRUB_FSHELP_DIR; + else if (dirent.filetype == FILETYPE_SYMLINK) + type = GRUB_FSHELP_SYMLINK; + else if (dirent.filetype == FILETYPE_REG) + type = GRUB_FSHELP_REG; + } + else + { + /* The filetype can not be read from the dirent, read + the inode to get more information. */ + grub_ext2_read_inode (diro->data, + grub_le_to_cpu32 (dirent.inode), + &fdiro->inode); + if (grub_errno) + { + grub_free (fdiro); + return 0; + } + + fdiro->inode_read = 1; + + if ((grub_le_to_cpu16 (fdiro->inode.mode) + & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY) + type = GRUB_FSHELP_DIR; + else if ((grub_le_to_cpu16 (fdiro->inode.mode) + & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK) + type = GRUB_FSHELP_SYMLINK; + else if ((grub_le_to_cpu16 (fdiro->inode.mode) + & FILETYPE_INO_MASK) == FILETYPE_INO_REG) + type = GRUB_FSHELP_REG; + } + + if (hook (filename, type, fdiro, hook_data)) + return 1; + } + + fpos += grub_le_to_cpu16 (dirent.direntlen); + } + + return 0; +} + +/* Open a file named NAME and initialize FILE. */ +static grub_err_t +grub_ext2_open (struct grub_file *file, const char *name) +{ + struct grub_ext2_data *data; + struct grub_fshelp_node *fdiro = 0; + grub_err_t err; + + grub_dl_ref (my_mod); + + data = grub_ext2_mount (file->device->disk); + if (! data) + { + err = grub_errno; + goto fail; + } + + err = grub_fshelp_find_file (name, &data->diropen, &fdiro, + grub_ext2_iterate_dir, + grub_ext2_read_symlink, GRUB_FSHELP_REG); + if (err) + goto fail; + + if (! fdiro->inode_read) + { + err = grub_ext2_read_inode (data, fdiro->ino, &fdiro->inode); + if (err) + goto fail; + } + + if (fdiro->inode.flags & grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG)) + { + err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "file is encrypted"); + goto fail; + } + + grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_ext2_inode)); + grub_free (fdiro); + + file->size = grub_le_to_cpu32 (data->inode->size); + file->size |= ((grub_off_t) grub_le_to_cpu32 (data->inode->size_high)) << 32; + file->data = data; + file->offset = 0; + + return 0; + + fail: + if (fdiro != &data->diropen) + grub_free (fdiro); + grub_free (data); + + grub_dl_unref (my_mod); + + return err; +} + +static grub_err_t +grub_ext2_close (grub_file_t file) +{ + grub_free (file->data); + + grub_dl_unref (my_mod); + + return GRUB_ERR_NONE; +} + +/* Read LEN bytes data from FILE into BUF. */ +static grub_ssize_t +grub_ext2_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_ext2_data *data = (struct grub_ext2_data *) file->data; + + return grub_ext2_read_file (&data->diropen, + file->read_hook, file->read_hook_data, + file->offset, len, buf); +} + + +/* Context for grub_ext2_dir. */ +struct grub_ext2_dir_ctx +{ + grub_fs_dir_hook_t hook; + void *hook_data; + struct grub_ext2_data *data; +}; + +/* Helper for grub_ext2_dir. */ +static int +grub_ext2_dir_iter (const char *filename, enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node, void *data) +{ + struct grub_ext2_dir_ctx *ctx = data; + struct grub_dirhook_info info; + + grub_memset (&info, 0, sizeof (info)); + if (! node->inode_read) + { + grub_ext2_read_inode (ctx->data, node->ino, &node->inode); + if (!grub_errno) + node->inode_read = 1; + grub_errno = GRUB_ERR_NONE; + } + if (node->inode_read) + { + info.mtimeset = 1; + info.mtime = grub_le_to_cpu32 (node->inode.mtime); + } + + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + if (!info.dir) + info.size = (((grub_off_t) grub_le_to_cpu32 (node->inode.size_high)) << 32) | grub_le_to_cpu32 (node->inode.size); + grub_free (node); + return ctx->hook (filename, &info, ctx->hook_data); +} + +static grub_err_t +grub_ext2_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook, + void *hook_data) +{ + struct grub_ext2_dir_ctx ctx = { + .hook = hook, + .hook_data = hook_data + }; + struct grub_fshelp_node *fdiro = 0; + + grub_dl_ref (my_mod); + + ctx.data = grub_ext2_mount (device->disk); + if (! ctx.data) + goto fail; + + grub_fshelp_find_file (path, &ctx.data->diropen, &fdiro, + grub_ext2_iterate_dir, grub_ext2_read_symlink, + GRUB_FSHELP_DIR); + if (grub_errno) + goto fail; + + grub_ext2_iterate_dir (fdiro, grub_ext2_dir_iter, &ctx); + + fail: + if (fdiro != &ctx.data->diropen) + grub_free (fdiro); + grub_free (ctx.data); + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_err_t +grub_ext2_label (grub_device_t device, char **label) +{ + struct grub_ext2_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_ext2_mount (disk); + if (data) + *label = grub_strndup (data->sblock.volume_name, + sizeof (data->sblock.volume_name)); + else + *label = NULL; + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + +static grub_err_t +grub_ext2_uuid (grub_device_t device, char **uuid) +{ + struct grub_ext2_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_ext2_mount (disk); + if (data) + { + *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + grub_be_to_cpu16 (data->sblock.uuid[0]), + grub_be_to_cpu16 (data->sblock.uuid[1]), + grub_be_to_cpu16 (data->sblock.uuid[2]), + grub_be_to_cpu16 (data->sblock.uuid[3]), + grub_be_to_cpu16 (data->sblock.uuid[4]), + grub_be_to_cpu16 (data->sblock.uuid[5]), + grub_be_to_cpu16 (data->sblock.uuid[6]), + grub_be_to_cpu16 (data->sblock.uuid[7])); + } + else + *uuid = NULL; + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + +/* Get mtime. */ +static grub_err_t +grub_ext2_mtime (grub_device_t device, grub_int32_t *tm) +{ + struct grub_ext2_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_ext2_mount (disk); + if (!data) + *tm = 0; + else + *tm = grub_le_to_cpu32 (data->sblock.utime); + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; + +} + +int grub_ext_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list) +{ + int blocksize; + int log2blocksize; + grub_disk_t disk; + grub_disk_addr_t i = 0; + grub_disk_addr_t blockcnt; + grub_disk_addr_t blknr; + grub_fshelp_node_t node = NULL; + + disk = file->device->disk; + node = &(((struct grub_ext2_data *)file->data)->diropen); + + log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data); + blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS); + blockcnt = (file->size + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS); + + while (i < blockcnt) + { + g_ventoy_block_count = 1; + blknr = grub_ext2_read_block(node, i); + if (blknr == 0) + { + return 0; + } + + i += g_ventoy_block_count; + blknr = blknr << log2blocksize; + grub_disk_blocklist_read(chunk_list, blknr, g_ventoy_block_count * blocksize, disk->log_sector_size); + } + + for (i = 0; i < chunk_list->cur_chunk; i++) + { + chunk_list->chunk[i].disk_start_sector += part_start; + chunk_list->chunk[i].disk_end_sector += part_start; + } + + return 0; +} + +static struct grub_fs grub_ext2_fs = + { + .name = "ext2", + .fs_dir = grub_ext2_dir, + .fs_open = grub_ext2_open, + .fs_read = grub_ext2_read, + .fs_close = grub_ext2_close, + .fs_label = grub_ext2_label, + .fs_uuid = grub_ext2_uuid, + .fs_mtime = grub_ext2_mtime, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif + .next = 0 + }; + +GRUB_MOD_INIT(ext2) +{ + grub_fs_register (&grub_ext2_fs); + my_mod = mod; +} + +GRUB_MOD_FINI(ext2) +{ + grub_fs_unregister (&grub_ext2_fs); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fat.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fat.c new file mode 100644 index 0000000..eb317a9 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fat.c @@ -0,0 +1,1403 @@ +/* fat.c - FAT filesystem */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef MODE_EXFAT +#include +#else +#include +#endif +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +enum + { + GRUB_FAT_ATTR_READ_ONLY = 0x01, + GRUB_FAT_ATTR_HIDDEN = 0x02, + GRUB_FAT_ATTR_SYSTEM = 0x04, +#ifndef MODE_EXFAT + GRUB_FAT_ATTR_VOLUME_ID = 0x08, +#endif + GRUB_FAT_ATTR_DIRECTORY = 0x10, + GRUB_FAT_ATTR_ARCHIVE = 0x20, + +#ifndef MODE_EXFAT + GRUB_FAT_ATTR_LONG_NAME = (GRUB_FAT_ATTR_READ_ONLY + | GRUB_FAT_ATTR_HIDDEN + | GRUB_FAT_ATTR_SYSTEM + | GRUB_FAT_ATTR_VOLUME_ID), +#endif + GRUB_FAT_ATTR_VALID = (GRUB_FAT_ATTR_READ_ONLY + | GRUB_FAT_ATTR_HIDDEN + | GRUB_FAT_ATTR_SYSTEM + | GRUB_FAT_ATTR_DIRECTORY + | GRUB_FAT_ATTR_ARCHIVE +#ifndef MODE_EXFAT + | GRUB_FAT_ATTR_VOLUME_ID +#endif + ) + }; + +#ifdef MODE_EXFAT +typedef struct grub_exfat_bpb grub_current_fat_bpb_t; +#else +typedef struct grub_fat_bpb grub_current_fat_bpb_t; +#endif + +#ifdef MODE_EXFAT +enum + { + FLAG_CONTIGUOUS = 2 + }; +struct grub_fat_dir_entry +{ + grub_uint8_t entry_type; + union + { + grub_uint8_t placeholder[31]; + struct { + grub_uint8_t secondary_count; + grub_uint16_t checksum; + grub_uint16_t attr; + grub_uint16_t reserved1; + grub_uint32_t c_time; + grub_uint32_t m_time; + grub_uint32_t a_time; + grub_uint8_t c_time_tenth; + grub_uint8_t m_time_tenth; + grub_uint8_t a_time_tenth; + grub_uint8_t reserved2[9]; + } GRUB_PACKED file; + struct { + grub_uint8_t flags; + grub_uint8_t reserved1; + grub_uint8_t name_length; + grub_uint16_t name_hash; + grub_uint16_t reserved2; + grub_uint64_t valid_size; + grub_uint32_t reserved3; + grub_uint32_t first_cluster; + grub_uint64_t file_size; + } GRUB_PACKED stream_extension; + struct { + grub_uint8_t flags; + grub_uint16_t str[15]; + } GRUB_PACKED file_name; + struct { + grub_uint8_t character_count; + grub_uint16_t str[15]; + } GRUB_PACKED volume_label; + } GRUB_PACKED type_specific; +} GRUB_PACKED; + +struct grub_fat_dir_node +{ + grub_uint32_t attr; + grub_uint32_t first_cluster; + grub_uint64_t file_size; + grub_uint64_t valid_size; + int have_stream; + int is_contiguous; +}; + +typedef struct grub_fat_dir_node grub_fat_dir_node_t; + +#else +struct grub_fat_dir_entry +{ + grub_uint8_t name[11]; + grub_uint8_t attr; + grub_uint8_t nt_reserved; + grub_uint8_t c_time_tenth; + grub_uint16_t c_time; + grub_uint16_t c_date; + grub_uint16_t a_date; + grub_uint16_t first_cluster_high; + grub_uint16_t w_time; + grub_uint16_t w_date; + grub_uint16_t first_cluster_low; + grub_uint32_t file_size; +} GRUB_PACKED; + +struct grub_fat_long_name_entry +{ + grub_uint8_t id; + grub_uint16_t name1[5]; + grub_uint8_t attr; + grub_uint8_t reserved; + grub_uint8_t checksum; + grub_uint16_t name2[6]; + grub_uint16_t first_cluster; + grub_uint16_t name3[2]; +} GRUB_PACKED; + +typedef struct grub_fat_dir_entry grub_fat_dir_node_t; + +#endif + +struct grub_fat_data +{ + int logical_sector_bits; + grub_uint32_t num_sectors; + + grub_uint32_t fat_sector; + grub_uint32_t sectors_per_fat; + int fat_size; + + grub_uint32_t root_cluster; +#ifndef MODE_EXFAT + grub_uint32_t root_sector; + grub_uint32_t num_root_sectors; +#endif + + int cluster_bits; + grub_uint32_t cluster_eof_mark; + grub_uint32_t cluster_sector; + grub_uint32_t num_clusters; + + grub_uint32_t uuid; +}; + +struct grub_fshelp_node { + grub_disk_t disk; + struct grub_fat_data *data; + + grub_uint8_t attr; +#ifndef MODE_EXFAT + grub_uint32_t file_size; +#else + grub_uint64_t file_size; +#endif + grub_uint32_t file_cluster; + grub_uint32_t cur_cluster_num; + grub_uint32_t cur_cluster; + +#ifdef MODE_EXFAT + int is_contiguous; +#endif +}; + +static grub_dl_t my_mod; + +#ifndef MODE_EXFAT +static int +fat_log2 (unsigned x) +{ + int i; + + if (x == 0) + return -1; + + for (i = 0; (x & 1) == 0; i++) + x >>= 1; + + if (x != 1) + return -1; + + return i; +} +#endif + +static struct grub_fat_data * +grub_fat_mount (grub_disk_t disk) +{ + grub_current_fat_bpb_t bpb; + struct grub_fat_data *data = 0; + grub_uint32_t first_fat, magic; + + if (! disk) + goto fail; + + data = (struct grub_fat_data *) grub_malloc (sizeof (*data)); + if (! data) + goto fail; + + /* Read the BPB. */ + if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb)) + goto fail; + +#ifdef MODE_EXFAT + if (grub_memcmp ((const char *) bpb.oem_name, "EXFAT ", + sizeof (bpb.oem_name)) != 0) + goto fail; +#endif + + /* Get the sizes of logical sectors and clusters. */ +#ifdef MODE_EXFAT + data->logical_sector_bits = bpb.bytes_per_sector_shift; +#else + data->logical_sector_bits = + fat_log2 (grub_le_to_cpu16 (bpb.bytes_per_sector)); +#endif + if (data->logical_sector_bits < GRUB_DISK_SECTOR_BITS + || data->logical_sector_bits >= 16) + goto fail; + data->logical_sector_bits -= GRUB_DISK_SECTOR_BITS; + +#ifdef MODE_EXFAT + data->cluster_bits = bpb.sectors_per_cluster_shift; +#else + data->cluster_bits = fat_log2 (bpb.sectors_per_cluster); +#endif + if (data->cluster_bits < 0 || data->cluster_bits > 25) + goto fail; + data->cluster_bits += data->logical_sector_bits; + + /* Get information about FATs. */ +#ifdef MODE_EXFAT + data->fat_sector = (grub_le_to_cpu32 (bpb.num_reserved_sectors) + << data->logical_sector_bits); +#else + data->fat_sector = (grub_le_to_cpu16 (bpb.num_reserved_sectors) + << data->logical_sector_bits); +#endif + if (data->fat_sector == 0) + goto fail; + +#ifdef MODE_EXFAT + data->sectors_per_fat = (grub_le_to_cpu32 (bpb.sectors_per_fat) + << data->logical_sector_bits); +#else + data->sectors_per_fat = ((bpb.sectors_per_fat_16 + ? grub_le_to_cpu16 (bpb.sectors_per_fat_16) + : grub_le_to_cpu32 (bpb.version_specific.fat32.sectors_per_fat_32)) + << data->logical_sector_bits); +#endif + if (data->sectors_per_fat == 0) + goto fail; + + /* Get the number of sectors in this volume. */ +#ifdef MODE_EXFAT + data->num_sectors = ((grub_le_to_cpu64 (bpb.num_total_sectors)) + << data->logical_sector_bits); +#else + data->num_sectors = ((bpb.num_total_sectors_16 + ? grub_le_to_cpu16 (bpb.num_total_sectors_16) + : grub_le_to_cpu32 (bpb.num_total_sectors_32)) + << data->logical_sector_bits); +#endif + if (data->num_sectors == 0) + goto fail; + + /* Get information about the root directory. */ + if (bpb.num_fats == 0) + goto fail; + +#ifndef MODE_EXFAT + data->root_sector = data->fat_sector + bpb.num_fats * data->sectors_per_fat; + data->num_root_sectors + = ((((grub_uint32_t) grub_le_to_cpu16 (bpb.num_root_entries) + * sizeof (struct grub_fat_dir_entry) + + grub_le_to_cpu16 (bpb.bytes_per_sector) - 1) + >> (data->logical_sector_bits + GRUB_DISK_SECTOR_BITS)) + << (data->logical_sector_bits)); +#endif + +#ifdef MODE_EXFAT + data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset) + << data->logical_sector_bits); + data->num_clusters = (grub_le_to_cpu32 (bpb.cluster_count) + << data->logical_sector_bits); +#else + data->cluster_sector = data->root_sector + data->num_root_sectors; + data->num_clusters = (((data->num_sectors - data->cluster_sector) + >> data->cluster_bits) + + 2); +#endif + + if (data->num_clusters <= 2) + goto fail; + +#ifdef MODE_EXFAT + { + /* exFAT. */ + data->root_cluster = grub_le_to_cpu32 (bpb.root_cluster); + data->fat_size = 32; + data->cluster_eof_mark = 0xffffffff; + + if ((bpb.volume_flags & grub_cpu_to_le16_compile_time (0x1)) + && bpb.num_fats > 1) + data->fat_sector += data->sectors_per_fat; + } +#else + if (! bpb.sectors_per_fat_16) + { + /* FAT32. */ + grub_uint16_t flags = grub_le_to_cpu16 (bpb.version_specific.fat32.extended_flags); + + data->root_cluster = grub_le_to_cpu32 (bpb.version_specific.fat32.root_cluster); + data->fat_size = 32; + data->cluster_eof_mark = 0x0ffffff8; + + if (flags & 0x80) + { + /* Get an active FAT. */ + unsigned active_fat = flags & 0xf; + + if (active_fat > bpb.num_fats) + goto fail; + + data->fat_sector += active_fat * data->sectors_per_fat; + } + + if (bpb.num_root_entries != 0 || bpb.version_specific.fat32.fs_version != 0) + goto fail; + } + else + { + /* FAT12 or FAT16. */ + data->root_cluster = ~0U; + + if (data->num_clusters <= 4085 + 2) + { + /* FAT12. */ + data->fat_size = 12; + data->cluster_eof_mark = 0x0ff8; + } + else + { + /* FAT16. */ + data->fat_size = 16; + data->cluster_eof_mark = 0xfff8; + } + } +#endif + + /* More sanity checks. */ + if (data->num_sectors <= data->fat_sector) + goto fail; + + if (grub_disk_read (disk, + data->fat_sector, + 0, + sizeof (first_fat), + &first_fat)) + goto fail; + + first_fat = grub_le_to_cpu32 (first_fat); + + if (data->fat_size == 32) + { + first_fat &= 0x0fffffff; + magic = 0x0fffff00; + } + else if (data->fat_size == 16) + { + first_fat &= 0x0000ffff; + magic = 0xff00; + } + else + { + first_fat &= 0x00000fff; + magic = 0x0f00; + } + + /* Serial number. */ +#ifdef MODE_EXFAT + data->uuid = grub_le_to_cpu32 (bpb.num_serial); +#else + if (bpb.sectors_per_fat_16) + data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat12_or_fat16.num_serial); + else + data->uuid = grub_le_to_cpu32 (bpb.version_specific.fat32.num_serial); +#endif + +#ifndef MODE_EXFAT + /* Ignore the 3rd bit, because some BIOSes assigns 0xF0 to the media + descriptor, even if it is a so-called superfloppy (e.g. an USB key). + The check may be too strict for this kind of stupid BIOSes, as + they overwrite the media descriptor. */ + if ((first_fat | 0x8) != (magic | bpb.media | 0x8)) + goto fail; +#else + (void) magic; +#endif + + return data; + + fail: + + grub_free (data); + grub_error (GRUB_ERR_BAD_FS, "not a FAT filesystem"); + return 0; +} + +static grub_ssize_t +grub_fat_read_data (grub_disk_t disk, grub_fshelp_node_t node, + grub_disk_read_hook_t read_hook, void *read_hook_data, + grub_off_t offset, grub_size_t len, char *buf) +{ + grub_size_t size; + grub_uint32_t logical_cluster; + unsigned logical_cluster_bits; + grub_ssize_t ret = 0; + unsigned long sector; + +#ifndef MODE_EXFAT + /* This is a special case. FAT12 and FAT16 doesn't have the root directory + in clusters. */ + if (node->file_cluster == ~0U) + { + size = (node->data->num_root_sectors << GRUB_DISK_SECTOR_BITS) - offset; + if (size > len) + size = len; + + if (grub_disk_read (disk, node->data->root_sector, offset, size, buf)) + return -1; + + return size; + } +#endif + +#ifdef MODE_EXFAT + if (node->is_contiguous) + { + /* Read the data here. */ + sector = (node->data->cluster_sector + + ((node->file_cluster - 2) + << node->data->cluster_bits)); + + disk->read_hook = read_hook; + disk->read_hook_data = read_hook_data; + grub_disk_read (disk, sector + (offset >> GRUB_DISK_SECTOR_BITS), + offset & (GRUB_DISK_SECTOR_SIZE - 1), len, buf); + disk->read_hook = 0; + if (grub_errno) + return -1; + + return len; + } +#endif + + /* Calculate the logical cluster number and offset. */ + logical_cluster_bits = (node->data->cluster_bits + + GRUB_DISK_SECTOR_BITS); + logical_cluster = offset >> logical_cluster_bits; + offset &= (1ULL << logical_cluster_bits) - 1; + + if (logical_cluster < node->cur_cluster_num) + { + node->cur_cluster_num = 0; + node->cur_cluster = node->file_cluster; + } + + while (len) + { + while (logical_cluster > node->cur_cluster_num) + { + /* Find next cluster. */ + grub_uint32_t next_cluster; + grub_uint32_t fat_offset; + + switch (node->data->fat_size) + { + case 32: + fat_offset = node->cur_cluster << 2; + break; + case 16: + fat_offset = node->cur_cluster << 1; + break; + default: + /* case 12: */ + fat_offset = node->cur_cluster + (node->cur_cluster >> 1); + break; + } + + /* Read the FAT. */ + if (grub_disk_read (disk, node->data->fat_sector, fat_offset, + (node->data->fat_size + 7) >> 3, + (char *) &next_cluster)) + return -1; + + next_cluster = grub_le_to_cpu32 (next_cluster); + switch (node->data->fat_size) + { + case 16: + next_cluster &= 0xFFFF; + break; + case 12: + if (node->cur_cluster & 1) + next_cluster >>= 4; + + next_cluster &= 0x0FFF; + break; + } + + grub_dprintf ("fat", "fat_size=%d, next_cluster=%u\n", + node->data->fat_size, next_cluster); + + /* Check the end. */ + if (next_cluster >= node->data->cluster_eof_mark) + return ret; + + if (next_cluster < 2 || (next_cluster - 2) >= node->data->num_clusters) + { + grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u", + next_cluster); + return -1; + } + + node->cur_cluster = next_cluster; + node->cur_cluster_num++; + } + + /* Read the data here. */ + sector = (node->data->cluster_sector + + ((node->cur_cluster - 2) + << node->data->cluster_bits)); + size = (1 << logical_cluster_bits) - offset; + if (size > len) + size = len; + + disk->read_hook = read_hook; + disk->read_hook_data = read_hook_data; + grub_disk_read (disk, sector, offset, size, buf); + disk->read_hook = 0; + if (grub_errno) + return -1; + + len -= size; + buf += size; + ret += size; + logical_cluster++; + offset = 0; + } + + return ret; +} + +struct grub_fat_iterate_context +{ +#ifdef MODE_EXFAT + struct grub_fat_dir_node dir; +#else + struct grub_fat_dir_entry dir; +#endif + char *filename; + grub_uint16_t *unibuf; + grub_ssize_t offset; +}; + +static grub_err_t +grub_fat_iterate_init (struct grub_fat_iterate_context *ctxt) +{ + ctxt->offset = -sizeof (struct grub_fat_dir_entry); + +#ifndef MODE_EXFAT + /* Allocate space enough to hold a long name. */ + ctxt->filename = grub_malloc (0x40 * 13 * GRUB_MAX_UTF8_PER_UTF16 + 1); + ctxt->unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2); +#else + ctxt->unibuf = grub_malloc (15 * 256 * 2); + ctxt->filename = grub_malloc (15 * 256 * GRUB_MAX_UTF8_PER_UTF16 + 1); +#endif + + if (! ctxt->filename || ! ctxt->unibuf) + { + grub_free (ctxt->filename); + grub_free (ctxt->unibuf); + return grub_errno; + } + return GRUB_ERR_NONE; +} + +static void +grub_fat_iterate_fini (struct grub_fat_iterate_context *ctxt) +{ + grub_free (ctxt->filename); + grub_free (ctxt->unibuf); +} + +#ifdef MODE_EXFAT +static grub_err_t +grub_fat_iterate_dir_next (grub_fshelp_node_t node, + struct grub_fat_iterate_context *ctxt) +{ + grub_memset (&ctxt->dir, 0, sizeof (ctxt->dir)); + while (1) + { + struct grub_fat_dir_entry dir; + + ctxt->offset += sizeof (dir); + + if (grub_fat_read_data (node->disk, node, 0, 0, ctxt->offset, sizeof (dir), + (char *) &dir) + != sizeof (dir)) + break; + + if (dir.entry_type == 0) + break; + if (!(dir.entry_type & 0x80)) + continue; + + if (dir.entry_type == 0x85) + { + unsigned i, nsec, slots = 0; + + nsec = dir.type_specific.file.secondary_count; + + ctxt->dir.attr = grub_cpu_to_le16 (dir.type_specific.file.attr); + ctxt->dir.have_stream = 0; + for (i = 0; i < nsec; i++) + { + struct grub_fat_dir_entry sec; + ctxt->offset += sizeof (sec); + if (grub_fat_read_data (node->disk, node, 0, 0, + ctxt->offset, sizeof (sec), (char *) &sec) + != sizeof (sec)) + break; + if (!(sec.entry_type & 0x80)) + continue; + if (!(sec.entry_type & 0x40)) + break; + switch (sec.entry_type) + { + case 0xc0: + ctxt->dir.first_cluster = grub_cpu_to_le32 (sec.type_specific.stream_extension.first_cluster); + ctxt->dir.valid_size + = grub_cpu_to_le64 (sec.type_specific.stream_extension.valid_size); + ctxt->dir.file_size + = grub_cpu_to_le64 (sec.type_specific.stream_extension.file_size); + ctxt->dir.have_stream = 1; + ctxt->dir.is_contiguous = !!(sec.type_specific.stream_extension.flags + & grub_cpu_to_le16_compile_time (FLAG_CONTIGUOUS)); + break; + case 0xc1: + { + int j; + for (j = 0; j < 15; j++) + ctxt->unibuf[slots * 15 + j] + = grub_le_to_cpu16 (sec.type_specific.file_name.str[j]); + slots++; + } + break; + default: + grub_dprintf ("exfat", "unknown secondary type 0x%02x\n", + sec.entry_type); + } + } + + if (i != nsec) + { + ctxt->offset -= sizeof (dir); + continue; + } + + *grub_utf16_to_utf8 ((grub_uint8_t *) ctxt->filename, ctxt->unibuf, + slots * 15) = '\0'; + + return 0; + } + /* Allocation bitmap. */ + if (dir.entry_type == 0x81) + continue; + /* Upcase table. */ + if (dir.entry_type == 0x82) + continue; + /* Volume label. */ + if (dir.entry_type == 0x83) + continue; + grub_dprintf ("exfat", "unknown primary type 0x%02x\n", + dir.entry_type); + } + return grub_errno ? : GRUB_ERR_EOF; +} + +#else + +static grub_err_t +grub_fat_iterate_dir_next (grub_fshelp_node_t node, + struct grub_fat_iterate_context *ctxt) +{ + char *filep = 0; + int checksum = -1; + int slot = -1, slots = -1; + + while (1) + { + unsigned i; + + /* Adjust the offset. */ + ctxt->offset += sizeof (ctxt->dir); + + /* Read a directory entry. */ + if (grub_fat_read_data (node->disk, node, 0, 0, + ctxt->offset, sizeof (ctxt->dir), + (char *) &ctxt->dir) + != sizeof (ctxt->dir) || ctxt->dir.name[0] == 0) + break; + + /* Handle long name entries. */ + if (ctxt->dir.attr == GRUB_FAT_ATTR_LONG_NAME) + { + struct grub_fat_long_name_entry *long_name + = (struct grub_fat_long_name_entry *) &ctxt->dir; + grub_uint8_t id = long_name->id; + + if (id & 0x40) + { + id &= 0x3f; + slots = slot = id; + checksum = long_name->checksum; + } + + if (id != slot || slot == 0 || checksum != long_name->checksum) + { + checksum = -1; + continue; + } + + slot--; + grub_memcpy (ctxt->unibuf + slot * 13, long_name->name1, 5 * 2); + grub_memcpy (ctxt->unibuf + slot * 13 + 5, long_name->name2, 6 * 2); + grub_memcpy (ctxt->unibuf + slot * 13 + 11, long_name->name3, 2 * 2); + continue; + } + + /* Check if this entry is valid. */ + if (ctxt->dir.name[0] == 0xe5 || (ctxt->dir.attr & ~GRUB_FAT_ATTR_VALID)) + continue; + + /* This is a workaround for Japanese. */ + if (ctxt->dir.name[0] == 0x05) + ctxt->dir.name[0] = 0xe5; + + if (checksum != -1 && slot == 0) + { + grub_uint8_t sum; + + for (sum = 0, i = 0; i < sizeof (ctxt->dir.name); i++) + sum = ((sum >> 1) | (sum << 7)) + ctxt->dir.name[i]; + + if (sum == checksum) + { + int u; + + for (u = 0; u < slots * 13; u++) + ctxt->unibuf[u] = grub_le_to_cpu16 (ctxt->unibuf[u]); + + *grub_utf16_to_utf8 ((grub_uint8_t *) ctxt->filename, + ctxt->unibuf, + slots * 13) = '\0'; + + return GRUB_ERR_NONE; + } + + checksum = -1; + } + + /* Convert the 8.3 file name. */ + filep = ctxt->filename; + if (ctxt->dir.attr & GRUB_FAT_ATTR_VOLUME_ID) + { + for (i = 0; i < sizeof (ctxt->dir.name) && ctxt->dir.name[i]; i++) + *filep++ = ctxt->dir.name[i]; + while (i > 0 && ctxt->dir.name[i - 1] == ' ') + { + filep--; + i--; + } + } + else + { + for (i = 0; i < 8 && ctxt->dir.name[i]; i++) + *filep++ = grub_tolower (ctxt->dir.name[i]); + while (i > 0 && ctxt->dir.name[i - 1] == ' ') + { + filep--; + i--; + } + + /* XXX should we check that dir position is 0 or 1? */ + if (i > 2 || filep[0] != '.' || (i == 2 && filep[1] != '.')) + *filep++ = '.'; + + for (i = 8; i < 11 && ctxt->dir.name[i]; i++) + *filep++ = grub_tolower (ctxt->dir.name[i]); + while (i > 8 && ctxt->dir.name[i - 1] == ' ') + { + filep--; + i--; + } + + if (i == 8) + filep--; + } + *filep = '\0'; + return GRUB_ERR_NONE; + } + + return grub_errno ? : GRUB_ERR_EOF; +} + +#endif + +static grub_err_t lookup_file (grub_fshelp_node_t node, + const char *name, + grub_fshelp_node_t *foundnode, + enum grub_fshelp_filetype *foundtype) +{ + grub_err_t err; + struct grub_fat_iterate_context ctxt; + + err = grub_fat_iterate_init (&ctxt); + if (err) + return err; + + while (!(err = grub_fat_iterate_dir_next (node, &ctxt))) + { + +#ifdef MODE_EXFAT + if (!ctxt.dir.have_stream) + continue; +#else + if (ctxt.dir.attr & GRUB_FAT_ATTR_VOLUME_ID) + continue; +#endif + + if (grub_strcasecmp (name, ctxt.filename) == 0) + { + *foundnode = grub_malloc (sizeof (struct grub_fshelp_node)); + if (!*foundnode) + return grub_errno; + (*foundnode)->attr = ctxt.dir.attr; +#ifdef MODE_EXFAT + (*foundnode)->file_size = ctxt.dir.file_size; + (*foundnode)->file_cluster = ctxt.dir.first_cluster; + (*foundnode)->is_contiguous = ctxt.dir.is_contiguous; +#else + (*foundnode)->file_size = grub_le_to_cpu32 (ctxt.dir.file_size); + (*foundnode)->file_cluster = ((grub_le_to_cpu16 (ctxt.dir.first_cluster_high) << 16) + | grub_le_to_cpu16 (ctxt.dir.first_cluster_low)); + /* If directory points to root, starting cluster is 0 */ + if (!(*foundnode)->file_cluster) + (*foundnode)->file_cluster = node->data->root_cluster; +#endif + (*foundnode)->cur_cluster_num = ~0U; + (*foundnode)->data = node->data; + (*foundnode)->disk = node->disk; + + *foundtype = ((*foundnode)->attr & GRUB_FAT_ATTR_DIRECTORY) ? GRUB_FSHELP_DIR : GRUB_FSHELP_REG; + + grub_fat_iterate_fini (&ctxt); + return GRUB_ERR_NONE; + } + } + + grub_fat_iterate_fini (&ctxt); + if (err == GRUB_ERR_EOF) + err = 0; + + return err; + +} + +static grub_err_t +grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook, + void *hook_data) +{ + struct grub_fat_data *data = 0; + grub_disk_t disk = device->disk; + grub_fshelp_node_t found = NULL; + grub_err_t err; + struct grub_fat_iterate_context ctxt; + + grub_dl_ref (my_mod); + + data = grub_fat_mount (disk); + if (! data) + goto fail; + + struct grub_fshelp_node root = { + .data = data, + .disk = disk, + .attr = GRUB_FAT_ATTR_DIRECTORY, + .file_size = 0, + .file_cluster = data->root_cluster, + .cur_cluster_num = ~0U, + .cur_cluster = 0, +#ifdef MODE_EXFAT + .is_contiguous = 0, +#endif + }; + + err = grub_fshelp_find_file_lookup (path, &root, &found, lookup_file, NULL, GRUB_FSHELP_DIR); + if (err) + goto fail; + + err = grub_fat_iterate_init (&ctxt); + if (err) + goto fail; + + while (!(err = grub_fat_iterate_dir_next (found, &ctxt))) + { + struct grub_dirhook_info info; + grub_memset (&info, 0, sizeof (info)); + + info.dir = !! (ctxt.dir.attr & GRUB_FAT_ATTR_DIRECTORY); + info.case_insensitive = 1; + + if (!info.dir) + info.size = ctxt.dir.file_size; + +#ifdef MODE_EXFAT + if (!ctxt.dir.have_stream) + continue; +#else + if (ctxt.dir.attr & GRUB_FAT_ATTR_VOLUME_ID) + continue; +#endif + + if (hook (ctxt.filename, &info, hook_data)) + break; + } + grub_fat_iterate_fini (&ctxt); + if (err == GRUB_ERR_EOF) + err = 0; + + fail: + if (found != &root) + grub_free (found); + + grub_free (data); + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_err_t +grub_fat_open (grub_file_t file, const char *name) +{ + struct grub_fat_data *data = 0; + grub_fshelp_node_t found = NULL; + grub_err_t err; + grub_disk_t disk = file->device->disk; + + grub_dl_ref (my_mod); + + data = grub_fat_mount (disk); + if (! data) + goto fail; + + struct grub_fshelp_node root = { + .data = data, + .disk = disk, + .attr = GRUB_FAT_ATTR_DIRECTORY, + .file_size = 0, + .file_cluster = data->root_cluster, + .cur_cluster_num = ~0U, + .cur_cluster = 0, +#ifdef MODE_EXFAT + .is_contiguous = 0, +#endif + }; + + err = grub_fshelp_find_file_lookup (name, &root, &found, lookup_file, NULL, GRUB_FSHELP_REG); + if (err) + goto fail; + + file->data = found; + file->size = found->file_size; + + return GRUB_ERR_NONE; + + fail: + + if (found != &root) + grub_free (found); + + grub_free (data); + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_ssize_t +grub_fat_read (grub_file_t file, char *buf, grub_size_t len) +{ + return grub_fat_read_data (file->device->disk, file->data, + file->read_hook, file->read_hook_data, + file->offset, len, buf); +} + +static grub_err_t +grub_fat_close (grub_file_t file) +{ + grub_fshelp_node_t node = file->data; + + grub_free (node->data); + grub_free (node); + + grub_dl_unref (my_mod); + + return grub_errno; +} + +#ifdef MODE_EXFAT +static grub_err_t +grub_fat_label (grub_device_t device, char **label) +{ + struct grub_fat_dir_entry dir; + grub_ssize_t offset = -sizeof(dir); + grub_disk_t disk = device->disk; + struct grub_fshelp_node root = { + .disk = disk, + .attr = GRUB_FAT_ATTR_DIRECTORY, + .file_size = 0, + .cur_cluster_num = ~0U, + .cur_cluster = 0, + .is_contiguous = 0, + }; + + root.data = grub_fat_mount (disk); + if (! root.data) + return grub_errno; + + root.file_cluster = root.data->root_cluster; + + *label = NULL; + + while (1) + { + offset += sizeof (dir); + + if (grub_fat_read_data (disk, &root, 0, 0, + offset, sizeof (dir), (char *) &dir) + != sizeof (dir)) + break; + + if (dir.entry_type == 0) + break; + if (!(dir.entry_type & 0x80)) + continue; + + /* Volume label. */ + if (dir.entry_type == 0x83) + { + grub_size_t chc; + grub_uint16_t t[ARRAY_SIZE (dir.type_specific.volume_label.str)]; + grub_size_t i; + *label = grub_malloc (ARRAY_SIZE (dir.type_specific.volume_label.str) + * GRUB_MAX_UTF8_PER_UTF16 + 1); + if (!*label) + { + grub_free (root.data); + return grub_errno; + } + chc = dir.type_specific.volume_label.character_count; + if (chc > ARRAY_SIZE (dir.type_specific.volume_label.str)) + chc = ARRAY_SIZE (dir.type_specific.volume_label.str); + for (i = 0; i < chc; i++) + t[i] = grub_le_to_cpu16 (dir.type_specific.volume_label.str[i]); + *grub_utf16_to_utf8 ((grub_uint8_t *) *label, t, chc) = '\0'; + } + } + + grub_free (root.data); + return grub_errno; +} + +#else + +static grub_err_t +grub_fat_label (grub_device_t device, char **label) +{ + grub_disk_t disk = device->disk; + grub_err_t err; + struct grub_fat_iterate_context ctxt; + struct grub_fshelp_node root = { + .disk = disk, + .attr = GRUB_FAT_ATTR_DIRECTORY, + .file_size = 0, + .cur_cluster_num = ~0U, + .cur_cluster = 0, + }; + + *label = 0; + + grub_dl_ref (my_mod); + + root.data = grub_fat_mount (disk); + if (! root.data) + goto fail; + + root.file_cluster = root.data->root_cluster; + + err = grub_fat_iterate_init (&ctxt); + if (err) + goto fail; + + while (!(err = grub_fat_iterate_dir_next (&root, &ctxt))) + if ((ctxt.dir.attr & ~GRUB_FAT_ATTR_ARCHIVE) == GRUB_FAT_ATTR_VOLUME_ID) + { + *label = grub_strdup (ctxt.filename); + break; + } + + grub_fat_iterate_fini (&ctxt); + + fail: + + grub_dl_unref (my_mod); + + grub_free (root.data); + + return grub_errno; +} + +#endif + +static grub_err_t +grub_fat_uuid (grub_device_t device, char **uuid) +{ + struct grub_fat_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_fat_mount (disk); + if (data) + { + char *ptr; + *uuid = grub_xasprintf ("%04x-%04x", + (grub_uint16_t) (data->uuid >> 16), + (grub_uint16_t) data->uuid); + for (ptr = *uuid; ptr && *ptr; ptr++) + *ptr = grub_toupper (*ptr); + } + else + *uuid = NULL; + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + +#ifdef GRUB_UTIL +#ifndef MODE_EXFAT +grub_disk_addr_t +grub_fat_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn) +#else +grub_disk_addr_t + grub_exfat_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn) +#endif +{ + grub_disk_addr_t ret; + struct grub_fat_data *data; + data = grub_fat_mount (disk); + if (!data) + return 0; + ret = data->cluster_sector; + + *sec_per_lcn = 1ULL << data->cluster_bits; + + grub_free (data); + return ret; +} +#endif + +static struct grub_fs grub_fat_fs = + { +#ifdef MODE_EXFAT + .name = "exfat", +#else + .name = "fat", +#endif + .fs_dir = grub_fat_dir, + .fs_open = grub_fat_open, + .fs_read = grub_fat_read, + .fs_close = grub_fat_close, + .fs_label = grub_fat_label, + .fs_uuid = grub_fat_uuid, +#ifdef GRUB_UTIL +#ifdef MODE_EXFAT + /* ExFAT BPB is 30 larger than FAT32 one. */ + .reserved_first_sector = 0, +#else + .reserved_first_sector = 1, +#endif + .blocklist_install = 1, +#endif + .next = 0 + }; + +#ifdef MODE_EXFAT +GRUB_MOD_INIT(exfat) +#else +GRUB_MOD_INIT(fat) +#endif +{ + COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32); + grub_fs_register (&grub_fat_fs); + my_mod = mod; +} +#ifdef MODE_EXFAT +GRUB_MOD_FINI(exfat) +#else +GRUB_MOD_FINI(fat) +#endif +{ + grub_fs_unregister (&grub_fat_fs); +} + +#ifdef MODE_EXFAT + +int grub_fat_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list) +{ + grub_size_t size; + grub_uint32_t i; + grub_uint32_t logical_cluster; + unsigned logical_cluster_bits; + unsigned long sector; + grub_fshelp_node_t node; + grub_disk_t disk; + grub_uint64_t len; + + disk = file->device->disk; + node = file->data; + len = file->size; + + if (node->is_contiguous) + { + /* Read the data here. */ + sector = (node->data->cluster_sector + ((node->file_cluster - 2) << node->data->cluster_bits)); + + chunk_list->chunk[0].img_start_sector = 0; + chunk_list->chunk[0].img_end_sector = (file->size >> 11) - 1; + chunk_list->chunk[0].disk_start_sector = sector; + chunk_list->chunk[0].disk_end_sector = sector + (file->size >> disk->log_sector_size) - 1; + chunk_list->cur_chunk = 1; + + goto END; + } + + /* Calculate the logical cluster number and offset. */ + logical_cluster = 0; + logical_cluster_bits = (node->data->cluster_bits + GRUB_DISK_SECTOR_BITS); + + if (logical_cluster < node->cur_cluster_num) + { + node->cur_cluster_num = 0; + node->cur_cluster = node->file_cluster; + } + + while (len) + { + while (logical_cluster > node->cur_cluster_num) + { + /* Find next cluster. */ + grub_uint32_t next_cluster; + grub_uint32_t fat_offset; + + switch (node->data->fat_size) + { + case 32: + fat_offset = node->cur_cluster << 2; + break; + case 16: + fat_offset = node->cur_cluster << 1; + break; + default: + /* case 12: */ + fat_offset = node->cur_cluster + (node->cur_cluster >> 1); + break; + } + + /* Read the FAT. */ + if (grub_disk_read (disk, node->data->fat_sector, fat_offset, + (node->data->fat_size + 7) >> 3, + (char *) &next_cluster)) + { + return -1; + } + + next_cluster = grub_le_to_cpu32 (next_cluster); + switch (node->data->fat_size) + { + case 16: + next_cluster &= 0xFFFF; + break; + case 12: + if (node->cur_cluster & 1) + next_cluster >>= 4; + + next_cluster &= 0x0FFF; + break; + } + + grub_dprintf ("fat", "fat_size=%d, next_cluster=%u\n", node->data->fat_size, next_cluster); + + /* Check the end. */ + if (next_cluster >= node->data->cluster_eof_mark) + { + return 0; + } + + if (next_cluster < 2 || (next_cluster - 2) >= node->data->num_clusters) + { + grub_error (GRUB_ERR_BAD_FS, "invalid cluster %u", next_cluster); + return -1; + } + + node->cur_cluster = next_cluster; + node->cur_cluster_num++; + } + + /* Read the data here. */ + sector = (node->data->cluster_sector + + ((node->cur_cluster - 2) + << node->data->cluster_bits)); + size = (1 << logical_cluster_bits); + if (size > len) + size = len; + + grub_disk_blocklist_read(chunk_list, sector, size, disk->log_sector_size); + + len -= size; + logical_cluster++; + } + +END: + + for (i = 0; i < chunk_list->cur_chunk; i++) + { + chunk_list->chunk[i].disk_start_sector += part_start; + chunk_list->chunk[i].disk_end_sector += part_start; + } + + return 0; +} + +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fshelp.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fshelp.c new file mode 100644 index 0000000..b51c398 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/fshelp.c @@ -0,0 +1,436 @@ +/* fshelp.c -- Filesystem helper functions */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +typedef int (*iterate_dir_func) (grub_fshelp_node_t dir, + grub_fshelp_iterate_dir_hook_t hook, + void *data); +typedef grub_err_t (*lookup_file_func) (grub_fshelp_node_t dir, + const char *name, + grub_fshelp_node_t *foundnode, + enum grub_fshelp_filetype *foundtype); +typedef char *(*read_symlink_func) (grub_fshelp_node_t node); + +struct stack_element { + struct stack_element *parent; + grub_fshelp_node_t node; + enum grub_fshelp_filetype type; +}; + +/* Context for grub_fshelp_find_file. */ +struct grub_fshelp_find_file_ctx +{ + /* Inputs. */ + const char *path; + grub_fshelp_node_t rootnode; + + /* Global options. */ + int symlinknest; + + /* Current file being traversed and its parents. */ + struct stack_element *currnode; +}; + +/* Helper for find_file_iter. */ +static void +free_node (grub_fshelp_node_t node, struct grub_fshelp_find_file_ctx *ctx) +{ + if (node != ctx->rootnode) + grub_free (node); +} + +static void +pop_element (struct grub_fshelp_find_file_ctx *ctx) +{ + struct stack_element *el; + el = ctx->currnode; + ctx->currnode = el->parent; + free_node (el->node, ctx); + grub_free (el); +} + +static void +free_stack (struct grub_fshelp_find_file_ctx *ctx) +{ + while (ctx->currnode) + pop_element (ctx); +} + +static void +go_up_a_level (struct grub_fshelp_find_file_ctx *ctx) +{ + if (!ctx->currnode->parent) + return; + pop_element (ctx); +} + +static grub_err_t +push_node (struct grub_fshelp_find_file_ctx *ctx, grub_fshelp_node_t node, enum grub_fshelp_filetype filetype) +{ + struct stack_element *nst; + nst = grub_malloc (sizeof (*nst)); + if (!nst) + return grub_errno; + nst->node = node; + nst->type = filetype & ~GRUB_FSHELP_CASE_INSENSITIVE; + nst->parent = ctx->currnode; + ctx->currnode = nst; + return GRUB_ERR_NONE; +} + +static grub_err_t +go_to_root (struct grub_fshelp_find_file_ctx *ctx) +{ + free_stack (ctx); + return push_node (ctx, ctx->rootnode, GRUB_FSHELP_DIR); +} + +struct grub_fshelp_find_file_iter_ctx +{ + const char *name; + grub_fshelp_node_t *foundnode; + enum grub_fshelp_filetype *foundtype; +}; + +int g_ventoy_case_insensitive = 0; + +/* Helper for grub_fshelp_find_file. */ +static int +find_file_iter (const char *filename, enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node, void *data) +{ + struct grub_fshelp_find_file_iter_ctx *ctx = data; + + if (g_ventoy_case_insensitive) + { + filetype |= GRUB_FSHELP_CASE_INSENSITIVE; + } + + if (filetype == GRUB_FSHELP_UNKNOWN || + ((filetype & GRUB_FSHELP_CASE_INSENSITIVE) + ? grub_strcasecmp (ctx->name, filename) + : grub_strcmp (ctx->name, filename))) + { + grub_free (node); + return 0; + } + + /* The node is found, stop iterating over the nodes. */ + *ctx->foundnode = node; + *ctx->foundtype = filetype; + return 1; +} + +static grub_err_t +directory_find_file (grub_fshelp_node_t node, const char *name, grub_fshelp_node_t *foundnode, + enum grub_fshelp_filetype *foundtype, iterate_dir_func iterate_dir) +{ + int found; + struct grub_fshelp_find_file_iter_ctx ctx = { + .foundnode = foundnode, + .foundtype = foundtype, + .name = name + }; + found = iterate_dir (node, find_file_iter, &ctx); + if (! found) + { + if (grub_errno) + return grub_errno; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +find_file (char *currpath, + iterate_dir_func iterate_dir, lookup_file_func lookup_file, + read_symlink_func read_symlink, + struct grub_fshelp_find_file_ctx *ctx) +{ + char *name, *next; + grub_err_t err; + for (name = currpath; ; name = next) + { + char c; + grub_fshelp_node_t foundnode = NULL; + enum grub_fshelp_filetype foundtype = 0; + + /* Remove all leading slashes. */ + while (*name == '/') + name++; + + /* Found the node! */ + if (! *name) + return 0; + + /* Extract the actual part from the pathname. */ + for (next = name; *next && *next != '/'; next++); + + /* At this point it is expected that the current node is a + directory, check if this is true. */ + if (ctx->currnode->type != GRUB_FSHELP_DIR) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); + + /* Don't rely on fs providing actual . in the listing. */ + if (next - name == 1 && name[0] == '.') + continue; + + /* Don't rely on fs providing actual .. in the listing. */ + if (next - name == 2 && name[0] == '.' && name[1] == '.') + { + go_up_a_level (ctx); + continue; + } + + /* Iterate over the directory. */ + c = *next; + *next = '\0'; + if (lookup_file) + err = lookup_file (ctx->currnode->node, name, &foundnode, &foundtype); + else + err = directory_find_file (ctx->currnode->node, name, &foundnode, &foundtype, iterate_dir); + *next = c; + + if (err) + return err; + + if (!foundnode) + break; + + push_node (ctx, foundnode, foundtype); + + /* Read in the symlink and follow it. */ + if (ctx->currnode->type == GRUB_FSHELP_SYMLINK) + { + char *symlink; + + /* Test if the symlink does not loop. */ + if (++ctx->symlinknest == 8) + return grub_error (GRUB_ERR_SYMLINK_LOOP, + N_("too deep nesting of symlinks")); + + symlink = read_symlink (ctx->currnode->node); + + if (!symlink) + return grub_errno; + + /* The symlink is an absolute path, go back to the root inode. */ + if (symlink[0] == '/') + { + err = go_to_root (ctx); + if (err) + return err; + } + else + { + /* Get from symlink to containing directory. */ + go_up_a_level (ctx); + } + + + /* Lookup the node the symlink points to. */ + find_file (symlink, iterate_dir, lookup_file, read_symlink, ctx); + grub_free (symlink); + + if (grub_errno) + return grub_errno; + } + } + + return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), + ctx->path); +} + +static grub_err_t +grub_fshelp_find_file_real (const char *path, grub_fshelp_node_t rootnode, + grub_fshelp_node_t *foundnode, + iterate_dir_func iterate_dir, + lookup_file_func lookup_file, + read_symlink_func read_symlink, + enum grub_fshelp_filetype expecttype) +{ + struct grub_fshelp_find_file_ctx ctx = { + .path = path, + .rootnode = rootnode, + .symlinknest = 0, + .currnode = 0 + }; + grub_err_t err; + enum grub_fshelp_filetype foundtype; + char *duppath; + + if (!path || path[0] != '/') + { + return grub_error (GRUB_ERR_BAD_FILENAME, N_("invalid file name `%s'"), path); + } + + err = go_to_root (&ctx); + if (err) + return err; + + duppath = grub_strdup (path); + if (!duppath) + return grub_errno; + err = find_file (duppath, iterate_dir, lookup_file, read_symlink, &ctx); + grub_free (duppath); + if (err) + { + free_stack (&ctx); + return err; + } + + *foundnode = ctx.currnode->node; + foundtype = ctx.currnode->type; + /* Avoid the node being freed. */ + ctx.currnode->node = 0; + free_stack (&ctx); + + /* Check if the node that was found was of the expected type. */ + if (expecttype == GRUB_FSHELP_REG && foundtype != expecttype) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file")); + else if (expecttype == GRUB_FSHELP_DIR && foundtype != expecttype) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); + + return 0; +} + +/* Lookup the node PATH. The node ROOTNODE describes the root of the + directory tree. The node found is returned in FOUNDNODE, which is + either a ROOTNODE or a new malloc'ed node. ITERATE_DIR is used to + iterate over all directory entries in the current node. + READ_SYMLINK is used to read the symlink if a node is a symlink. + EXPECTTYPE is the type node that is expected by the called, an + error is generated if the node is not of the expected type. */ +grub_err_t +grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, + grub_fshelp_node_t *foundnode, + iterate_dir_func iterate_dir, + read_symlink_func read_symlink, + enum grub_fshelp_filetype expecttype) +{ + return grub_fshelp_find_file_real (path, rootnode, foundnode, + iterate_dir, NULL, + read_symlink, expecttype); + +} + +grub_err_t +grub_fshelp_find_file_lookup (const char *path, grub_fshelp_node_t rootnode, + grub_fshelp_node_t *foundnode, + lookup_file_func lookup_file, + read_symlink_func read_symlink, + enum grub_fshelp_filetype expecttype) +{ + return grub_fshelp_find_file_real (path, rootnode, foundnode, + NULL, lookup_file, + read_symlink, expecttype); + +} + +/* Read LEN bytes from the file NODE on disk DISK into the buffer BUF, + beginning with the block POS. READ_HOOK should be set before + reading a block from the file. READ_HOOK_DATA is passed through as + the DATA argument to READ_HOOK. GET_BLOCK is used to translate + file blocks to disk blocks. The file is FILESIZE bytes big and the + blocks have a size of LOG2BLOCKSIZE (in log2). */ +grub_ssize_t +grub_fshelp_read_file (grub_disk_t disk, grub_fshelp_node_t node, + grub_disk_read_hook_t read_hook, void *read_hook_data, + grub_off_t pos, grub_size_t len, char *buf, + grub_disk_addr_t (*get_block) (grub_fshelp_node_t node, + grub_disk_addr_t block), + grub_off_t filesize, int log2blocksize, + grub_disk_addr_t blocks_start) +{ + grub_disk_addr_t i, blockcnt; + int blocksize = 1 << (log2blocksize + GRUB_DISK_SECTOR_BITS); + + if (pos > filesize) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("attempt to read past the end of file")); + return -1; + } + + /* Adjust LEN so it we can't read past the end of the file. */ + if (pos + len > filesize) + len = filesize - pos; + + blockcnt = ((len + pos) + blocksize - 1) >> (log2blocksize + GRUB_DISK_SECTOR_BITS); + + for (i = pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS); i < blockcnt; i++) + { + grub_disk_addr_t blknr; + int blockoff = pos & (blocksize - 1); + int blockend = blocksize; + + int skipfirst = 0; + + blknr = get_block (node, i); + if (grub_errno) + return -1; + + blknr = blknr << log2blocksize; + + /* Last block. */ + if (i == blockcnt - 1) + { + blockend = (len + pos) & (blocksize - 1); + + /* The last portion is exactly blocksize. */ + if (! blockend) + blockend = blocksize; + } + + /* First block. */ + if (i == (pos >> (log2blocksize + GRUB_DISK_SECTOR_BITS))) + { + skipfirst = blockoff; + blockend -= skipfirst; + } + + /* If the block number is 0 this block is not stored on disk but + is zero filled instead. */ + if (blknr) + { + disk->read_hook = read_hook; + disk->read_hook_data = read_hook_data; + + grub_disk_read (disk, blknr + blocks_start, skipfirst, + blockend, buf); + disk->read_hook = 0; + if (grub_errno) + return -1; + } + else if (read_hook != (grub_disk_read_hook_t)(void *)grub_disk_blocklist_read) + grub_memset (buf, 0, blockend); + + buf += blocksize - skipfirst; + } + + return len; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/iso9660.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/iso9660.c new file mode 100644 index 0000000..9f2306f --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/iso9660.c @@ -0,0 +1,1167 @@ +/* iso9660.c - iso9660 implementation with extensions: + SUSP, Rock Ridge. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static int g_ventoy_no_joliet = 0; +static int g_ventoy_cur_joliet = 0; +static grub_uint64_t g_ventoy_last_read_pos = 0; +static grub_uint64_t g_ventoy_last_read_offset = 0; +static grub_uint64_t g_ventoy_last_read_dirent_pos = 0; +static grub_uint64_t g_ventoy_last_read_dirent_offset = 0; +static grub_uint64_t g_ventoy_last_file_dirent_pos = 0; +static grub_uint64_t g_ventoy_last_file_dirent_offset = 0; + +#define GRUB_ISO9660_FSTYPE_DIR 0040000 +#define GRUB_ISO9660_FSTYPE_REG 0100000 +#define GRUB_ISO9660_FSTYPE_SYMLINK 0120000 +#define GRUB_ISO9660_FSTYPE_MASK 0170000 + +#define GRUB_ISO9660_LOG2_BLKSZ 2 +#define GRUB_ISO9660_BLKSZ 2048 + +#define GRUB_ISO9660_RR_DOT 2 +#define GRUB_ISO9660_RR_DOTDOT 4 + +#define GRUB_ISO9660_VOLDESC_BOOT 0 +#define GRUB_ISO9660_VOLDESC_PRIMARY 1 +#define GRUB_ISO9660_VOLDESC_SUPP 2 +#define GRUB_ISO9660_VOLDESC_PART 3 +#define GRUB_ISO9660_VOLDESC_END 255 + +/* The head of a volume descriptor. */ +struct grub_iso9660_voldesc +{ + grub_uint8_t type; + grub_uint8_t magic[5]; + grub_uint8_t version; +} GRUB_PACKED; + +struct grub_iso9660_date2 +{ + grub_uint8_t year; + grub_uint8_t month; + grub_uint8_t day; + grub_uint8_t hour; + grub_uint8_t minute; + grub_uint8_t second; + grub_uint8_t offset; +} GRUB_PACKED; + +/* A directory entry. */ +struct grub_iso9660_dir +{ + grub_uint8_t len; + grub_uint8_t ext_sectors; + grub_uint32_t first_sector; + grub_uint32_t first_sector_be; + grub_uint32_t size; + grub_uint32_t size_be; + struct grub_iso9660_date2 mtime; + grub_uint8_t flags; + grub_uint8_t unused2[6]; +#define MAX_NAMELEN 255 + grub_uint8_t namelen; +} GRUB_PACKED; + +struct grub_iso9660_date +{ + grub_uint8_t year[4]; + grub_uint8_t month[2]; + grub_uint8_t day[2]; + grub_uint8_t hour[2]; + grub_uint8_t minute[2]; + grub_uint8_t second[2]; + grub_uint8_t hundredth[2]; + grub_uint8_t offset; +} GRUB_PACKED; + +/* The primary volume descriptor. Only little endian is used. */ +struct grub_iso9660_primary_voldesc +{ + struct grub_iso9660_voldesc voldesc; + grub_uint8_t unused1[33]; + grub_uint8_t volname[32]; + grub_uint8_t unused2[16]; + grub_uint8_t escape[32]; + grub_uint8_t unused3[12]; + grub_uint32_t path_table_size; + grub_uint8_t unused4[4]; + grub_uint32_t path_table; + grub_uint8_t unused5[12]; + struct grub_iso9660_dir rootdir; + grub_uint8_t unused6[624]; + struct grub_iso9660_date created; + struct grub_iso9660_date modified; +} GRUB_PACKED; + +/* A single entry in the path table. */ +struct grub_iso9660_path +{ + grub_uint8_t len; + grub_uint8_t sectors; + grub_uint32_t first_sector; + grub_uint16_t parentdir; + grub_uint8_t name[0]; +} GRUB_PACKED; + +/* An entry in the System Usage area of the directory entry. */ +struct grub_iso9660_susp_entry +{ + grub_uint8_t sig[2]; + grub_uint8_t len; + grub_uint8_t version; + grub_uint8_t data[0]; +} GRUB_PACKED; + +/* The CE entry. This is used to describe the next block where data + can be found. */ +struct grub_iso9660_susp_ce +{ + struct grub_iso9660_susp_entry entry; + grub_uint32_t blk; + grub_uint32_t blk_be; + grub_uint32_t off; + grub_uint32_t off_be; + grub_uint32_t len; + grub_uint32_t len_be; +} GRUB_PACKED; + +struct grub_iso9660_data +{ + struct grub_iso9660_primary_voldesc voldesc; + grub_disk_t disk; + int rockridge; + int susp_skip; + int joliet; + struct grub_fshelp_node *node; +}; + +struct grub_fshelp_node +{ + struct grub_iso9660_data *data; + grub_size_t have_dirents, alloc_dirents; + int have_symlink; + struct grub_iso9660_dir dirents[8]; + char symlink[0]; +}; + +enum + { + FLAG_TYPE_PLAIN = 0, + FLAG_TYPE_DIR = 2, + FLAG_TYPE = 3, + FLAG_MORE_EXTENTS = 0x80 + }; + +static grub_dl_t my_mod; + + +static grub_err_t +iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int32_t *nix) +{ + struct grub_datetime datetime; + + if (! i->year[0] && ! i->year[1] + && ! i->year[2] && ! i->year[3] + && ! i->month[0] && ! i->month[1] + && ! i->day[0] && ! i->day[1] + && ! i->hour[0] && ! i->hour[1] + && ! i->minute[0] && ! i->minute[1] + && ! i->second[0] && ! i->second[1] + && ! i->hundredth[0] && ! i->hundredth[1]) + return grub_error (GRUB_ERR_BAD_NUMBER, "empty date"); + datetime.year = (i->year[0] - '0') * 1000 + (i->year[1] - '0') * 100 + + (i->year[2] - '0') * 10 + (i->year[3] - '0'); + datetime.month = (i->month[0] - '0') * 10 + (i->month[1] - '0'); + datetime.day = (i->day[0] - '0') * 10 + (i->day[1] - '0'); + datetime.hour = (i->hour[0] - '0') * 10 + (i->hour[1] - '0'); + datetime.minute = (i->minute[0] - '0') * 10 + (i->minute[1] - '0'); + datetime.second = (i->second[0] - '0') * 10 + (i->second[1] - '0'); + + if (!grub_datetime2unixtime (&datetime, nix)) + return grub_error (GRUB_ERR_BAD_NUMBER, "incorrect date"); + *nix -= i->offset * 60 * 15; + return GRUB_ERR_NONE; +} + +static int +iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int32_t *nix) +{ + struct grub_datetime datetime; + + datetime.year = i->year + 1900; + datetime.month = i->month; + datetime.day = i->day; + datetime.hour = i->hour; + datetime.minute = i->minute; + datetime.second = i->second; + + if (!grub_datetime2unixtime (&datetime, nix)) + return 0; + *nix -= i->offset * 60 * 15; + return 1; +} + +static grub_err_t +read_node (grub_fshelp_node_t node, grub_off_t off, grub_size_t len, char *buf) +{ + grub_size_t i = 0; + + while (len > 0) + { + grub_size_t toread; + grub_err_t err; + while (i < node->have_dirents + && off >= grub_le_to_cpu32 (node->dirents[i].size)) + { + off -= grub_le_to_cpu32 (node->dirents[i].size); + i++; + } + if (i == node->have_dirents) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "read out of range"); + toread = grub_le_to_cpu32 (node->dirents[i].size); + if (toread > len) + toread = len; + g_ventoy_last_read_pos = ((grub_disk_addr_t) grub_le_to_cpu32 (node->dirents[i].first_sector)) << GRUB_ISO9660_LOG2_BLKSZ; + g_ventoy_last_read_offset = off; + err = grub_disk_read (node->data->disk, g_ventoy_last_read_pos, off, toread, buf); + if (err) + return err; + len -= toread; + off += toread; + buf += toread; + } + return GRUB_ERR_NONE; +} + +/* Iterate over the susp entries, starting with block SUA_BLOCK on the + offset SUA_POS with a size of SUA_SIZE bytes. Hook is called for + every entry. */ +static grub_err_t +grub_iso9660_susp_iterate (grub_fshelp_node_t node, grub_off_t off, + grub_ssize_t sua_size, + grub_err_t (*hook) + (struct grub_iso9660_susp_entry *entry, void *hook_arg), + void *hook_arg) +{ + char *sua; + struct grub_iso9660_susp_entry *entry; + grub_err_t err; + + if (sua_size <= 0) + return GRUB_ERR_NONE; + + sua = grub_malloc (sua_size); + if (!sua) + return grub_errno; + + /* Load a part of the System Usage Area. */ + err = read_node (node, off, sua_size, sua); + if (err) + return err; + + for (entry = (struct grub_iso9660_susp_entry *) sua; (char *) entry < (char *) sua + sua_size - 1 && entry->len > 0; + entry = (struct grub_iso9660_susp_entry *) + ((char *) entry + entry->len)) + { + /* The last entry. */ + if (grub_strncmp ((char *) entry->sig, "ST", 2) == 0) + break; + + /* Additional entries are stored elsewhere. */ + if (grub_strncmp ((char *) entry->sig, "CE", 2) == 0) + { + struct grub_iso9660_susp_ce *ce; + grub_disk_addr_t ce_block; + + ce = (struct grub_iso9660_susp_ce *) entry; + sua_size = grub_le_to_cpu32 (ce->len); + off = grub_le_to_cpu32 (ce->off); + ce_block = grub_le_to_cpu32 (ce->blk) << GRUB_ISO9660_LOG2_BLKSZ; + + grub_free (sua); + sua = grub_malloc (sua_size); + if (!sua) + return grub_errno; + + /* Load a part of the System Usage Area. */ + err = grub_disk_read (node->data->disk, ce_block, off, + sua_size, sua); + if (err) + return err; + + entry = (struct grub_iso9660_susp_entry *) sua; + } + + if (hook (entry, hook_arg)) + { + grub_free (sua); + return 0; + } + } + + grub_free (sua); + return 0; +} + +static char * +grub_iso9660_convert_string (grub_uint8_t *us, int len) +{ + char *p; + int i; + grub_uint16_t t[MAX_NAMELEN / 2 + 1]; + + p = grub_malloc (len * GRUB_MAX_UTF8_PER_UTF16 + 1); + if (! p) + return NULL; + + for (i=0; isig, "ER", 2) == 0) + { + data->rockridge = 1; + return 1; + } + return 0; +} + +static grub_err_t +set_rockridge (struct grub_iso9660_data *data) +{ + int sua_pos; + int sua_size; + char *sua; + struct grub_iso9660_dir rootdir; + struct grub_iso9660_susp_entry *entry; + + data->rockridge = 0; + + /* Read the system use area and test it to see if SUSP is + supported. */ + if (grub_disk_read (data->disk, + (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector) + << GRUB_ISO9660_LOG2_BLKSZ), 0, + sizeof (rootdir), (char *) &rootdir)) + return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); + + sua_pos = (sizeof (rootdir) + rootdir.namelen + + (rootdir.namelen % 2) - 1); + sua_size = rootdir.len - sua_pos; + + if (!sua_size) + return GRUB_ERR_NONE; + + sua = grub_malloc (sua_size); + if (! sua) + return grub_errno; + + if (grub_disk_read (data->disk, + (grub_le_to_cpu32 (data->voldesc.rootdir.first_sector) + << GRUB_ISO9660_LOG2_BLKSZ), sua_pos, + sua_size, sua)) + { + grub_free (sua); + return grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); + } + + entry = (struct grub_iso9660_susp_entry *) sua; + + /* Test if the SUSP protocol is used on this filesystem. */ + if (grub_strncmp ((char *) entry->sig, "SP", 2) == 0) + { + struct grub_fshelp_node rootnode; + + rootnode.data = data; + rootnode.alloc_dirents = ARRAY_SIZE (rootnode.dirents); + rootnode.have_dirents = 1; + rootnode.have_symlink = 0; + rootnode.dirents[0] = data->voldesc.rootdir; + + /* The 2nd data byte stored how many bytes are skipped every time + to get to the SUA (System Usage Area). */ + data->susp_skip = entry->data[2]; + entry = (struct grub_iso9660_susp_entry *) ((char *) entry + entry->len); + + /* Iterate over the entries in the SUA area to detect + extensions. */ + if (grub_iso9660_susp_iterate (&rootnode, + sua_pos, sua_size, susp_iterate_set_rockridge, + data)) + { + grub_free (sua); + return grub_errno; + } + } + grub_free (sua); + return GRUB_ERR_NONE; +} + +static struct grub_iso9660_data * +grub_iso9660_mount (grub_disk_t disk) +{ + struct grub_iso9660_data *data = 0; + struct grub_iso9660_primary_voldesc voldesc; + int block; + + data = grub_zalloc (sizeof (struct grub_iso9660_data)); + if (! data) + return 0; + + data->disk = disk; + + g_ventoy_cur_joliet = 0; + block = 16; + do + { + int copy_voldesc = 0; + + /* Read the superblock. */ + if (grub_disk_read (disk, block << GRUB_ISO9660_LOG2_BLKSZ, 0, + sizeof (struct grub_iso9660_primary_voldesc), + (char *) &voldesc)) + { + grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); + goto fail; + } + + if (grub_strncmp ((char *) voldesc.voldesc.magic, "CD001", 5) != 0) + { + grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); + goto fail; + } + + if (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_PRIMARY) + copy_voldesc = 1; + else if (!data->rockridge + && (voldesc.voldesc.type == GRUB_ISO9660_VOLDESC_SUPP) + && (voldesc.escape[0] == 0x25) && (voldesc.escape[1] == 0x2f) + && + ((voldesc.escape[2] == 0x40) || /* UCS-2 Level 1. */ + (voldesc.escape[2] == 0x43) || /* UCS-2 Level 2. */ + (voldesc.escape[2] == 0x45))) /* UCS-2 Level 3. */ + { + if (0 == g_ventoy_no_joliet) { + copy_voldesc = 1; + data->joliet = 1; + g_ventoy_cur_joliet = 1; + } + } + + if (copy_voldesc) + { + grub_memcpy((char *) &data->voldesc, (char *) &voldesc, + sizeof (struct grub_iso9660_primary_voldesc)); + if (set_rockridge (data)) + goto fail; + } + + block++; + } while (voldesc.voldesc.type != GRUB_ISO9660_VOLDESC_END); + + return data; + + fail: + grub_free (data); + return 0; +} + + +static char * +grub_iso9660_read_symlink (grub_fshelp_node_t node) +{ + return node->have_symlink + ? grub_strdup (node->symlink + + (node->have_dirents) * sizeof (node->dirents[0]) + - sizeof (node->dirents)) : grub_strdup (""); +} + +static grub_off_t +get_node_size (grub_fshelp_node_t node) +{ + grub_off_t ret = 0; + grub_size_t i; + + for (i = 0; i < node->have_dirents; i++) + ret += grub_le_to_cpu32 (node->dirents[i].size); + return ret; +} + +struct iterate_dir_ctx +{ + char *filename; + int filename_alloc; + enum grub_fshelp_filetype type; + char *symlink; + int was_continue; +}; + + /* Extend the symlink. */ +static void +add_part (struct iterate_dir_ctx *ctx, + const char *part, + int len2) +{ + int size = ctx->symlink ? grub_strlen (ctx->symlink) : 0; + + ctx->symlink = grub_realloc (ctx->symlink, size + len2 + 1); + if (! ctx->symlink) + return; + + grub_memcpy (ctx->symlink + size, part, len2); + ctx->symlink[size + len2] = 0; +} + +static grub_err_t +susp_iterate_dir (struct grub_iso9660_susp_entry *entry, + void *_ctx) +{ + struct iterate_dir_ctx *ctx = _ctx; + + /* The filename in the rock ridge entry. */ + if (grub_strncmp ("NM", (char *) entry->sig, 2) == 0) + { + /* The flags are stored at the data position 0, here the + filename type is stored. */ + /* FIXME: Fix this slightly improper cast. */ + if (entry->data[0] & GRUB_ISO9660_RR_DOT) + ctx->filename = (char *) "."; + else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT) + ctx->filename = (char *) ".."; + else if (entry->len >= 5) + { + grub_size_t off = 0, csize = 1; + char *old; + csize = entry->len - 5; + old = ctx->filename; + if (ctx->filename_alloc) + { + off = grub_strlen (ctx->filename); + ctx->filename = grub_realloc (ctx->filename, csize + off + 1); + } + else + { + off = 0; + ctx->filename = grub_zalloc (csize + 1); + } + if (!ctx->filename) + { + ctx->filename = old; + return grub_errno; + } + ctx->filename_alloc = 1; + grub_memcpy (ctx->filename + off, (char *) &entry->data[1], csize); + ctx->filename[off + csize] = '\0'; + } + } + /* The mode information (st_mode). */ + else if (grub_strncmp ((char *) entry->sig, "PX", 2) == 0) + { + /* At position 0 of the PX record the st_mode information is + stored (little-endian). */ + grub_uint32_t mode = ((entry->data[0] + (entry->data[1] << 8)) + & GRUB_ISO9660_FSTYPE_MASK); + + switch (mode) + { + case GRUB_ISO9660_FSTYPE_DIR: + ctx->type = GRUB_FSHELP_DIR; + break; + case GRUB_ISO9660_FSTYPE_REG: + ctx->type = GRUB_FSHELP_REG; + break; + case GRUB_ISO9660_FSTYPE_SYMLINK: + ctx->type = GRUB_FSHELP_SYMLINK; + break; + default: + ctx->type = GRUB_FSHELP_UNKNOWN; + } + } + else if (grub_strncmp ("SL", (char *) entry->sig, 2) == 0) + { + unsigned int pos = 1; + + /* The symlink is not stored as a POSIX symlink, translate it. */ + while (pos + sizeof (*entry) < entry->len) + { + /* The current position is the `Component Flag'. */ + switch (entry->data[pos] & 30) + { + case 0: + { + /* The data on pos + 2 is the actual data, pos + 1 + is the length. Both are part of the `Component + Record'. */ + if (ctx->symlink && !ctx->was_continue) + add_part (ctx, "/", 1); + add_part (ctx, (char *) &entry->data[pos + 2], + entry->data[pos + 1]); + ctx->was_continue = (entry->data[pos] & 1); + break; + } + + case 2: + add_part (ctx, "./", 2); + break; + + case 4: + add_part (ctx, "../", 3); + break; + + case 8: + add_part (ctx, "/", 1); + break; + } + /* In pos + 1 the length of the `Component Record' is + stored. */ + pos += entry->data[pos + 1] + 2; + } + + /* Check if `grub_realloc' failed. */ + if (grub_errno) + return grub_errno; + } + + return 0; +} + +static int +grub_iso9660_iterate_dir (grub_fshelp_node_t dir, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) +{ + struct grub_iso9660_dir dirent; + grub_off_t offset = 0; + grub_off_t len; + struct iterate_dir_ctx ctx; + + len = get_node_size (dir); + + for (; offset < len; offset += dirent.len) + { + ctx.symlink = 0; + ctx.was_continue = 0; + + if (read_node (dir, offset, sizeof (dirent), (char *) &dirent)) + return 0; + + if ((dirent.flags & FLAG_TYPE) != FLAG_TYPE_DIR) { + g_ventoy_last_read_dirent_pos = g_ventoy_last_read_pos; + g_ventoy_last_read_dirent_offset = g_ventoy_last_read_offset; + } + + /* The end of the block, skip to the next one. */ + if (!dirent.len) + { + offset = (offset / GRUB_ISO9660_BLKSZ + 1) * GRUB_ISO9660_BLKSZ; + continue; + } + + { + char name[MAX_NAMELEN + 1]; + int nameoffset = offset + sizeof (dirent); + struct grub_fshelp_node *node; + int sua_off = (sizeof (dirent) + dirent.namelen + 1 + - (dirent.namelen % 2)); + int sua_size = dirent.len - sua_off; + + sua_off += offset + dir->data->susp_skip; + + ctx.filename = 0; + ctx.filename_alloc = 0; + ctx.type = GRUB_FSHELP_UNKNOWN; + + if (dir->data->rockridge + && grub_iso9660_susp_iterate (dir, sua_off, sua_size, + susp_iterate_dir, &ctx)) + return 0; + + /* Read the name. */ + if (read_node (dir, nameoffset, dirent.namelen, (char *) name)) + return 0; + + node = grub_malloc (sizeof (struct grub_fshelp_node)); + if (!node) + return 0; + + node->alloc_dirents = ARRAY_SIZE (node->dirents); + node->have_dirents = 1; + + /* Setup a new node. */ + node->data = dir->data; + node->have_symlink = 0; + + /* If the filetype was not stored using rockridge, use + whatever is stored in the iso9660 filesystem. */ + if (ctx.type == GRUB_FSHELP_UNKNOWN) + { + if ((dirent.flags & FLAG_TYPE) == FLAG_TYPE_DIR) + ctx.type = GRUB_FSHELP_DIR; + else if ((dirent.flags & FLAG_TYPE) == 3) + ctx.type = GRUB_FSHELP_DIR; + else + ctx.type = GRUB_FSHELP_REG; + } + + /* . and .. */ + if (!ctx.filename && dirent.namelen == 1 && name[0] == 0) + ctx.filename = (char *) "."; + + if (!ctx.filename && dirent.namelen == 1 && name[0] == 1) + ctx.filename = (char *) ".."; + + /* The filename was not stored in a rock ridge entry. Read it + from the iso9660 filesystem. */ + if (!dir->data->joliet && !ctx.filename) + { + char *ptr; + name[dirent.namelen] = '\0'; + ctx.filename = grub_strrchr (name, ';'); + if (ctx.filename) + *ctx.filename = '\0'; + /* ISO9660 names are not case-preserving. */ + ctx.type |= GRUB_FSHELP_CASE_INSENSITIVE; + for (ptr = name; *ptr; ptr++) + *ptr = grub_tolower (*ptr); + if (ptr != name && *(ptr - 1) == '.') + *(ptr - 1) = 0; + ctx.filename = name; + } + + if (dir->data->joliet && !ctx.filename) + { + char *semicolon; + + ctx.filename = grub_iso9660_convert_string + ((grub_uint8_t *) name, dirent.namelen >> 1); + + semicolon = grub_strrchr (ctx.filename, ';'); + if (semicolon) + *semicolon = '\0'; + + ctx.filename_alloc = 1; + } + + node->dirents[0] = dirent; + while (dirent.flags & FLAG_MORE_EXTENTS) + { + offset += dirent.len; + if (read_node (dir, offset, sizeof (dirent), (char *) &dirent)) + { + if (ctx.filename_alloc) + grub_free (ctx.filename); + grub_free (node); + return 0; + } + if (node->have_dirents >= node->alloc_dirents) + { + struct grub_fshelp_node *new_node; + node->alloc_dirents *= 2; + new_node = grub_realloc (node, + sizeof (struct grub_fshelp_node) + + ((node->alloc_dirents + - ARRAY_SIZE (node->dirents)) + * sizeof (node->dirents[0]))); + if (!new_node) + { + if (ctx.filename_alloc) + grub_free (ctx.filename); + grub_free (node); + return 0; + } + node = new_node; + } + node->dirents[node->have_dirents++] = dirent; + } + if (ctx.symlink) + { + if ((node->alloc_dirents - node->have_dirents) + * sizeof (node->dirents[0]) < grub_strlen (ctx.symlink) + 1) + { + struct grub_fshelp_node *new_node; + new_node = grub_realloc (node, + sizeof (struct grub_fshelp_node) + + ((node->alloc_dirents + - ARRAY_SIZE (node->dirents)) + * sizeof (node->dirents[0])) + + grub_strlen (ctx.symlink) + 1); + if (!new_node) + { + if (ctx.filename_alloc) + grub_free (ctx.filename); + grub_free (node); + return 0; + } + node = new_node; + } + node->have_symlink = 1; + grub_strcpy (node->symlink + + node->have_dirents * sizeof (node->dirents[0]) + - sizeof (node->dirents), ctx.symlink); + grub_free (ctx.symlink); + ctx.symlink = 0; + ctx.was_continue = 0; + } + if (hook (ctx.filename, ctx.type, node, hook_data)) + { + g_ventoy_last_file_dirent_pos = g_ventoy_last_read_dirent_pos; + g_ventoy_last_file_dirent_offset = g_ventoy_last_read_dirent_offset; + if (ctx.filename_alloc) + grub_free (ctx.filename); + return 1; + } + if (ctx.filename_alloc) + grub_free (ctx.filename); + } + } + + return 0; +} + + + +/* Context for grub_iso9660_dir. */ +struct grub_iso9660_dir_ctx +{ + grub_fs_dir_hook_t hook; + void *hook_data; +}; + +/* Helper for grub_iso9660_dir. */ +static int +grub_iso9660_dir_iter (const char *filename, + enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node, void *data) +{ + struct grub_iso9660_dir_ctx *ctx = data; + struct grub_dirhook_info info; + + grub_memset (&info, 0, sizeof (info)); + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = !!iso9660_to_unixtime2 (&node->dirents[0].mtime, &info.mtime); + + grub_free (node); + return ctx->hook (filename, &info, ctx->hook_data); +} + +static grub_err_t +grub_iso9660_dir (grub_device_t device, const char *path, + grub_fs_dir_hook_t hook, void *hook_data) +{ + struct grub_iso9660_dir_ctx ctx = { hook, hook_data }; + struct grub_iso9660_data *data = 0; + struct grub_fshelp_node rootnode; + struct grub_fshelp_node *foundnode; + + grub_dl_ref (my_mod); + + data = grub_iso9660_mount (device->disk); + if (! data) + goto fail; + + rootnode.data = data; + rootnode.alloc_dirents = 0; + rootnode.have_dirents = 1; + rootnode.have_symlink = 0; + rootnode.dirents[0] = data->voldesc.rootdir; + + /* Use the fshelp function to traverse the path. */ + if (grub_fshelp_find_file (path, &rootnode, + &foundnode, + grub_iso9660_iterate_dir, + grub_iso9660_read_symlink, + GRUB_FSHELP_DIR)) + goto fail; + + /* List the files in the directory. */ + grub_iso9660_iterate_dir (foundnode, grub_iso9660_dir_iter, &ctx); + + if (foundnode != &rootnode) + grub_free (foundnode); + + fail: + grub_free (data); + + grub_dl_unref (my_mod); + + return grub_errno; +} + + +/* Open a file named NAME and initialize FILE. */ +static grub_err_t +grub_iso9660_open (struct grub_file *file, const char *name) +{ + struct grub_iso9660_data *data; + struct grub_fshelp_node rootnode; + struct grub_fshelp_node *foundnode; + + grub_dl_ref (my_mod); + + data = grub_iso9660_mount (file->device->disk); + if (!data) + goto fail; + + rootnode.data = data; + rootnode.alloc_dirents = 0; + rootnode.have_dirents = 1; + rootnode.have_symlink = 0; + rootnode.dirents[0] = data->voldesc.rootdir; + + /* Use the fshelp function to traverse the path. */ + if (grub_fshelp_find_file (name, &rootnode, + &foundnode, + grub_iso9660_iterate_dir, + grub_iso9660_read_symlink, + GRUB_FSHELP_REG)) + goto fail; + + data->node = foundnode; + file->data = data; + file->size = get_node_size (foundnode); + file->offset = 0; + + return 0; + + fail: + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + + +static grub_ssize_t +grub_iso9660_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_iso9660_data *data = + (struct grub_iso9660_data *) file->data; + grub_err_t err; + + /* XXX: The file is stored in as a single extent. */ + data->disk->read_hook = file->read_hook; + data->disk->read_hook_data = file->read_hook_data; + err = read_node (data->node, file->offset, len, buf); + data->disk->read_hook = NULL; + + if (err || grub_errno) + return -1; + + return len; +} + + +static grub_err_t +grub_iso9660_close (grub_file_t file) +{ + struct grub_iso9660_data *data = + (struct grub_iso9660_data *) file->data; + grub_free (data->node); + grub_free (data); + + grub_dl_unref (my_mod); + + return GRUB_ERR_NONE; +} + + +static grub_err_t +grub_iso9660_label (grub_device_t device, char **label) +{ + struct grub_iso9660_data *data; + data = grub_iso9660_mount (device->disk); + + if (data) + { + if (data->joliet) + *label = grub_iso9660_convert_string (data->voldesc.volname, 16); + else + *label = grub_strndup ((char *) data->voldesc.volname, 32); + if (*label) + { + char *ptr; + for (ptr = *label; *ptr;ptr++); + ptr--; + while (ptr >= *label && *ptr == ' ') + *ptr-- = 0; + } + + grub_free (data); + } + else + *label = 0; + + return grub_errno; +} + + +static grub_err_t +grub_iso9660_uuid (grub_device_t device, char **uuid) +{ + struct grub_iso9660_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_iso9660_mount (disk); + if (data) + { + if (! data->voldesc.modified.year[0] && ! data->voldesc.modified.year[1] + && ! data->voldesc.modified.year[2] && ! data->voldesc.modified.year[3] + && ! data->voldesc.modified.month[0] && ! data->voldesc.modified.month[1] + && ! data->voldesc.modified.day[0] && ! data->voldesc.modified.day[1] + && ! data->voldesc.modified.hour[0] && ! data->voldesc.modified.hour[1] + && ! data->voldesc.modified.minute[0] && ! data->voldesc.modified.minute[1] + && ! data->voldesc.modified.second[0] && ! data->voldesc.modified.second[1] + && ! data->voldesc.modified.hundredth[0] && ! data->voldesc.modified.hundredth[1]) + { + grub_error (GRUB_ERR_BAD_NUMBER, "no creation date in filesystem to generate UUID"); + *uuid = NULL; + } + else + { + *uuid = grub_xasprintf ("%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c", + data->voldesc.modified.year[0], + data->voldesc.modified.year[1], + data->voldesc.modified.year[2], + data->voldesc.modified.year[3], + data->voldesc.modified.month[0], + data->voldesc.modified.month[1], + data->voldesc.modified.day[0], + data->voldesc.modified.day[1], + data->voldesc.modified.hour[0], + data->voldesc.modified.hour[1], + data->voldesc.modified.minute[0], + data->voldesc.modified.minute[1], + data->voldesc.modified.second[0], + data->voldesc.modified.second[1], + data->voldesc.modified.hundredth[0], + data->voldesc.modified.hundredth[1]); + } + } + else + *uuid = NULL; + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + +/* Get writing time of filesystem. */ +static grub_err_t +grub_iso9660_mtime (grub_device_t device, grub_int32_t *timebuf) +{ + struct grub_iso9660_data *data; + grub_disk_t disk = device->disk; + grub_err_t err; + + grub_dl_ref (my_mod); + + data = grub_iso9660_mount (disk); + if (!data) + { + grub_dl_unref (my_mod); + return grub_errno; + } + err = iso9660_to_unixtime (&data->voldesc.modified, timebuf); + + grub_dl_unref (my_mod); + + grub_free (data); + + return err; +} + +void grub_iso9660_set_nojoliet(int nojoliet) +{ + g_ventoy_no_joliet = nojoliet; +} + +int grub_iso9660_is_joliet(void) +{ + return g_ventoy_cur_joliet; +} + +grub_uint64_t grub_iso9660_get_last_read_pos(grub_file_t file) +{ + (void)file; + return (g_ventoy_last_read_pos << GRUB_DISK_SECTOR_BITS); +} + +grub_uint64_t grub_iso9660_get_last_file_dirent_pos(grub_file_t file) +{ + (void)file; + return (g_ventoy_last_file_dirent_pos << GRUB_DISK_SECTOR_BITS) + g_ventoy_last_file_dirent_offset; +} + +static struct grub_fs grub_iso9660_fs = + { + .name = "iso9660", + .fs_dir = grub_iso9660_dir, + .fs_open = grub_iso9660_open, + .fs_read = grub_iso9660_read, + .fs_close = grub_iso9660_close, + .fs_label = grub_iso9660_label, + .fs_uuid = grub_iso9660_uuid, + .fs_mtime = grub_iso9660_mtime, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif + .next = 0 + }; + +GRUB_MOD_INIT(iso9660) +{ + grub_fs_register (&grub_iso9660_fs); + my_mod = mod; +} + +GRUB_MOD_FINI(iso9660) +{ + grub_fs_unregister (&grub_iso9660_fs); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ntfs.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ntfs.c new file mode 100644 index 0000000..085f0d0 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/ntfs.c @@ -0,0 +1,1244 @@ +/* ntfs.c - NTFS filesystem */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007,2008,2009 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define grub_fshelp_node grub_ntfs_file + +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_dl_t my_mod; + +#define grub_fshelp_node grub_ntfs_file + +static inline grub_uint16_t +u16at (void *ptr, grub_size_t ofs) +{ + return grub_le_to_cpu16 (grub_get_unaligned16 ((char *) ptr + ofs)); +} + +static inline grub_uint32_t +u32at (void *ptr, grub_size_t ofs) +{ + return grub_le_to_cpu32 (grub_get_unaligned32 ((char *) ptr + ofs)); +} + +static inline grub_uint64_t +u64at (void *ptr, grub_size_t ofs) +{ + return grub_le_to_cpu64 (grub_get_unaligned64 ((char *) ptr + ofs)); +} + +grub_ntfscomp_func_t grub_ntfscomp_func; + +static grub_err_t +fixup (grub_uint8_t *buf, grub_size_t len, const grub_uint8_t *magic) +{ + grub_uint16_t ss; + grub_uint8_t *pu; + grub_uint16_t us; + + COMPILE_TIME_ASSERT ((1 << GRUB_NTFS_BLK_SHR) == GRUB_DISK_SECTOR_SIZE); + + if (grub_memcmp (buf, magic, 4)) + return grub_error (GRUB_ERR_BAD_FS, "%s label not found", magic); + + ss = u16at (buf, 6) - 1; + if (ss != len) + return grub_error (GRUB_ERR_BAD_FS, "size not match"); + pu = buf + u16at (buf, 4); + us = u16at (pu, 0); + buf -= 2; + while (ss > 0) + { + buf += GRUB_DISK_SECTOR_SIZE; + pu += 2; + if (u16at (buf, 0) != us) + return grub_error (GRUB_ERR_BAD_FS, "fixup signature not match"); + buf[0] = pu[0]; + buf[1] = pu[1]; + ss--; + } + + return 0; +} + +static grub_err_t read_mft (struct grub_ntfs_data *data, grub_uint8_t *buf, + grub_uint64_t mftno); +static grub_err_t read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, + grub_disk_addr_t ofs, grub_size_t len, + int cached, + grub_disk_read_hook_t read_hook, + void *read_hook_data); + +static grub_err_t read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, + grub_uint8_t *dest, + grub_disk_addr_t ofs, grub_size_t len, + int cached, + grub_disk_read_hook_t read_hook, + void *read_hook_data); + +static void +init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft) +{ + at->mft = mft; + at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0; + at->attr_nxt = mft->buf + u16at (mft->buf, 0x14); + at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL; +} + +static void +free_attr (struct grub_ntfs_attr *at) +{ + grub_free (at->emft_buf); + grub_free (at->edat_buf); + grub_free (at->sbuf); +} + +static grub_uint8_t * +find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) +{ + if (at->flags & GRUB_NTFS_AF_ALST) + { + retry: + while (at->attr_nxt < at->attr_end) + { + at->attr_cur = at->attr_nxt; + at->attr_nxt += u16at (at->attr_cur, 4); + if ((*at->attr_cur == attr) || (attr == 0)) + { + grub_uint8_t *new_pos; + + if (at->flags & GRUB_NTFS_AF_MMFT) + { + if ((grub_disk_read + (at->mft->data->disk, u32at (at->attr_cur, 0x10), 0, + 512, at->emft_buf)) + || + (grub_disk_read + (at->mft->data->disk, u32at (at->attr_cur, 0x14), 0, + 512, at->emft_buf + 512))) + return NULL; + + if (fixup (at->emft_buf, at->mft->data->mft_size, + (const grub_uint8_t *) "FILE")) + return NULL; + } + else + { + if (read_mft (at->mft->data, at->emft_buf, + u32at (at->attr_cur, 0x10))) + return NULL; + } + + new_pos = &at->emft_buf[u16at (at->emft_buf, 0x14)]; + while (*new_pos != 0xFF) + { + if ((*new_pos == *at->attr_cur) + && (u16at (new_pos, 0xE) == u16at (at->attr_cur, 0x18))) + { + return new_pos; + } + new_pos += u16at (new_pos, 4); + } + grub_error (GRUB_ERR_BAD_FS, + "can\'t find 0x%X in attribute list", + (unsigned char) *at->attr_cur); + return NULL; + } + } + return NULL; + } + at->attr_cur = at->attr_nxt; + while (*at->attr_cur != 0xFF) + { + at->attr_nxt += u16at (at->attr_cur, 4); + if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST) + at->attr_end = at->attr_cur; + if ((*at->attr_cur == attr) || (attr == 0)) + return at->attr_cur; + at->attr_cur = at->attr_nxt; + } + if (at->attr_end) + { + grub_uint8_t *pa; + + at->emft_buf = grub_malloc (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + if (at->emft_buf == NULL) + return NULL; + + pa = at->attr_end; + if (pa[8]) + { + grub_uint32_t n; + + n = ((u32at (pa, 0x30) + GRUB_DISK_SECTOR_SIZE - 1) + & (~(GRUB_DISK_SECTOR_SIZE - 1))); + at->attr_cur = at->attr_end; + at->edat_buf = grub_malloc (n); + if (!at->edat_buf) + return NULL; + if (read_data (at, pa, at->edat_buf, 0, n, 0, 0, 0)) + { + grub_error (GRUB_ERR_BAD_FS, + "fail to read non-resident attribute list"); + return NULL; + } + at->attr_nxt = at->edat_buf; + at->attr_end = at->edat_buf + u32at (pa, 0x30); + } + else + { + at->attr_nxt = at->attr_end + u16at (pa, 0x14); + at->attr_end = at->attr_end + u32at (pa, 4); + } + at->flags |= GRUB_NTFS_AF_ALST; + while (at->attr_nxt < at->attr_end) + { + if ((*at->attr_nxt == attr) || (attr == 0)) + break; + at->attr_nxt += u16at (at->attr_nxt, 4); + } + if (at->attr_nxt >= at->attr_end) + return NULL; + + if ((at->flags & GRUB_NTFS_AF_MMFT) && (attr == GRUB_NTFS_AT_DATA)) + { + at->flags |= GRUB_NTFS_AF_GPOS; + at->attr_cur = at->attr_nxt; + pa = at->attr_cur; + grub_set_unaligned32 ((char *) pa + 0x10, + grub_cpu_to_le32 (at->mft->data->mft_start)); + grub_set_unaligned32 ((char *) pa + 0x14, + grub_cpu_to_le32 (at->mft->data->mft_start + + 1)); + pa = at->attr_nxt + u16at (pa, 4); + while (pa < at->attr_end) + { + if (*pa != attr) + break; + if (read_attr + (at, pa + 0x10, + u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), + at->mft->data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0, 0)) + return NULL; + pa += u16at (pa, 4); + } + at->attr_nxt = at->attr_cur; + at->flags &= ~GRUB_NTFS_AF_GPOS; + } + goto retry; + } + return NULL; +} + +static grub_uint8_t * +locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft, + grub_uint8_t attr) +{ + grub_uint8_t *pa; + + init_attr (at, mft); + pa = find_attr (at, attr); + if (pa == NULL) + return NULL; + if ((at->flags & GRUB_NTFS_AF_ALST) == 0) + { + while (1) + { + pa = find_attr (at, attr); + if (pa == NULL) + break; + if (at->flags & GRUB_NTFS_AF_ALST) + return pa; + } + grub_errno = GRUB_ERR_NONE; + free_attr (at); + init_attr (at, mft); + pa = find_attr (at, attr); + } + return pa; +} + +static grub_disk_addr_t +read_run_data (const grub_uint8_t *run, int nn, int sig) +{ + grub_uint64_t r = 0; + + if (sig && nn && (run[nn - 1] & 0x80)) + r = -1; + + grub_memcpy (&r, run, nn); + + return grub_le_to_cpu64 (r); +} + +grub_err_t +grub_ntfs_read_run_list (struct grub_ntfs_rlst * ctx) +{ + grub_uint8_t c1, c2; + grub_disk_addr_t val; + grub_uint8_t *run; + + run = ctx->cur_run; +retry: + c1 = ((*run) & 0x7); + c2 = ((*run) >> 4) & 0x7; + run++; + if (!c1) + { + if ((ctx->attr) && (ctx->attr->flags & GRUB_NTFS_AF_ALST)) + { + grub_disk_read_hook_t save_hook; + + save_hook = ctx->comp.disk->read_hook; + ctx->comp.disk->read_hook = 0; + run = find_attr (ctx->attr, *ctx->attr->attr_cur); + ctx->comp.disk->read_hook = save_hook; + if (run) + { + if (run[8] == 0) + return grub_error (GRUB_ERR_BAD_FS, + "$DATA should be non-resident"); + + run += u16at (run, 0x20); + ctx->curr_lcn = 0; + goto retry; + } + } + return grub_error (GRUB_ERR_BAD_FS, "run list overflown"); + } + ctx->curr_vcn = ctx->next_vcn; + ctx->next_vcn += read_run_data (run, c1, 0); /* length of current VCN */ + run += c1; + val = read_run_data (run, c2, 1); /* offset to previous LCN */ + run += c2; + ctx->curr_lcn += val; + if (val == 0) + ctx->flags |= GRUB_NTFS_RF_BLNK; + else + ctx->flags &= ~GRUB_NTFS_RF_BLNK; + ctx->cur_run = run; + return 0; +} + +static grub_disk_addr_t +grub_ntfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t block) +{ + struct grub_ntfs_rlst *ctx; + + ctx = (struct grub_ntfs_rlst *) node; + if (block >= ctx->next_vcn) + { + if (grub_ntfs_read_run_list (ctx)) + return -1; + return ctx->curr_lcn; + } + else + return (ctx->flags & GRUB_NTFS_RF_BLNK) ? 0 : (block - + ctx->curr_vcn + ctx->curr_lcn); +} + +static grub_err_t +read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest, + grub_disk_addr_t ofs, grub_size_t len, int cached, + grub_disk_read_hook_t read_hook, void *read_hook_data) +{ + struct grub_ntfs_rlst cc, *ctx; + + if (len == 0) + return 0; + + grub_memset (&cc, 0, sizeof (cc)); + ctx = &cc; + ctx->attr = at; + ctx->comp.log_spc = at->mft->data->log_spc; + ctx->comp.disk = at->mft->data->disk; + + if (read_hook == grub_file_progress_hook) + ctx->file = read_hook_data; + + if (pa[8] == 0) + { + if (ofs + len > u32at (pa, 0x10)) + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); + grub_memcpy (dest, pa + u32at (pa, 0x14) + ofs, len); + return 0; + } + + ctx->cur_run = pa + u16at (pa, 0x20); + + ctx->next_vcn = u32at (pa, 0x10); + ctx->curr_lcn = 0; + + if ((pa[0xC] & GRUB_NTFS_FLAG_COMPRESSED) + && !(at->flags & GRUB_NTFS_AF_GPOS)) + { + if (!cached) + return grub_error (GRUB_ERR_BAD_FS, "attribute can\'t be compressed"); + + return (grub_ntfscomp_func) ? grub_ntfscomp_func (dest, ofs, len, ctx) + : grub_error (GRUB_ERR_BAD_FS, N_("module `%s' isn't loaded"), + "ntfscomp"); + } + + ctx->target_vcn = ofs >> (GRUB_NTFS_BLK_SHR + ctx->comp.log_spc); + while (ctx->next_vcn <= ctx->target_vcn) + { + if (grub_ntfs_read_run_list (ctx)) + return grub_errno; + } + + if (at->flags & GRUB_NTFS_AF_GPOS) + { + grub_disk_addr_t st0, st1; + grub_uint64_t m; + + m = (ofs >> GRUB_NTFS_BLK_SHR) & ((1 << ctx->comp.log_spc) - 1); + + st0 = + ((ctx->target_vcn - ctx->curr_vcn + ctx->curr_lcn) << ctx->comp.log_spc) + m; + st1 = st0 + 1; + if (st1 == + (ctx->next_vcn - ctx->curr_vcn + ctx->curr_lcn) << ctx->comp.log_spc) + { + if (grub_ntfs_read_run_list (ctx)) + return grub_errno; + st1 = ctx->curr_lcn << ctx->comp.log_spc; + } + grub_set_unaligned32 (dest, grub_cpu_to_le32 (st0)); + grub_set_unaligned32 (dest + 4, grub_cpu_to_le32 (st1)); + return 0; + } + + grub_fshelp_read_file (ctx->comp.disk, (grub_fshelp_node_t) ctx, + read_hook, read_hook_data, ofs, len, + (char *) dest, + grub_ntfs_read_block, ofs + len, + ctx->comp.log_spc, 0); + return grub_errno; +} + +static grub_err_t +read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, grub_disk_addr_t ofs, + grub_size_t len, int cached, + grub_disk_read_hook_t read_hook, void *read_hook_data) +{ + grub_uint8_t *save_cur; + grub_uint8_t attr; + grub_uint8_t *pp; + grub_err_t ret; + + save_cur = at->attr_cur; + at->attr_nxt = at->attr_cur; + attr = *at->attr_nxt; + if (at->flags & GRUB_NTFS_AF_ALST) + { + grub_uint8_t *pa; + grub_disk_addr_t vcn; + + /* If compression is possible make sure that we include possible + compressed block size. */ + if (GRUB_NTFS_LOG_COM_SEC >= at->mft->data->log_spc) + vcn = ((ofs >> GRUB_NTFS_COM_LOG_LEN) + << (GRUB_NTFS_LOG_COM_SEC - at->mft->data->log_spc)) & ~0xFULL; + else + vcn = ofs >> (at->mft->data->log_spc + GRUB_NTFS_BLK_SHR); + pa = at->attr_nxt + u16at (at->attr_nxt, 4); + while (pa < at->attr_end) + { + if (*pa != attr) + break; + if (u32at (pa, 8) > vcn) + break; + at->attr_nxt = pa; + pa += u16at (pa, 4); + } + } + pp = find_attr (at, attr); + if (pp) + ret = read_data (at, pp, dest, ofs, len, cached, + read_hook, read_hook_data); + else + ret = + (grub_errno) ? grub_errno : grub_error (GRUB_ERR_BAD_FS, + "attribute not found"); + at->attr_cur = save_cur; + return ret; +} + +static grub_err_t +read_mft (struct grub_ntfs_data *data, grub_uint8_t *buf, grub_uint64_t mftno) +{ + if (read_attr + (&data->mmft.attr, buf, mftno * ((grub_disk_addr_t) data->mft_size << GRUB_NTFS_BLK_SHR), + data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0, 0)) + return grub_error (GRUB_ERR_BAD_FS, "read MFT 0x%llx fails", (unsigned long long) mftno); + return fixup (buf, data->mft_size, (const grub_uint8_t *) "FILE"); +} + +static grub_err_t +init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno) +{ + unsigned short flag; + + mft->inode_read = 1; + + mft->buf = grub_malloc (mft->data->mft_size << GRUB_NTFS_BLK_SHR); + if (mft->buf == NULL) + return grub_errno; + + if (read_mft (mft->data, mft->buf, mftno)) + return grub_errno; + + flag = u16at (mft->buf, 0x16); + if ((flag & 1) == 0) + return grub_error (GRUB_ERR_BAD_FS, "MFT 0x%llx is not in use", + (unsigned long long) mftno); + + if ((flag & 2) == 0) + { + grub_uint8_t *pa; + + pa = locate_attr (&mft->attr, mft, GRUB_NTFS_AT_DATA); + if (pa == NULL) + return grub_error (GRUB_ERR_BAD_FS, "no $DATA in MFT 0x%llx", + (unsigned long long) mftno); + + if (!pa[8]) + mft->size = u32at (pa, 0x10); + else + mft->size = u64at (pa, 0x30); + + if ((mft->attr.flags & GRUB_NTFS_AF_ALST) == 0) + mft->attr.attr_end = 0; /* Don't jump to attribute list */ + } + else + init_attr (&mft->attr, mft); + + return 0; +} + +static void +free_file (struct grub_ntfs_file *mft) +{ + free_attr (&mft->attr); + grub_free (mft->buf); +} + +static char * +get_utf8 (grub_uint8_t *in, grub_size_t len) +{ + grub_uint8_t *buf; + grub_uint16_t *tmp; + grub_size_t i; + + buf = grub_malloc (len * GRUB_MAX_UTF8_PER_UTF16 + 1); + tmp = grub_malloc (len * sizeof (tmp[0])); + if (!buf || !tmp) + { + grub_free (buf); + grub_free (tmp); + return NULL; + } + for (i = 0; i < len; i++) + tmp[i] = grub_le_to_cpu16 (grub_get_unaligned16 (in + 2 * i)); + *grub_utf16_to_utf8 (buf, tmp, len) = '\0'; + grub_free (tmp); + return (char *) buf; +} + +static int +list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) +{ + grub_uint8_t *np; + int ns; + + while (1) + { + grub_uint8_t namespace; + char *ustr; + + if (pos[0xC] & 2) /* end signature */ + break; + + np = pos + 0x50; + ns = *(np++); + namespace = *(np++); + + /* + * Ignore files in DOS namespace, as they will reappear as Win32 + * names. + */ + if ((ns) && (namespace != 2)) + { + enum grub_fshelp_filetype type; + struct grub_ntfs_file *fdiro; + grub_uint32_t attr; + + attr = u32at (pos, 0x48); + if (attr & GRUB_NTFS_ATTR_REPARSE) + type = GRUB_FSHELP_SYMLINK; + else if (attr & GRUB_NTFS_ATTR_DIRECTORY) + type = GRUB_FSHELP_DIR; + else + type = GRUB_FSHELP_REG; + + fdiro = grub_zalloc (sizeof (struct grub_ntfs_file)); + if (!fdiro) + return 0; + + fdiro->data = diro->data; + fdiro->ino = u64at (pos, 0) & 0xffffffffffffULL; + fdiro->mtime = u64at (pos, 0x20); + + ustr = get_utf8 (np, ns); + if (ustr == NULL) + { + grub_free (fdiro); + return 0; + } + if (namespace) + type |= GRUB_FSHELP_CASE_INSENSITIVE; + + if (hook (ustr, type, fdiro, hook_data)) + { + grub_free (ustr); + return 1; + } + + grub_free (ustr); + } + pos += u16at (pos, 8); + } + return 0; +} + +struct symlink_descriptor +{ + grub_uint32_t type; + grub_uint32_t total_len; + grub_uint16_t off1; + grub_uint16_t len1; + grub_uint16_t off2; + grub_uint16_t len2; +} GRUB_PACKED; + +static char * +grub_ntfs_read_symlink (grub_fshelp_node_t node) +{ + struct grub_ntfs_file *mft; + struct symlink_descriptor symdesc; + grub_err_t err; + grub_uint8_t *buf16; + char *buf, *end; + grub_size_t len; + grub_uint8_t *pa; + grub_size_t off; + + mft = (struct grub_ntfs_file *) node; + + mft->buf = grub_malloc (mft->data->mft_size << GRUB_NTFS_BLK_SHR); + if (mft->buf == NULL) + return NULL; + + if (read_mft (mft->data, mft->buf, mft->ino)) + return NULL; + + pa = locate_attr (&mft->attr, mft, GRUB_NTFS_AT_SYMLINK); + if (pa == NULL) + { + grub_error (GRUB_ERR_BAD_FS, "no $SYMLINK in MFT 0x%llx", + (unsigned long long) mft->ino); + return NULL; + } + + err = read_attr (&mft->attr, (grub_uint8_t *) &symdesc, 0, + sizeof (struct symlink_descriptor), 1, 0, 0); + if (err) + return NULL; + + switch (grub_cpu_to_le32 (symdesc.type)) + { + case 0xa000000c: + off = (sizeof (struct symlink_descriptor) + 4 + + grub_cpu_to_le32 (symdesc.off1)); + len = grub_cpu_to_le32 (symdesc.len1); + break; + case 0xa0000003: + off = (sizeof (struct symlink_descriptor) + + grub_cpu_to_le32 (symdesc.off1)); + len = grub_cpu_to_le32 (symdesc.len1); + break; + default: + grub_error (GRUB_ERR_BAD_FS, "symlink type invalid (%x)", + grub_cpu_to_le32 (symdesc.type)); + return NULL; + } + + buf16 = grub_malloc (len); + if (!buf16) + return NULL; + + err = read_attr (&mft->attr, buf16, off, len, 1, 0, 0); + if (err) + return NULL; + + buf = get_utf8 (buf16, len / 2); + if (!buf) + { + grub_free (buf16); + return NULL; + } + grub_free (buf16); + + for (end = buf; *end; end++) + if (*end == '\\') + *end = '/'; + + /* Split the sequence to avoid GCC thinking that this is a trigraph. */ + if (grub_memcmp (buf, "/?" "?/", 4) == 0 && buf[5] == ':' && buf[6] == '/' + && grub_isalpha (buf[4])) + { + grub_memmove (buf, buf + 6, end - buf + 1 - 6); + end -= 6; + } + return buf; +} + +static int +grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) +{ + grub_uint8_t *bitmap; + struct grub_ntfs_attr attr, *at; + grub_uint8_t *cur_pos, *indx, *bmp; + int ret = 0; + grub_size_t bitmap_len; + struct grub_ntfs_file *mft; + + mft = (struct grub_ntfs_file *) dir; + + if (!mft->inode_read) + { + if (init_file (mft, mft->ino)) + return 0; + } + + indx = NULL; + bmp = NULL; + + at = &attr; + init_attr (at, mft); + while (1) + { + cur_pos = find_attr (at, GRUB_NTFS_AT_INDEX_ROOT); + if (cur_pos == NULL) + { + grub_error (GRUB_ERR_BAD_FS, "no $INDEX_ROOT"); + goto done; + } + + /* Resident, Namelen=4, Offset=0x18, Flags=0x00, Name="$I30" */ + if ((u32at (cur_pos, 8) != 0x180400) || + (u32at (cur_pos, 0x18) != 0x490024) || + (u32at (cur_pos, 0x1C) != 0x300033)) + continue; + cur_pos += u16at (cur_pos, 0x14); + if (*cur_pos != 0x30) /* Not filename index */ + continue; + break; + } + + cur_pos += 0x10; /* Skip index root */ + ret = list_file (mft, cur_pos + u16at (cur_pos, 0), hook, hook_data); + if (ret) + goto done; + + bitmap = NULL; + bitmap_len = 0; + free_attr (at); + init_attr (at, mft); + while ((cur_pos = find_attr (at, GRUB_NTFS_AT_BITMAP)) != NULL) + { + int ofs; + + ofs = cur_pos[0xA]; + /* Namelen=4, Name="$I30" */ + if ((cur_pos[9] == 4) && + (u32at (cur_pos, ofs) == 0x490024) && + (u32at (cur_pos, ofs + 4) == 0x300033)) + { + int is_resident = (cur_pos[8] == 0); + + bitmap_len = ((is_resident) ? u32at (cur_pos, 0x10) : + u32at (cur_pos, 0x28)); + + bmp = grub_malloc (bitmap_len); + if (bmp == NULL) + goto done; + + if (is_resident) + { + grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14), + bitmap_len); + } + else + { + if (read_data (at, cur_pos, bmp, 0, bitmap_len, 0, 0, 0)) + { + grub_error (GRUB_ERR_BAD_FS, + "fails to read non-resident $BITMAP"); + goto done; + } + bitmap_len = u32at (cur_pos, 0x30); + } + + bitmap = bmp; + break; + } + } + + free_attr (at); + cur_pos = locate_attr (at, mft, GRUB_NTFS_AT_INDEX_ALLOCATION); + while (cur_pos != NULL) + { + /* Non-resident, Namelen=4, Offset=0x40, Flags=0, Name="$I30" */ + if ((u32at (cur_pos, 8) == 0x400401) && + (u32at (cur_pos, 0x40) == 0x490024) && + (u32at (cur_pos, 0x44) == 0x300033)) + break; + cur_pos = find_attr (at, GRUB_NTFS_AT_INDEX_ALLOCATION); + } + + if ((!cur_pos) && (bitmap)) + { + grub_error (GRUB_ERR_BAD_FS, "$BITMAP without $INDEX_ALLOCATION"); + goto done; + } + + if (bitmap) + { + grub_disk_addr_t i; + grub_uint8_t v; + + indx = grub_malloc (mft->data->idx_size << GRUB_NTFS_BLK_SHR); + if (indx == NULL) + goto done; + + v = 1; + for (i = 0; i < (grub_disk_addr_t)bitmap_len * 8; i++) + { + if (*bitmap & v) + { + if ((read_attr + (at, indx, i * (mft->data->idx_size << GRUB_NTFS_BLK_SHR), + (mft->data->idx_size << GRUB_NTFS_BLK_SHR), 0, 0, 0)) + || (fixup (indx, mft->data->idx_size, + (const grub_uint8_t *) "INDX"))) + goto done; + ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)], + hook, hook_data); + if (ret) + goto done; + } + v <<= 1; + if (!v) + { + v = 1; + bitmap++; + } + } + } + +done: + free_attr (at); + grub_free (indx); + grub_free (bmp); + + return ret; +} + +static struct grub_ntfs_data * +grub_ntfs_mount (grub_disk_t disk) +{ + struct grub_ntfs_bpb bpb; + struct grub_ntfs_data *data = 0; + grub_uint32_t spc; + grub_uint32_t sectors_per_cluster; + + if (!disk) + goto fail; + + data = (struct grub_ntfs_data *) grub_zalloc (sizeof (*data)); + if (!data) + goto fail; + + data->disk = disk; + + /* Read the BPB. */ + if (grub_disk_read (disk, 0, 0, sizeof (bpb), &bpb)) + goto fail; + + sectors_per_cluster = bpb.sectors_per_cluster; + if (sectors_per_cluster > 0x80) + sectors_per_cluster = 1U << (256U - bpb.sectors_per_cluster); + + if (grub_memcmp ((char *) &bpb.oem_name, "NTFS", 4) != 0 + || sectors_per_cluster == 0 + || (sectors_per_cluster & (sectors_per_cluster - 1)) != 0 + || bpb.bytes_per_sector == 0 + || (bpb.bytes_per_sector & (bpb.bytes_per_sector - 1)) != 0) + goto fail; + + spc = (((grub_uint32_t) sectors_per_cluster + * (grub_uint32_t) grub_le_to_cpu16 (bpb.bytes_per_sector)) + >> GRUB_NTFS_BLK_SHR); + if (spc == 0) + goto fail; + + for (data->log_spc = 0; (1U << data->log_spc) < spc; data->log_spc++); + + if (bpb.clusters_per_mft > 0) + data->mft_size = ((grub_disk_addr_t) bpb.clusters_per_mft) << data->log_spc; + else if (-bpb.clusters_per_mft < GRUB_NTFS_BLK_SHR || -bpb.clusters_per_mft >= 31) + goto fail; + else + data->mft_size = 1ULL << (-bpb.clusters_per_mft - GRUB_NTFS_BLK_SHR); + + if (bpb.clusters_per_index > 0) + data->idx_size = (((grub_disk_addr_t) bpb.clusters_per_index) + << data->log_spc); + else if (-bpb.clusters_per_index < GRUB_NTFS_BLK_SHR || -bpb.clusters_per_index >= 31) + goto fail; + else + data->idx_size = 1ULL << (-bpb.clusters_per_index - GRUB_NTFS_BLK_SHR); + + data->mft_start = grub_le_to_cpu64 (bpb.mft_lcn) << data->log_spc; + + if ((data->mft_size > GRUB_NTFS_MAX_MFT) || (data->idx_size > GRUB_NTFS_MAX_IDX)) + goto fail; + + data->mmft.data = data; + data->cmft.data = data; + + data->mmft.buf = grub_malloc (data->mft_size << GRUB_NTFS_BLK_SHR); + if (!data->mmft.buf) + goto fail; + + if (grub_disk_read + (disk, data->mft_start, 0, data->mft_size << GRUB_NTFS_BLK_SHR, data->mmft.buf)) + goto fail; + + data->uuid = grub_le_to_cpu64 (bpb.num_serial); + + if (fixup (data->mmft.buf, data->mft_size, (const grub_uint8_t *) "FILE")) + goto fail; + + if (!locate_attr (&data->mmft.attr, &data->mmft, GRUB_NTFS_AT_DATA)) + goto fail; + + if (init_file (&data->cmft, GRUB_NTFS_FILE_ROOT)) + goto fail; + + return data; + +fail: + grub_error (GRUB_ERR_BAD_FS, "not an ntfs filesystem"); + + if (data) + { + free_file (&data->mmft); + free_file (&data->cmft); + grub_free (data); + } + return 0; +} + +/* Context for grub_ntfs_dir. */ +struct grub_ntfs_dir_ctx +{ + grub_fs_dir_hook_t hook; + void *hook_data; +}; + +/* Helper for grub_ntfs_dir. */ +static int +grub_ntfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node, void *data) +{ + struct grub_ntfs_dir_ctx *ctx = data; + struct grub_dirhook_info info; + + grub_memset (&info, 0, sizeof (info)); + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = 1; + info.mtime = grub_divmod64 (node->mtime, 10000000, 0) + - 86400ULL * 365 * (1970 - 1601) + - 86400ULL * ((1970 - 1601) / 4) + 86400ULL * ((1970 - 1601) / 100); + if (!info.dir) + info.size = node->size; + grub_free (node); + return ctx->hook (filename, &info, ctx->hook_data); +} + +static grub_err_t +grub_ntfs_dir (grub_device_t device, const char *path, + grub_fs_dir_hook_t hook, void *hook_data) +{ + struct grub_ntfs_dir_ctx ctx = { hook, hook_data }; + struct grub_ntfs_data *data = 0; + struct grub_fshelp_node *fdiro = 0; + + grub_dl_ref (my_mod); + + data = grub_ntfs_mount (device->disk); + if (!data) + goto fail; + + grub_fshelp_find_file (path, &data->cmft, &fdiro, grub_ntfs_iterate_dir, + grub_ntfs_read_symlink, GRUB_FSHELP_DIR); + + if (grub_errno) + goto fail; + + grub_ntfs_iterate_dir (fdiro, grub_ntfs_dir_iter, &ctx); + +fail: + if ((fdiro) && (fdiro != &data->cmft)) + { + free_file (fdiro); + grub_free (fdiro); + } + if (data) + { + free_file (&data->mmft); + free_file (&data->cmft); + grub_free (data); + } + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_err_t +grub_ntfs_open (grub_file_t file, const char *name) +{ + struct grub_ntfs_data *data = 0; + struct grub_fshelp_node *mft = 0; + + grub_dl_ref (my_mod); + + data = grub_ntfs_mount (file->device->disk); + if (!data) + goto fail; + + grub_fshelp_find_file (name, &data->cmft, &mft, grub_ntfs_iterate_dir, + grub_ntfs_read_symlink, GRUB_FSHELP_REG); + + if (grub_errno) + goto fail; + + if (mft != &data->cmft) + { + free_file (&data->cmft); + grub_memcpy (&data->cmft, mft, sizeof (*mft)); + grub_free (mft); + if (!data->cmft.inode_read) + { + if (init_file (&data->cmft, data->cmft.ino)) + goto fail; + } + } + + file->size = data->cmft.size; + file->data = data; + file->offset = 0; + + return 0; + +fail: + if (data) + { + free_file (&data->mmft); + free_file (&data->cmft); + grub_free (data); + } + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_ssize_t +grub_ntfs_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_ntfs_file *mft; + + mft = &((struct grub_ntfs_data *) file->data)->cmft; + if (file->read_hook) + mft->attr.save_pos = 1; + + read_attr (&mft->attr, (grub_uint8_t *) buf, file->offset, len, 1, + file->read_hook, file->read_hook_data); + return (grub_errno) ? -1 : (grub_ssize_t) len; +} + +static grub_err_t +grub_ntfs_close (grub_file_t file) +{ + struct grub_ntfs_data *data; + + data = file->data; + + if (data) + { + free_file (&data->mmft); + free_file (&data->cmft); + grub_free (data); + } + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_err_t +grub_ntfs_label (grub_device_t device, char **label) +{ + struct grub_ntfs_data *data = 0; + struct grub_fshelp_node *mft = 0; + grub_uint8_t *pa; + + grub_dl_ref (my_mod); + + *label = 0; + + data = grub_ntfs_mount (device->disk); + if (!data) + goto fail; + + grub_fshelp_find_file ("/$Volume", &data->cmft, &mft, grub_ntfs_iterate_dir, + 0, GRUB_FSHELP_REG); + + if (grub_errno) + goto fail; + + if (!mft->inode_read) + { + mft->buf = grub_malloc (mft->data->mft_size << GRUB_NTFS_BLK_SHR); + if (mft->buf == NULL) + goto fail; + + if (read_mft (mft->data, mft->buf, mft->ino)) + goto fail; + } + + init_attr (&mft->attr, mft); + pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME); + if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) + { + int len; + + len = u32at (pa, 0x10) / 2; + pa += u16at (pa, 0x14); + *label = get_utf8 (pa, len); + } + +fail: + if ((mft) && (mft != &data->cmft)) + { + free_file (mft); + grub_free (mft); + } + if (data) + { + free_file (&data->mmft); + free_file (&data->cmft); + grub_free (data); + } + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_err_t +grub_ntfs_uuid (grub_device_t device, char **uuid) +{ + struct grub_ntfs_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_ntfs_mount (disk); + if (data) + { + char *ptr; + *uuid = grub_xasprintf ("%016llx", (unsigned long long) data->uuid); + if (*uuid) + for (ptr = *uuid; *ptr; ptr++) + *ptr = grub_toupper (*ptr); + free_file (&data->mmft); + free_file (&data->cmft); + grub_free (data); + } + else + *uuid = NULL; + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static struct grub_fs grub_ntfs_fs = + { + .name = "ntfs", + .fs_dir = grub_ntfs_dir, + .fs_open = grub_ntfs_open, + .fs_read = grub_ntfs_read, + .fs_close = grub_ntfs_close, + .fs_label = grub_ntfs_label, + .fs_uuid = grub_ntfs_uuid, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif + .next = 0 +}; + +GRUB_MOD_INIT (ntfs) +{ + grub_fs_register (&grub_ntfs_fs); + my_mod = mod; +} + +GRUB_MOD_FINI (ntfs) +{ + grub_fs_unregister (&grub_ntfs_fs); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/squash4.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/squash4.c new file mode 100644 index 0000000..54dcf0c --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/squash4.c @@ -0,0 +1,1067 @@ +/* squash4.c - SquashFS */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xz.h" +#include "xz_stream.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +/* + object format Pointed by + superblock RAW Fixed offset (0) + data RAW ? Fixed offset (60) + inode table Chunk superblock + dir table Chunk superblock + fragment table Chunk unk1 + unk1 RAW, Chunk superblock + unk2 RAW superblock + UID/GID Chunk exttblptr + exttblptr RAW superblock + + UID/GID table is the array ot uint32_t + unk1 contains pointer to fragment table followed by some chunk. + unk2 containts one uint64_t +*/ + +struct grub_squash_super +{ + grub_uint32_t magic; +#define SQUASH_MAGIC 0x73717368 + grub_uint32_t dummy1; + grub_uint32_t creation_time; + grub_uint32_t block_size; + grub_uint32_t dummy2; + grub_uint16_t compression; + grub_uint16_t dummy3; + grub_uint64_t dummy4; + grub_uint16_t root_ino_offset; + grub_uint32_t root_ino_chunk; + grub_uint16_t dummy5; + grub_uint64_t total_size; + grub_uint64_t exttbloffset; + grub_uint64_t dummy6; + grub_uint64_t inodeoffset; + grub_uint64_t diroffset; + grub_uint64_t unk1offset; + grub_uint64_t unk2offset; +} GRUB_PACKED; + +/* Chunk-based */ +struct grub_squash_inode +{ + /* Same values as direlem types. */ + grub_uint16_t type; + grub_uint16_t dummy[3]; + grub_uint32_t mtime; + grub_uint32_t dummy2; + union + { + struct { + grub_uint32_t chunk; + grub_uint32_t fragment; + grub_uint32_t offset; + grub_uint32_t size; + grub_uint32_t block_size[0]; + } GRUB_PACKED file; + struct { + grub_uint64_t chunk; + grub_uint64_t size; + grub_uint32_t dummy1[3]; + grub_uint32_t fragment; + grub_uint32_t offset; + grub_uint32_t dummy3; + grub_uint32_t block_size[0]; + } GRUB_PACKED long_file; + struct { + grub_uint32_t chunk; + grub_uint32_t dummy; + grub_uint16_t size; + grub_uint16_t offset; + } GRUB_PACKED dir; + struct { + grub_uint32_t dummy1; + grub_uint32_t size; + grub_uint32_t chunk; + grub_uint32_t dummy2; + grub_uint16_t dummy3; + grub_uint16_t offset; + } GRUB_PACKED long_dir; + struct { + grub_uint32_t dummy; + grub_uint32_t namelen; + char name[0]; + } GRUB_PACKED symlink; + } GRUB_PACKED; +} GRUB_PACKED; + +struct grub_squash_cache_inode +{ + struct grub_squash_inode ino; + grub_disk_addr_t ino_chunk; + grub_uint16_t ino_offset; + grub_uint32_t *block_sizes; + grub_disk_addr_t *cumulated_block_sizes; +}; + +/* Chunk-based. */ +struct grub_squash_dirent_header +{ + /* Actually the value is the number of elements - 1. */ + grub_uint32_t nelems; + grub_uint32_t ino_chunk; + grub_uint32_t dummy; +} GRUB_PACKED; + +struct grub_squash_dirent +{ + grub_uint16_t ino_offset; + grub_uint16_t dummy; + grub_uint16_t type; + /* Actually the value is the length of name - 1. */ + grub_uint16_t namelen; + char name[0]; +} GRUB_PACKED; + +enum + { + SQUASH_TYPE_DIR = 1, + SQUASH_TYPE_REGULAR = 2, + SQUASH_TYPE_SYMLINK = 3, + SQUASH_TYPE_LONG_DIR = 8, + SQUASH_TYPE_LONG_REGULAR = 9, + }; + + +struct grub_squash_frag_desc +{ + grub_uint64_t offset; + grub_uint32_t size; + grub_uint32_t dummy; +} GRUB_PACKED; + +enum + { + SQUASH_CHUNK_FLAGS = 0x8000, + SQUASH_CHUNK_UNCOMPRESSED = 0x8000 + }; + +enum + { + SQUASH_BLOCK_FLAGS = 0x1000000, + SQUASH_BLOCK_UNCOMPRESSED = 0x1000000 + }; + +enum + { + COMPRESSION_ZLIB = 1, + COMPRESSION_LZO = 3, + COMPRESSION_XZ = 4, + COMPRESSION_LZ4 = 5, + COMPRESSION_ZSTD = 6, + }; + + +#define SQUASH_CHUNK_SIZE 0x2000 +#define XZBUFSIZ 0x2000 + +struct grub_squash_data +{ + grub_disk_t disk; + struct grub_squash_super sb; + struct grub_squash_cache_inode ino; + grub_uint64_t fragments; + int log2_blksz; + grub_size_t blksz; + grub_ssize_t (*decompress) (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t outsize, + struct grub_squash_data *data); + struct xz_dec *xzdec; + char *xzbuf; +}; + +struct grub_fshelp_node +{ + struct grub_squash_data *data; + struct grub_squash_inode ino; + grub_size_t stsize; + struct + { + grub_disk_addr_t ino_chunk; + grub_uint16_t ino_offset; + } stack[1]; +}; + +static grub_err_t +read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len, + grub_uint64_t chunk_start, grub_off_t offset) +{ + while (len > 0) + { + grub_uint64_t csize; + grub_uint16_t d; + grub_err_t err; + while (1) + { + err = grub_disk_read (data->disk, + chunk_start >> GRUB_DISK_SECTOR_BITS, + chunk_start & (GRUB_DISK_SECTOR_SIZE - 1), + sizeof (d), &d); + if (err) + return err; + if (offset < SQUASH_CHUNK_SIZE) + break; + offset -= SQUASH_CHUNK_SIZE; + chunk_start += 2 + (grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS); + } + + csize = SQUASH_CHUNK_SIZE - offset; + if (csize > len) + csize = len; + + if (grub_le_to_cpu16 (d) & SQUASH_CHUNK_UNCOMPRESSED) + { + grub_disk_addr_t a = chunk_start + 2 + offset; + err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS), + a & (GRUB_DISK_SECTOR_SIZE - 1), + csize, buf); + if (err) + return err; + } + else + { + char *tmp; + grub_size_t bsize = grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS; + grub_disk_addr_t a = chunk_start + 2; + tmp = grub_malloc (bsize); + if (!tmp) + return grub_errno; + /* FIXME: buffer uncompressed data. */ + err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS), + a & (GRUB_DISK_SECTOR_SIZE - 1), + bsize, tmp); + if (err) + { + grub_free (tmp); + return err; + } + + if (data->decompress (tmp, bsize, offset, + buf, csize, data) < 0) + { + grub_free (tmp); + return grub_errno; + } + grub_free (tmp); + } + len -= csize; + offset += csize; + buf = (char *) buf + csize; + } + return GRUB_ERR_NONE; +} + +static grub_ssize_t +zlib_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t outsize, + struct grub_squash_data *data __attribute__ ((unused))) +{ + return grub_zlib_decompress (inbuf, insize, off, outbuf, outsize); +} + +static grub_ssize_t +lzo_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t len, struct grub_squash_data *data) +{ + lzo_uint usize = data->blksz; + grub_uint8_t *udata; + + if (usize < 8192) + usize = 8192; + + udata = grub_malloc (usize); + if (!udata) + return -1; + + if (lzo1x_decompress_safe ((grub_uint8_t *) inbuf, + insize, udata, &usize, NULL) != LZO_E_OK) + { + grub_error (GRUB_ERR_BAD_FS, "incorrect compressed chunk"); + grub_free (udata); + return -1; + } + grub_memcpy (outbuf, udata + off, len); + grub_free (udata); + return len; +} + +static grub_ssize_t +xz_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t len, struct grub_squash_data *data) +{ + grub_size_t ret = 0; + grub_off_t pos = 0; + struct xz_buf buf; + + xz_dec_reset (data->xzdec); + buf.in = (grub_uint8_t *) inbuf; + buf.in_pos = 0; + buf.in_size = insize; + buf.out = (grub_uint8_t *) data->xzbuf; + buf.out_pos = 0; + buf.out_size = XZBUFSIZ; + + while (len) + { + enum xz_ret xzret; + + buf.out_pos = 0; + + xzret = xz_dec_run (data->xzdec, &buf); + + if (xzret != XZ_OK && xzret != XZ_STREAM_END) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "invalid xz chunk"); + return -1; + } + if (pos + buf.out_pos >= off) + { + grub_ssize_t outoff = pos - off; + grub_size_t l; + if (outoff >= 0) + { + l = buf.out_pos; + if (l > len) + l = len; + grub_memcpy (outbuf + outoff, buf.out, l); + } + else + { + outoff = -outoff; + l = buf.out_pos - outoff; + if (l > len) + l = len; + grub_memcpy (outbuf, buf.out + outoff, l); + } + ret += l; + len -= l; + } + pos += buf.out_pos; + if (xzret == XZ_STREAM_END) + break; + } + return ret; +} + +int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int maxOutputSize); +static grub_ssize_t lz4_decompress_wrap(char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t len, struct grub_squash_data *data) +{ + char *udata = NULL; + int usize = data->blksz; + + if (usize < 8192) + usize = 8192; + + udata = grub_malloc (usize); + if (!udata) + return -1; + + LZ4_uncompress_unknownOutputSize(inbuf, udata, insize, usize); + grub_memcpy (outbuf, udata + off, len); + grub_free (udata); + return len; +} + +static grub_ssize_t zstd_decompress_wrap(char *inbuf, grub_size_t insize, grub_off_t off, + char *outbuf, grub_size_t len, struct grub_squash_data *data) +{ + char *udata = NULL; + int usize = data->blksz; + if (usize < 8192) + usize = 8192; + + udata = grub_malloc (usize); + if (!udata) + return -1; + + ZSTD_decompress(udata, usize, inbuf, insize); + grub_memcpy(outbuf, udata + off, len); + grub_free(udata); + + return len; +} + +static struct grub_squash_data * +squash_mount (grub_disk_t disk) +{ + struct grub_squash_super sb; + grub_err_t err; + struct grub_squash_data *data; + grub_uint64_t frag; + + err = grub_disk_read (disk, 0, 0, sizeof (sb), &sb); + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_error (GRUB_ERR_BAD_FS, "not a squash4"); + if (err) + return NULL; + if (sb.magic != grub_cpu_to_le32_compile_time (SQUASH_MAGIC) + || sb.block_size == 0 + || ((sb.block_size - 1) & sb.block_size)) + { + grub_error (GRUB_ERR_BAD_FS, "not squash4"); + return NULL; + } + + err = grub_disk_read (disk, + grub_le_to_cpu64 (sb.unk1offset) + >> GRUB_DISK_SECTOR_BITS, + grub_le_to_cpu64 (sb.unk1offset) + & (GRUB_DISK_SECTOR_SIZE - 1), sizeof (frag), &frag); + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_error (GRUB_ERR_BAD_FS, "not a squash4"); + if (err) + return NULL; + + data = grub_zalloc (sizeof (*data)); + if (!data) + return NULL; + data->sb = sb; + data->disk = disk; + data->fragments = grub_le_to_cpu64 (frag); + + switch (sb.compression) + { + case grub_cpu_to_le16_compile_time (COMPRESSION_ZLIB): + data->decompress = zlib_decompress; + break; + case grub_cpu_to_le16_compile_time (COMPRESSION_LZO): + data->decompress = lzo_decompress; + break; + case grub_cpu_to_le16_compile_time (COMPRESSION_LZ4): + data->decompress = lz4_decompress_wrap; + break; + case grub_cpu_to_le16_compile_time (COMPRESSION_ZSTD): + data->decompress = zstd_decompress_wrap; + break; + case grub_cpu_to_le16_compile_time (COMPRESSION_XZ): + data->decompress = xz_decompress; + data->xzbuf = grub_malloc (XZBUFSIZ); + if (!data->xzbuf) + { + grub_free (data); + return NULL; + } + data->xzdec = xz_dec_init (1 << 16); + if (!data->xzdec) + { + grub_free (data->xzbuf); + grub_free (data); + return NULL; + } + break; + default: + grub_free (data); + grub_error (GRUB_ERR_BAD_FS, "unsupported compression %d", + grub_le_to_cpu16 (sb.compression)); + return NULL; + } + + data->blksz = grub_le_to_cpu32 (data->sb.block_size); + for (data->log2_blksz = 0; + (1U << data->log2_blksz) < data->blksz; + data->log2_blksz++); + + return data; +} + +static char * +grub_squash_read_symlink (grub_fshelp_node_t node) +{ + char *ret; + grub_err_t err; + ret = grub_malloc (grub_le_to_cpu32 (node->ino.symlink.namelen) + 1); + + err = read_chunk (node->data, ret, + grub_le_to_cpu32 (node->ino.symlink.namelen), + grub_le_to_cpu64 (node->data->sb.inodeoffset) + + node->stack[node->stsize - 1].ino_chunk, + node->stack[node->stsize - 1].ino_offset + + (node->ino.symlink.name - (char *) &node->ino)); + if (err) + { + grub_free (ret); + return NULL; + } + ret[grub_le_to_cpu32 (node->ino.symlink.namelen)] = 0; + return ret; +} + +static int +grub_squash_iterate_dir (grub_fshelp_node_t dir, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) +{ + grub_uint32_t off; + grub_uint32_t endoff; + grub_uint64_t chunk; + unsigned i; + + /* FIXME: why - 3 ? */ + switch (dir->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_DIR): + off = grub_le_to_cpu16 (dir->ino.dir.offset); + endoff = grub_le_to_cpu16 (dir->ino.dir.size) + off - 3; + chunk = grub_le_to_cpu32 (dir->ino.dir.chunk); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_DIR): + off = grub_le_to_cpu16 (dir->ino.long_dir.offset); + endoff = grub_le_to_cpu32 (dir->ino.long_dir.size) + off - 3; + chunk = grub_le_to_cpu32 (dir->ino.long_dir.chunk); + break; + default: + grub_error (GRUB_ERR_BAD_FS, "unexpected ino type 0x%x", + grub_le_to_cpu16 (dir->ino.type)); + return 0; + } + + { + grub_fshelp_node_t node; + node = grub_malloc (sizeof (*node) + dir->stsize * sizeof (dir->stack[0])); + if (!node) + return 0; + grub_memcpy (node, dir, + sizeof (*node) + dir->stsize * sizeof (dir->stack[0])); + if (hook (".", GRUB_FSHELP_DIR, node, hook_data)) + return 1; + + if (dir->stsize != 1) + { + grub_err_t err; + + node = grub_malloc (sizeof (*node) + dir->stsize * sizeof (dir->stack[0])); + if (!node) + return 0; + + grub_memcpy (node, dir, + sizeof (*node) + dir->stsize * sizeof (dir->stack[0])); + + node->stsize--; + err = read_chunk (dir->data, &node->ino, sizeof (node->ino), + grub_le_to_cpu64 (dir->data->sb.inodeoffset) + + node->stack[node->stsize - 1].ino_chunk, + node->stack[node->stsize - 1].ino_offset); + if (err) + return 0; + + if (hook ("..", GRUB_FSHELP_DIR, node, hook_data)) + return 1; + } + } + + while (off < endoff) + { + struct grub_squash_dirent_header dh; + grub_err_t err; + + err = read_chunk (dir->data, &dh, sizeof (dh), + grub_le_to_cpu64 (dir->data->sb.diroffset) + + chunk, off); + if (err) + return 0; + off += sizeof (dh); + for (i = 0; i < (unsigned) grub_le_to_cpu32 (dh.nelems) + 1; i++) + { + char *buf; + int r; + struct grub_fshelp_node *node; + enum grub_fshelp_filetype filetype = GRUB_FSHELP_REG; + struct grub_squash_dirent di; + struct grub_squash_inode ino; + + err = read_chunk (dir->data, &di, sizeof (di), + grub_le_to_cpu64 (dir->data->sb.diroffset) + + chunk, off); + if (err) + return 0; + off += sizeof (di); + + err = read_chunk (dir->data, &ino, sizeof (ino), + grub_le_to_cpu64 (dir->data->sb.inodeoffset) + + grub_le_to_cpu32 (dh.ino_chunk), + grub_cpu_to_le16 (di.ino_offset)); + if (err) + return 0; + + buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2); + if (!buf) + return 0; + err = read_chunk (dir->data, buf, + grub_le_to_cpu16 (di.namelen) + 1, + grub_le_to_cpu64 (dir->data->sb.diroffset) + + chunk, off); + if (err) + return 0; + + off += grub_le_to_cpu16 (di.namelen) + 1; + buf[grub_le_to_cpu16 (di.namelen) + 1] = 0; + if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_DIR) + filetype = GRUB_FSHELP_DIR; + if (grub_le_to_cpu16 (di.type) == SQUASH_TYPE_SYMLINK) + filetype = GRUB_FSHELP_SYMLINK; + + node = grub_malloc (sizeof (*node) + + (dir->stsize + 1) * sizeof (dir->stack[0])); + if (! node) + return 0; + + grub_memcpy (node, dir, + sizeof (*node) + dir->stsize * sizeof (dir->stack[0])); + + node->ino = ino; + node->stack[node->stsize].ino_chunk = grub_le_to_cpu32 (dh.ino_chunk); + node->stack[node->stsize].ino_offset = grub_le_to_cpu16 (di.ino_offset); + node->stsize++; + r = hook (buf, filetype, node, hook_data); + + grub_free (buf); + if (r) + return r; + } + } + return 0; +} + +static grub_err_t +make_root_node (struct grub_squash_data *data, struct grub_fshelp_node *root) +{ + grub_memset (root, 0, sizeof (*root)); + root->data = data; + root->stsize = 1; + root->stack[0].ino_chunk = grub_le_to_cpu32 (data->sb.root_ino_chunk); + root->stack[0].ino_offset = grub_cpu_to_le16 (data->sb.root_ino_offset); + return read_chunk (data, &root->ino, sizeof (root->ino), + grub_le_to_cpu64 (data->sb.inodeoffset) + + root->stack[0].ino_chunk, + root->stack[0].ino_offset); +} + +static void +squash_unmount (struct grub_squash_data *data) +{ + if (data->xzdec) + xz_dec_end (data->xzdec); + grub_free (data->xzbuf); + grub_free (data->ino.cumulated_block_sizes); + grub_free (data->ino.block_sizes); + grub_free (data); +} + + +/* Context for grub_squash_dir. */ +struct grub_squash_dir_ctx +{ + grub_fs_dir_hook_t hook; + void *hook_data; +}; + +/* Helper for grub_squash_dir. */ +static int +grub_squash_dir_iter (const char *filename, enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node, void *data) +{ + struct grub_squash_dir_ctx *ctx = data; + struct grub_dirhook_info info; + + grub_memset (&info, 0, sizeof (info)); + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = 1; + info.mtime = grub_le_to_cpu32 (node->ino.mtime); + grub_free (node); + return ctx->hook (filename, &info, ctx->hook_data); +} + +static grub_err_t +grub_squash_dir (grub_device_t device, const char *path, + grub_fs_dir_hook_t hook, void *hook_data) +{ + struct grub_squash_dir_ctx ctx = { hook, hook_data }; + struct grub_squash_data *data = 0; + struct grub_fshelp_node *fdiro = 0; + struct grub_fshelp_node root; + grub_err_t err; + + data = squash_mount (device->disk); + if (! data) + return grub_errno; + + err = make_root_node (data, &root); + if (err) + return err; + + grub_fshelp_find_file (path, &root, &fdiro, grub_squash_iterate_dir, + grub_squash_read_symlink, GRUB_FSHELP_DIR); + if (!grub_errno) + grub_squash_iterate_dir (fdiro, grub_squash_dir_iter, &ctx); + + squash_unmount (data); + + return grub_errno; +} + +static grub_err_t +grub_squash_open (struct grub_file *file, const char *name) +{ + struct grub_squash_data *data = 0; + struct grub_fshelp_node *fdiro = 0; + struct grub_fshelp_node root; + grub_err_t err; + + data = squash_mount (file->device->disk); + if (! data) + return grub_errno; + + err = make_root_node (data, &root); + if (err) + return err; + + grub_fshelp_find_file (name, &root, &fdiro, grub_squash_iterate_dir, + grub_squash_read_symlink, GRUB_FSHELP_REG); + if (grub_errno) + { + squash_unmount (data); + return grub_errno; + } + + file->data = data; + data->ino.ino = fdiro->ino; + data->ino.block_sizes = NULL; + data->ino.cumulated_block_sizes = NULL; + data->ino.ino_chunk = fdiro->stack[fdiro->stsize - 1].ino_chunk; + data->ino.ino_offset = fdiro->stack[fdiro->stsize - 1].ino_offset; + + switch (fdiro->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR): + file->size = grub_le_to_cpu64 (fdiro->ino.long_file.size); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR): + file->size = grub_le_to_cpu32 (fdiro->ino.file.size); + break; + default: + { + grub_uint16_t type = grub_le_to_cpu16 (fdiro->ino.type); + grub_free (fdiro); + squash_unmount (data); + return grub_error (GRUB_ERR_BAD_FS, "unexpected ino type 0x%x", type); + } + } + + grub_free (fdiro); + + return GRUB_ERR_NONE; +} + +static grub_ssize_t +direct_read (struct grub_squash_data *data, + struct grub_squash_cache_inode *ino, + grub_off_t off, char *buf, grub_size_t len) +{ + grub_err_t err; + grub_off_t cumulated_uncompressed_size = 0; + grub_uint64_t a = 0; + grub_size_t i; + grub_size_t origlen = len; + + switch (ino->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR): + a = grub_le_to_cpu64 (ino->ino.long_file.chunk); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR): + a = grub_le_to_cpu32 (ino->ino.file.chunk); + break; + } + + if (!ino->block_sizes) + { + grub_off_t total_size = 0; + grub_size_t total_blocks; + grub_size_t block_offset = 0; + switch (ino->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR): + total_size = grub_le_to_cpu64 (ino->ino.long_file.size); + block_offset = ((char *) &ino->ino.long_file.block_size + - (char *) &ino->ino); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR): + total_size = grub_le_to_cpu32 (ino->ino.file.size); + block_offset = ((char *) &ino->ino.file.block_size + - (char *) &ino->ino); + break; + } + total_blocks = ((total_size + data->blksz - 1) >> data->log2_blksz); + ino->block_sizes = grub_malloc (total_blocks + * sizeof (ino->block_sizes[0])); + ino->cumulated_block_sizes = grub_malloc (total_blocks + * sizeof (ino->cumulated_block_sizes[0])); + if (!ino->block_sizes || !ino->cumulated_block_sizes) + { + grub_free (ino->block_sizes); + grub_free (ino->cumulated_block_sizes); + ino->block_sizes = 0; + ino->cumulated_block_sizes = 0; + return -1; + } + err = read_chunk (data, ino->block_sizes, + total_blocks * sizeof (ino->block_sizes[0]), + grub_le_to_cpu64 (data->sb.inodeoffset) + + ino->ino_chunk, + ino->ino_offset + block_offset); + if (err) + { + grub_free (ino->block_sizes); + grub_free (ino->cumulated_block_sizes); + ino->block_sizes = 0; + ino->cumulated_block_sizes = 0; + return -1; + } + ino->cumulated_block_sizes[0] = 0; + for (i = 1; i < total_blocks; i++) + ino->cumulated_block_sizes[i] = ino->cumulated_block_sizes[i - 1] + + (grub_le_to_cpu32 (ino->block_sizes[i - 1]) & ~SQUASH_BLOCK_FLAGS); + } + + if (a == 0) + a = sizeof (struct grub_squash_super); + i = off >> data->log2_blksz; + cumulated_uncompressed_size = data->blksz * (grub_disk_addr_t) i; + while (cumulated_uncompressed_size < off + len) + { + grub_size_t boff, curread; + boff = off - cumulated_uncompressed_size; + curread = data->blksz - boff; + if (curread > len) + curread = len; + if (!ino->block_sizes[i]) + { + /* Sparse block */ + grub_memset (buf, '\0', curread); + } + else if (!(ino->block_sizes[i] + & grub_cpu_to_le32_compile_time (SQUASH_BLOCK_UNCOMPRESSED))) + { + char *block; + grub_size_t csize; + csize = grub_le_to_cpu32 (ino->block_sizes[i]) & ~SQUASH_BLOCK_FLAGS; + block = grub_malloc (csize); + if (!block) + return -1; + err = grub_disk_read (data->disk, + (ino->cumulated_block_sizes[i] + a) + >> GRUB_DISK_SECTOR_BITS, + (ino->cumulated_block_sizes[i] + a) + & (GRUB_DISK_SECTOR_SIZE - 1), + csize, block); + if (err) + { + grub_free (block); + return -1; + } + if (data->decompress (block, csize, boff, buf, curread, data) + != (grub_ssize_t) curread) + { + grub_free (block); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_FS, "incorrect compressed chunk"); + return -1; + } + grub_free (block); + } + else + err = grub_disk_read (data->disk, + (ino->cumulated_block_sizes[i] + a + boff) + >> GRUB_DISK_SECTOR_BITS, + (ino->cumulated_block_sizes[i] + a + boff) + & (GRUB_DISK_SECTOR_SIZE - 1), + curread, buf); + if (err) + return -1; + off += curread; + len -= curread; + buf += curread; + cumulated_uncompressed_size += grub_le_to_cpu32 (data->sb.block_size); + i++; + } + return origlen; +} + + +static grub_ssize_t +grub_squash_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_squash_data *data = file->data; + struct grub_squash_cache_inode *ino = &data->ino; + grub_off_t off = file->offset; + grub_err_t err; + grub_uint64_t a, b; + grub_uint32_t fragment = 0; + int compressed = 0; + struct grub_squash_frag_desc frag; + grub_off_t direct_len; + grub_uint64_t mask = grub_le_to_cpu32 (data->sb.block_size) - 1; + grub_size_t orig_len = len; + + switch (ino->ino.type) + { + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR): + fragment = grub_le_to_cpu32 (ino->ino.long_file.fragment); + break; + case grub_cpu_to_le16_compile_time (SQUASH_TYPE_REGULAR): + fragment = grub_le_to_cpu32 (ino->ino.file.fragment); + break; + } + + /* Squash may pack file tail as fragment. So read initial part directly and + get tail from fragments */ + direct_len = fragment == 0xffffffff ? file->size : file->size & ~mask; + if (off < direct_len) + { + grub_size_t read_len = direct_len - off; + grub_ssize_t res; + + if (read_len > len) + read_len = len; + res = direct_read (data, ino, off, buf, read_len); + if ((grub_size_t) res != read_len) + return -1; /* FIXME: is short read possible here? */ + len -= read_len; + if (!len) + return read_len; + buf += read_len; + off = 0; + } + else + off -= direct_len; + + err = read_chunk (data, &frag, sizeof (frag), + data->fragments, sizeof (frag) * fragment); + if (err) + return -1; + a = grub_le_to_cpu64 (frag.offset); + compressed = !(frag.size & grub_cpu_to_le32_compile_time (SQUASH_BLOCK_UNCOMPRESSED)); + if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR)) + b = grub_le_to_cpu32 (ino->ino.long_file.offset) + off; + else + b = grub_le_to_cpu32 (ino->ino.file.offset) + off; + + /* FIXME: cache uncompressed chunks. */ + if (compressed) + { + char *block; + block = grub_malloc (grub_le_to_cpu32 (frag.size)); + if (!block) + return -1; + err = grub_disk_read (data->disk, + a >> GRUB_DISK_SECTOR_BITS, + a & (GRUB_DISK_SECTOR_SIZE - 1), + grub_le_to_cpu32 (frag.size), block); + if (err) + { + grub_free (block); + return -1; + } + if (data->decompress (block, grub_le_to_cpu32 (frag.size), + b, buf, len, data) + != (grub_ssize_t) len) + { + grub_free (block); + if (!grub_errno) + grub_error (GRUB_ERR_BAD_FS, "incorrect compressed chunk"); + return -1; + } + grub_free (block); + } + else + { + err = grub_disk_read (data->disk, (a + b) >> GRUB_DISK_SECTOR_BITS, + (a + b) & (GRUB_DISK_SECTOR_SIZE - 1), len, buf); + if (err) + return -1; + } + return orig_len; +} + +static grub_err_t +grub_squash_close (grub_file_t file) +{ + squash_unmount (file->data); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_squash_mtime (grub_device_t dev, grub_int32_t *tm) +{ + struct grub_squash_data *data = 0; + + data = squash_mount (dev->disk); + if (! data) + return grub_errno; + *tm = grub_le_to_cpu32 (data->sb.creation_time); + squash_unmount (data); + return GRUB_ERR_NONE; +} + +static struct grub_fs grub_squash_fs = + { + .name = "squash4", + .fs_dir = grub_squash_dir, + .fs_open = grub_squash_open, + .fs_read = grub_squash_read, + .fs_close = grub_squash_close, + .fs_mtime = grub_squash_mtime, +#ifdef GRUB_UTIL + .reserved_first_sector = 0, + .blocklist_install = 0, +#endif + .next = 0 + }; + +GRUB_MOD_INIT(squash4) +{ + grub_fs_register (&grub_squash_fs); +} + +GRUB_MOD_FINI(squash4) +{ + grub_fs_unregister (&grub_squash_fs); +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/udf.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/udf.c new file mode 100644 index 0000000..280ff21 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/udf.c @@ -0,0 +1,1439 @@ +/* udf.c - Universal Disk Format filesystem. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define OFFSET_OF(TYPE, MEMBER) ((grub_size_t) &((TYPE *)0)->MEMBER) + +grub_uint32_t g_last_disk_read_sector = 0; +grub_uint32_t g_last_fe_tag_ident = 0; +grub_uint32_t g_last_icb_read_sector = 0; +grub_uint32_t g_last_icb_read_sector_tag_ident = 0; +grub_uint32_t g_last_fileattr_read_sector = 0; +grub_uint32_t g_last_fileattr_read_sector_tag_ident = 0; +grub_uint32_t g_last_fileattr_offset = 0; +grub_uint64_t g_last_pd_length_offset = 0; + +#define GRUB_UDF_MAX_PDS 2 +#define GRUB_UDF_MAX_PMS 6 + +#define U16 grub_le_to_cpu16 +#define U32 grub_le_to_cpu32 +#define U64 grub_le_to_cpu64 + +#define GRUB_UDF_TAG_IDENT_PVD 0x0001 +#define GRUB_UDF_TAG_IDENT_AVDP 0x0002 +#define GRUB_UDF_TAG_IDENT_VDP 0x0003 +#define GRUB_UDF_TAG_IDENT_IUVD 0x0004 +#define GRUB_UDF_TAG_IDENT_PD 0x0005 +#define GRUB_UDF_TAG_IDENT_LVD 0x0006 +#define GRUB_UDF_TAG_IDENT_USD 0x0007 +#define GRUB_UDF_TAG_IDENT_TD 0x0008 +#define GRUB_UDF_TAG_IDENT_LVID 0x0009 + +#define GRUB_UDF_TAG_IDENT_FSD 0x0100 +#define GRUB_UDF_TAG_IDENT_FID 0x0101 +#define GRUB_UDF_TAG_IDENT_AED 0x0102 +#define GRUB_UDF_TAG_IDENT_IE 0x0103 +#define GRUB_UDF_TAG_IDENT_TE 0x0104 +#define GRUB_UDF_TAG_IDENT_FE 0x0105 +#define GRUB_UDF_TAG_IDENT_EAHD 0x0106 +#define GRUB_UDF_TAG_IDENT_USE 0x0107 +#define GRUB_UDF_TAG_IDENT_SBD 0x0108 +#define GRUB_UDF_TAG_IDENT_PIE 0x0109 +#define GRUB_UDF_TAG_IDENT_EFE 0x010A + +#define GRUB_UDF_ICBTAG_TYPE_UNDEF 0x00 +#define GRUB_UDF_ICBTAG_TYPE_USE 0x01 +#define GRUB_UDF_ICBTAG_TYPE_PIE 0x02 +#define GRUB_UDF_ICBTAG_TYPE_IE 0x03 +#define GRUB_UDF_ICBTAG_TYPE_DIRECTORY 0x04 +#define GRUB_UDF_ICBTAG_TYPE_REGULAR 0x05 +#define GRUB_UDF_ICBTAG_TYPE_BLOCK 0x06 +#define GRUB_UDF_ICBTAG_TYPE_CHAR 0x07 +#define GRUB_UDF_ICBTAG_TYPE_EA 0x08 +#define GRUB_UDF_ICBTAG_TYPE_FIFO 0x09 +#define GRUB_UDF_ICBTAG_TYPE_SOCKET 0x0A +#define GRUB_UDF_ICBTAG_TYPE_TE 0x0B +#define GRUB_UDF_ICBTAG_TYPE_SYMLINK 0x0C +#define GRUB_UDF_ICBTAG_TYPE_STREAMDIR 0x0D + +#define GRUB_UDF_ICBTAG_FLAG_AD_MASK 0x0007 +#define GRUB_UDF_ICBTAG_FLAG_AD_SHORT 0x0000 +#define GRUB_UDF_ICBTAG_FLAG_AD_LONG 0x0001 +#define GRUB_UDF_ICBTAG_FLAG_AD_EXT 0x0002 +#define GRUB_UDF_ICBTAG_FLAG_AD_IN_ICB 0x0003 + +#define GRUB_UDF_EXT_NORMAL 0x00000000 +#define GRUB_UDF_EXT_NREC_ALLOC 0x40000000 +#define GRUB_UDF_EXT_NREC_NALLOC 0x80000000 +#define GRUB_UDF_EXT_MASK 0xC0000000 + +#define GRUB_UDF_FID_CHAR_HIDDEN 0x01 +#define GRUB_UDF_FID_CHAR_DIRECTORY 0x02 +#define GRUB_UDF_FID_CHAR_DELETED 0x04 +#define GRUB_UDF_FID_CHAR_PARENT 0x08 +#define GRUB_UDF_FID_CHAR_METADATA 0x10 + +#define GRUB_UDF_STD_IDENT_BEA01 "BEA01" +#define GRUB_UDF_STD_IDENT_BOOT2 "BOOT2" +#define GRUB_UDF_STD_IDENT_CD001 "CD001" +#define GRUB_UDF_STD_IDENT_CDW02 "CDW02" +#define GRUB_UDF_STD_IDENT_NSR02 "NSR02" +#define GRUB_UDF_STD_IDENT_NSR03 "NSR03" +#define GRUB_UDF_STD_IDENT_TEA01 "TEA01" + +#define GRUB_UDF_CHARSPEC_TYPE_CS0 0x00 +#define GRUB_UDF_CHARSPEC_TYPE_CS1 0x01 +#define GRUB_UDF_CHARSPEC_TYPE_CS2 0x02 +#define GRUB_UDF_CHARSPEC_TYPE_CS3 0x03 +#define GRUB_UDF_CHARSPEC_TYPE_CS4 0x04 +#define GRUB_UDF_CHARSPEC_TYPE_CS5 0x05 +#define GRUB_UDF_CHARSPEC_TYPE_CS6 0x06 +#define GRUB_UDF_CHARSPEC_TYPE_CS7 0x07 +#define GRUB_UDF_CHARSPEC_TYPE_CS8 0x08 + +#define GRUB_UDF_PARTMAP_TYPE_1 1 +#define GRUB_UDF_PARTMAP_TYPE_2 2 + +struct grub_udf_lb_addr +{ + grub_uint32_t block_num; + grub_uint16_t part_ref; +} GRUB_PACKED; + +struct grub_udf_short_ad +{ + grub_uint32_t length; + grub_uint32_t position; +} GRUB_PACKED; + +struct grub_udf_long_ad +{ + grub_uint32_t length; + struct grub_udf_lb_addr block; + grub_uint8_t imp_use[6]; +} GRUB_PACKED; + +struct grub_udf_extent_ad +{ + grub_uint32_t length; + grub_uint32_t start; +} GRUB_PACKED; + +struct grub_udf_charspec +{ + grub_uint8_t charset_type; + grub_uint8_t charset_info[63]; +} GRUB_PACKED; + +struct grub_udf_timestamp +{ + grub_uint16_t type_and_timezone; + grub_uint16_t year; + grub_uint8_t month; + grub_uint8_t day; + grub_uint8_t hour; + grub_uint8_t minute; + grub_uint8_t second; + grub_uint8_t centi_seconds; + grub_uint8_t hundreds_of_micro_seconds; + grub_uint8_t micro_seconds; +} GRUB_PACKED; + +struct grub_udf_regid +{ + grub_uint8_t flags; + grub_uint8_t ident[23]; + grub_uint8_t ident_suffix[8]; +} GRUB_PACKED; + +struct grub_udf_tag +{ + grub_uint16_t tag_ident; + grub_uint16_t desc_version; + grub_uint8_t tag_checksum; + grub_uint8_t reserved; + grub_uint16_t tag_serial_number; + grub_uint16_t desc_crc; + grub_uint16_t desc_crc_length; + grub_uint32_t tag_location; +} GRUB_PACKED; + +struct grub_udf_fileset +{ + struct grub_udf_tag tag; + struct grub_udf_timestamp datetime; + grub_uint16_t interchange_level; + grub_uint16_t max_interchange_level; + grub_uint32_t charset_list; + grub_uint32_t max_charset_list; + grub_uint32_t fileset_num; + grub_uint32_t fileset_desc_num; + struct grub_udf_charspec vol_charset; + grub_uint8_t vol_ident[128]; + struct grub_udf_charspec fileset_charset; + grub_uint8_t fileset_ident[32]; + grub_uint8_t copyright_file_ident[32]; + grub_uint8_t abstract_file_ident[32]; + struct grub_udf_long_ad root_icb; + struct grub_udf_regid domain_ident; + struct grub_udf_long_ad next_ext; + struct grub_udf_long_ad streamdir_icb; +} GRUB_PACKED; + +struct grub_udf_icbtag +{ + grub_uint32_t prior_recorded_num_direct_entries; + grub_uint16_t strategy_type; + grub_uint16_t strategy_parameter; + grub_uint16_t num_entries; + grub_uint8_t reserved; + grub_uint8_t file_type; + struct grub_udf_lb_addr parent_idb; + grub_uint16_t flags; +} GRUB_PACKED; + +struct grub_udf_file_ident +{ + struct grub_udf_tag tag; + grub_uint16_t version_num; + grub_uint8_t characteristics; +#define MAX_FILE_IDENT_LENGTH 256 + grub_uint8_t file_ident_length; + struct grub_udf_long_ad icb; + grub_uint16_t imp_use_length; +} GRUB_PACKED; + +struct grub_udf_file_entry +{ + struct grub_udf_tag tag; + struct grub_udf_icbtag icbtag; + grub_uint32_t uid; + grub_uint32_t gid; + grub_uint32_t permissions; + grub_uint16_t link_count; + grub_uint8_t record_format; + grub_uint8_t record_display_attr; + grub_uint32_t record_length; + grub_uint64_t file_size; + grub_uint64_t blocks_recorded; + struct grub_udf_timestamp access_time; + struct grub_udf_timestamp modification_time; + struct grub_udf_timestamp attr_time; + grub_uint32_t checkpoint; + struct grub_udf_long_ad extended_attr_idb; + struct grub_udf_regid imp_ident; + grub_uint64_t unique_id; + grub_uint32_t ext_attr_length; + grub_uint32_t alloc_descs_length; + grub_uint8_t ext_attr[0]; +} GRUB_PACKED; + +struct grub_udf_extended_file_entry +{ + struct grub_udf_tag tag; + struct grub_udf_icbtag icbtag; + grub_uint32_t uid; + grub_uint32_t gid; + grub_uint32_t permissions; + grub_uint16_t link_count; + grub_uint8_t record_format; + grub_uint8_t record_display_attr; + grub_uint32_t record_length; + grub_uint64_t file_size; + grub_uint64_t object_size; + grub_uint64_t blocks_recorded; + struct grub_udf_timestamp access_time; + struct grub_udf_timestamp modification_time; + struct grub_udf_timestamp create_time; + struct grub_udf_timestamp attr_time; + grub_uint32_t checkpoint; + grub_uint32_t reserved; + struct grub_udf_long_ad extended_attr_icb; + struct grub_udf_long_ad streamdir_icb; + struct grub_udf_regid imp_ident; + grub_uint64_t unique_id; + grub_uint32_t ext_attr_length; + grub_uint32_t alloc_descs_length; + grub_uint8_t ext_attr[0]; +} GRUB_PACKED; + +struct grub_udf_vrs +{ + grub_uint8_t type; + grub_uint8_t magic[5]; + grub_uint8_t version; +} GRUB_PACKED; + +struct grub_udf_avdp +{ + struct grub_udf_tag tag; + struct grub_udf_extent_ad vds; +} GRUB_PACKED; + +struct grub_udf_pd +{ + struct grub_udf_tag tag; + grub_uint32_t seq_num; + grub_uint16_t flags; + grub_uint16_t part_num; + struct grub_udf_regid contents; + grub_uint8_t contents_use[128]; + grub_uint32_t access_type; + grub_uint32_t start; + grub_uint32_t length; +} GRUB_PACKED; + +struct grub_udf_partmap +{ + grub_uint8_t type; + grub_uint8_t length; + union + { + struct + { + grub_uint16_t seq_num; + grub_uint16_t part_num; + } type1; + + struct + { + grub_uint8_t ident[62]; + } type2; + }; +} GRUB_PACKED; + +struct grub_udf_pvd +{ + struct grub_udf_tag tag; + grub_uint32_t seq_num; + grub_uint32_t pvd_num; + grub_uint8_t ident[32]; + grub_uint16_t vol_seq_num; + grub_uint16_t max_vol_seq_num; + grub_uint16_t interchange_level; + grub_uint16_t max_interchange_level; + grub_uint32_t charset_list; + grub_uint32_t max_charset_list; + grub_uint8_t volset_ident[128]; + struct grub_udf_charspec desc_charset; + struct grub_udf_charspec expl_charset; + struct grub_udf_extent_ad vol_abstract; + struct grub_udf_extent_ad vol_copyright; + struct grub_udf_regid app_ident; + struct grub_udf_timestamp recording_time; + struct grub_udf_regid imp_ident; + grub_uint8_t imp_use[64]; + grub_uint32_t pred_vds_loc; + grub_uint16_t flags; + grub_uint8_t reserved[22]; +} GRUB_PACKED; + +struct grub_udf_lvd +{ + struct grub_udf_tag tag; + grub_uint32_t seq_num; + struct grub_udf_charspec charset; + grub_uint8_t ident[128]; + grub_uint32_t bsize; + struct grub_udf_regid domain_ident; + struct grub_udf_long_ad root_fileset; + grub_uint32_t map_table_length; + grub_uint32_t num_part_maps; + struct grub_udf_regid imp_ident; + grub_uint8_t imp_use[128]; + struct grub_udf_extent_ad integrity_seq_ext; + grub_uint8_t part_maps[1608]; +} GRUB_PACKED; + +struct grub_udf_aed +{ + struct grub_udf_tag tag; + grub_uint32_t prev_ae; + grub_uint32_t ae_len; +} GRUB_PACKED; + +struct grub_udf_data +{ + grub_disk_t disk; + struct grub_udf_pvd pvd; + struct grub_udf_lvd lvd; + struct grub_udf_pd pds[GRUB_UDF_MAX_PDS]; + struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS]; + struct grub_udf_long_ad root_icb; + int npd, npm, lbshift; +}; + +struct grub_fshelp_node +{ + struct grub_udf_data *data; + int part_ref; + union + { + struct grub_udf_file_entry fe; + struct grub_udf_extended_file_entry efe; + char raw[0]; + } block; +}; + +static inline grub_size_t +get_fshelp_size (struct grub_udf_data *data) +{ + struct grub_fshelp_node *x = NULL; + return sizeof (*x) + + (1 << (GRUB_DISK_SECTOR_BITS + + data->lbshift)) - sizeof (x->block); +} + +static grub_dl_t my_mod; + +static grub_uint32_t +grub_udf_get_block (struct grub_udf_data *data, + grub_uint16_t part_ref, grub_uint32_t block) +{ + part_ref = U16 (part_ref); + + if (part_ref >= data->npm) + { + grub_error (GRUB_ERR_BAD_FS, "invalid part ref"); + return 0; + } + + return (U32 (data->pds[data->pms[part_ref]->type1.part_num].start) + + U32 (block)); +} + +static grub_err_t +grub_udf_read_icb (struct grub_udf_data *data, + struct grub_udf_long_ad *icb, + struct grub_fshelp_node *node) +{ + grub_uint32_t block; + + block = grub_udf_get_block (data, + icb->block.part_ref, + icb->block.block_num); + + if (grub_errno) + return grub_errno; + + if (grub_disk_read (data->disk, block << data->lbshift, 0, + 1 << (GRUB_DISK_SECTOR_BITS + + data->lbshift), + &node->block)) + return grub_errno; + + g_last_disk_read_sector = block; + g_last_fe_tag_ident = U16(node->block.fe.tag.tag_ident); + + if ((U16 (node->block.fe.tag.tag_ident) != GRUB_UDF_TAG_IDENT_FE) && + (U16 (node->block.fe.tag.tag_ident) != GRUB_UDF_TAG_IDENT_EFE)) + return grub_error (GRUB_ERR_BAD_FS, "invalid fe/efe descriptor"); + + node->part_ref = icb->block.part_ref; + node->data = data; + return 0; +} + +static grub_disk_addr_t +grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) +{ + char *buf = NULL; + char *ptr; + grub_ssize_t len; + grub_disk_addr_t filebytes; + + switch (U16 (node->block.fe.tag.tag_ident)) + { + case GRUB_UDF_TAG_IDENT_FE: + ptr = (char *) &node->block.fe.ext_attr[0] + U32 (node->block.fe.ext_attr_length); + len = U32 (node->block.fe.alloc_descs_length); + break; + + case GRUB_UDF_TAG_IDENT_EFE: + ptr = (char *) &node->block.efe.ext_attr[0] + U32 (node->block.efe.ext_attr_length); + len = U32 (node->block.efe.alloc_descs_length); + break; + + default: + grub_error (GRUB_ERR_BAD_FS, "invalid file entry"); + return 0; + } + + if ((U16 (node->block.fe.icbtag.flags) & GRUB_UDF_ICBTAG_FLAG_AD_MASK) + == GRUB_UDF_ICBTAG_FLAG_AD_SHORT) + { + struct grub_udf_short_ad *ad = (struct grub_udf_short_ad *) ptr; + + filebytes = fileblock * U32 (node->data->lvd.bsize); + while (len >= (grub_ssize_t) sizeof (struct grub_udf_short_ad)) + { + grub_uint32_t adlen = U32 (ad->length) & 0x3fffffff; + grub_uint32_t adtype = U32 (ad->length) >> 30; + if (adtype == 3) + { + struct grub_udf_aed *extension; + grub_disk_addr_t sec = grub_udf_get_block(node->data, + node->part_ref, + ad->position); + if (!buf) + { + buf = grub_malloc (U32 (node->data->lvd.bsize)); + if (!buf) + return 0; + } + if (grub_disk_read (node->data->disk, sec << node->data->lbshift, + 0, adlen, buf)) + goto fail; + + extension = (struct grub_udf_aed *) buf; + if (U16 (extension->tag.tag_ident) != GRUB_UDF_TAG_IDENT_AED) + { + grub_error (GRUB_ERR_BAD_FS, "invalid aed tag"); + goto fail; + } + + len = U32 (extension->ae_len); + ad = (struct grub_udf_short_ad *) + (buf + sizeof (struct grub_udf_aed)); + continue; + } + + if (filebytes < adlen) + { + grub_uint32_t ad_pos = ad->position; + grub_free (buf); + return ((U32 (ad_pos) & GRUB_UDF_EXT_MASK) ? 0 : + (grub_udf_get_block (node->data, node->part_ref, ad_pos) + + (filebytes >> (GRUB_DISK_SECTOR_BITS + + node->data->lbshift)))); + } + + filebytes -= adlen; + ad++; + len -= sizeof (struct grub_udf_short_ad); + } + } + else + { + struct grub_udf_long_ad *ad = (struct grub_udf_long_ad *) ptr; + + filebytes = fileblock * U32 (node->data->lvd.bsize); + while (len >= (grub_ssize_t) sizeof (struct grub_udf_long_ad)) + { + grub_uint32_t adlen = U32 (ad->length) & 0x3fffffff; + grub_uint32_t adtype = U32 (ad->length) >> 30; + if (adtype == 3) + { + struct grub_udf_aed *extension; + grub_disk_addr_t sec = grub_udf_get_block(node->data, + ad->block.part_ref, + ad->block.block_num); + if (!buf) + { + buf = grub_malloc (U32 (node->data->lvd.bsize)); + if (!buf) + return 0; + } + if (grub_disk_read (node->data->disk, sec << node->data->lbshift, + 0, adlen, buf)) + goto fail; + + extension = (struct grub_udf_aed *) buf; + if (U16 (extension->tag.tag_ident) != GRUB_UDF_TAG_IDENT_AED) + { + grub_error (GRUB_ERR_BAD_FS, "invalid aed tag"); + goto fail; + } + + len = U32 (extension->ae_len); + ad = (struct grub_udf_long_ad *) + (buf + sizeof (struct grub_udf_aed)); + continue; + } + + if (filebytes < adlen) + { + grub_uint32_t ad_block_num = ad->block.block_num; + grub_uint32_t ad_part_ref = ad->block.part_ref; + grub_free (buf); + return ((U32 (ad_block_num) & GRUB_UDF_EXT_MASK) ? 0 : + (grub_udf_get_block (node->data, ad_part_ref, + ad_block_num) + + (filebytes >> (GRUB_DISK_SECTOR_BITS + + node->data->lbshift)))); + } + + filebytes -= adlen; + ad++; + len -= sizeof (struct grub_udf_long_ad); + } + } + +fail: + grub_free (buf); + + return 0; +} + +static grub_ssize_t +grub_udf_read_file (grub_fshelp_node_t node, + grub_disk_read_hook_t read_hook, void *read_hook_data, + grub_off_t pos, grub_size_t len, char *buf) +{ + switch (U16 (node->block.fe.icbtag.flags) & GRUB_UDF_ICBTAG_FLAG_AD_MASK) + { + case GRUB_UDF_ICBTAG_FLAG_AD_IN_ICB: + { + char *ptr; + + ptr = ((U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE) ? + ((char *) &node->block.fe.ext_attr[0] + + U32 (node->block.fe.ext_attr_length)) : + ((char *) &node->block.efe.ext_attr[0] + + U32 (node->block.efe.ext_attr_length))); + + grub_memcpy (buf, ptr + pos, len); + + return len; + } + + case GRUB_UDF_ICBTAG_FLAG_AD_EXT: + grub_error (GRUB_ERR_BAD_FS, "invalid extent type"); + return 0; + } + + return grub_fshelp_read_file (node->data->disk, node, + read_hook, read_hook_data, + pos, len, buf, grub_udf_read_block, + U64 (node->block.fe.file_size), + node->data->lbshift, 0); +} + +static unsigned sblocklist[] = { 256, 512, 0 }; + +static struct grub_udf_data * +grub_udf_mount (grub_disk_t disk) +{ + struct grub_udf_data *data = 0; + struct grub_udf_fileset root_fs; + unsigned *sblklist; + grub_uint32_t block, vblock; + int i, lbshift; + + data = grub_malloc (sizeof (struct grub_udf_data)); + if (!data) + return 0; + + data->disk = disk; + + /* Search for Anchor Volume Descriptor Pointer (AVDP) + * and determine logical block size. */ + block = 0; + for (lbshift = 0; lbshift < 4; lbshift++) + { + for (sblklist = sblocklist; *sblklist; sblklist++) + { + struct grub_udf_avdp avdp; + + if (grub_disk_read (disk, *sblklist << lbshift, 0, + sizeof (struct grub_udf_avdp), &avdp)) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + + if (U16 (avdp.tag.tag_ident) == GRUB_UDF_TAG_IDENT_AVDP && + U32 (avdp.tag.tag_location) == *sblklist) + { + block = U32 (avdp.vds.start); + break; + } + } + + if (block) + break; + } + + if (!block) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + data->lbshift = lbshift; + + /* Search for Volume Recognition Sequence (VRS). */ + for (vblock = (32767 >> (lbshift + GRUB_DISK_SECTOR_BITS)) + 1;; + vblock += (2047 >> (lbshift + GRUB_DISK_SECTOR_BITS)) + 1) + { + struct grub_udf_vrs vrs; + + if (grub_disk_read (disk, vblock << lbshift, 0, + sizeof (struct grub_udf_vrs), &vrs)) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + + if ((!grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_NSR03, 5)) || + (!grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_NSR02, 5))) + break; + + if ((grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_BEA01, 5)) && + (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_BOOT2, 5)) && + (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_CD001, 5)) && + (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_CDW02, 5)) && + (grub_memcmp (vrs.magic, GRUB_UDF_STD_IDENT_TEA01, 5))) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + } + + data->npd = data->npm = 0; + /* Locate Partition Descriptor (PD) and Logical Volume Descriptor (LVD). */ + while (1) + { + struct grub_udf_tag tag; + + if (grub_disk_read (disk, block << lbshift, 0, + sizeof (struct grub_udf_tag), &tag)) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + + tag.tag_ident = U16 (tag.tag_ident); + if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PVD) + { + if (grub_disk_read (disk, block << lbshift, 0, + sizeof (struct grub_udf_pvd), + &data->pvd)) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + } + else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD) + { + if (data->npd >= GRUB_UDF_MAX_PDS) + { + grub_error (GRUB_ERR_BAD_FS, "too many PDs"); + goto fail; + } + + if (grub_disk_read (disk, block << lbshift, 0, + sizeof (struct grub_udf_pd), + &data->pds[data->npd])) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + + g_last_pd_length_offset = (block << lbshift) * 512 + OFFSET_OF(struct grub_udf_pd, length); + + data->npd++; + } + else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_LVD) + { + int k; + + struct grub_udf_partmap *ppm; + + if (grub_disk_read (disk, block << lbshift, 0, + sizeof (struct grub_udf_lvd), + &data->lvd)) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + + if (data->npm + U32 (data->lvd.num_part_maps) > GRUB_UDF_MAX_PMS) + { + grub_error (GRUB_ERR_BAD_FS, "too many partition maps"); + goto fail; + } + + ppm = (struct grub_udf_partmap *) &data->lvd.part_maps; + for (k = U32 (data->lvd.num_part_maps); k > 0; k--) + { + if (ppm->type != GRUB_UDF_PARTMAP_TYPE_1) + { + grub_error (GRUB_ERR_BAD_FS, "partmap type not supported"); + goto fail; + } + + data->pms[data->npm++] = ppm; + ppm = (struct grub_udf_partmap *) ((char *) ppm + + U32 (ppm->length)); + } + } + else if (tag.tag_ident > GRUB_UDF_TAG_IDENT_TD) + { + grub_error (GRUB_ERR_BAD_FS, "invalid tag ident"); + goto fail; + } + else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_TD) + break; + + block++; + } + + for (i = 0; i < data->npm; i++) + { + int j; + + for (j = 0; j < data->npd; j++) + if (data->pms[i]->type1.part_num == data->pds[j].part_num) + { + data->pms[i]->type1.part_num = j; + break; + } + + if (j == data->npd) + { + grub_error (GRUB_ERR_BAD_FS, "can\'t find PD"); + goto fail; + } + } + + block = grub_udf_get_block (data, + data->lvd.root_fileset.block.part_ref, + data->lvd.root_fileset.block.block_num); + + if (grub_errno) + goto fail; + + if (grub_disk_read (disk, block << lbshift, 0, + sizeof (struct grub_udf_fileset), &root_fs)) + { + grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem"); + goto fail; + } + + if (U16 (root_fs.tag.tag_ident) != GRUB_UDF_TAG_IDENT_FSD) + { + grub_error (GRUB_ERR_BAD_FS, "invalid fileset descriptor"); + goto fail; + } + + data->root_icb = root_fs.root_icb; + + return data; + +fail: + grub_free (data); + return 0; +} + +#ifdef GRUB_UTIL +grub_disk_addr_t +grub_udf_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn) +{ + grub_disk_addr_t ret; + static struct grub_udf_data *data; + + data = grub_udf_mount (disk); + if (!data) + return 0; + + ret = U32 (data->pds[data->pms[0]->type1.part_num].start); + *sec_per_lcn = 1ULL << data->lbshift; + grub_free (data); + return ret; +} +#endif + +static char * +read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf) +{ + grub_uint16_t *utf16 = NULL; + grub_size_t utf16len = 0; + + if (sz == 0) + return NULL; + + if (raw[0] != 8 && raw[0] != 16) + return NULL; + + if (raw[0] == 8) + { + unsigned i; + utf16len = sz - 1; + utf16 = grub_malloc (utf16len * sizeof (utf16[0])); + if (!utf16) + return NULL; + for (i = 0; i < utf16len; i++) + utf16[i] = raw[i + 1]; + } + if (raw[0] == 16) + { + unsigned i; + utf16len = (sz - 1) / 2; + utf16 = grub_malloc (utf16len * sizeof (utf16[0])); + if (!utf16) + return NULL; + for (i = 0; i < utf16len; i++) + utf16[i] = (raw[2 * i + 1] << 8) | raw[2*i + 2]; + } + if (!outbuf) + outbuf = grub_malloc (utf16len * GRUB_MAX_UTF8_PER_UTF16 + 1); + if (outbuf) + *grub_utf16_to_utf8 ((grub_uint8_t *) outbuf, utf16, utf16len) = '\0'; + grub_free (utf16); + return outbuf; +} + +static char * +read_dstring (const grub_uint8_t *raw, grub_size_t sz) +{ + grub_size_t len; + + if (raw[0] == 0) { + char *outbuf = grub_malloc (1); + if (!outbuf) + return NULL; + outbuf[0] = 0; + return outbuf; + } + + len = raw[sz - 1]; + if (len > sz - 1) + len = sz - 1; + return read_string (raw, len, NULL); +} + +static int +grub_udf_iterate_dir (grub_fshelp_node_t dir, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) +{ + grub_fshelp_node_t child; + struct grub_udf_file_ident dirent; + grub_off_t offset = 0; + + child = grub_malloc (get_fshelp_size (dir->data)); + if (!child) + return 0; + + /* The current directory is not stored. */ + grub_memcpy (child, dir, get_fshelp_size (dir->data)); + + if (hook (".", GRUB_FSHELP_DIR, child, hook_data)) + return 1; + + while (offset < U64 (dir->block.fe.file_size)) + { + if (grub_udf_read_file (dir, 0, 0, offset, sizeof (dirent), + (char *) &dirent) != sizeof (dirent)) + return 0; + + if (U16 (dirent.tag.tag_ident) != GRUB_UDF_TAG_IDENT_FID) + { + grub_error (GRUB_ERR_BAD_FS, "invalid fid tag"); + return 0; + } + + offset += sizeof (dirent) + U16 (dirent.imp_use_length); + if (!(dirent.characteristics & GRUB_UDF_FID_CHAR_DELETED)) + { + child = grub_malloc (get_fshelp_size (dir->data)); + if (!child) + return 0; + + if (grub_udf_read_icb (dir->data, &dirent.icb, child)) + return 0; + + g_last_icb_read_sector = g_last_disk_read_sector; + g_last_icb_read_sector_tag_ident = g_last_fe_tag_ident; + if (dirent.characteristics & GRUB_UDF_FID_CHAR_PARENT) + { + /* This is the parent directory. */ + if (hook ("..", GRUB_FSHELP_DIR, child, hook_data)) + return 1; + } + else + { + enum grub_fshelp_filetype type; + char *filename; + grub_uint8_t raw[MAX_FILE_IDENT_LENGTH]; + + type = ((dirent.characteristics & GRUB_UDF_FID_CHAR_DIRECTORY) ? + (GRUB_FSHELP_DIR) : (GRUB_FSHELP_REG)); + if (child->block.fe.icbtag.file_type == GRUB_UDF_ICBTAG_TYPE_SYMLINK) + type = GRUB_FSHELP_SYMLINK; + + if ((grub_udf_read_file (dir, 0, 0, offset, + dirent.file_ident_length, + (char *) raw)) + != dirent.file_ident_length) + return 0; + + filename = read_string (raw, dirent.file_ident_length, 0); + if (!filename) + grub_print_error (); + + if (filename && hook (filename, type, child, hook_data)) + { + g_last_fileattr_read_sector = g_last_icb_read_sector; + g_last_fileattr_read_sector_tag_ident = g_last_icb_read_sector_tag_ident; + g_last_fileattr_offset = (grub_uint32_t)((child->block.fe.ext_attr + child->block.fe.ext_attr_length) - (grub_uint8_t *)&(child->block.fe)); + grub_free (filename); + return 1; + } + grub_free (filename); + } + } + + /* Align to dword boundary. */ + offset = (offset + dirent.file_ident_length + 3) & (~3); + } + + return 0; +} + +static char * +grub_udf_read_symlink (grub_fshelp_node_t node) +{ + grub_size_t sz = U64 (node->block.fe.file_size); + grub_uint8_t *raw; + const grub_uint8_t *ptr; + char *out, *optr; + + if (sz < 4) + return NULL; + raw = grub_malloc (sz); + if (!raw) + return NULL; + if (grub_udf_read_file (node, NULL, NULL, 0, sz, (char *) raw) < 0) + { + grub_free (raw); + return NULL; + } + + out = grub_malloc (sz * 2 + 1); + if (!out) + { + grub_free (raw); + return NULL; + } + + optr = out; + + for (ptr = raw; ptr < raw + sz; ) + { + grub_size_t s; + if ((grub_size_t) (ptr - raw + 4) > sz) + goto fail; + if (!(ptr[2] == 0 && ptr[3] == 0)) + goto fail; + s = 4 + ptr[1]; + if ((grub_size_t) (ptr - raw + s) > sz) + goto fail; + switch (*ptr) + { + case 1: + if (ptr[1]) + goto fail; + /* Fallthrough. */ + case 2: + /* in 4 bytes. out: 1 byte. */ + optr = out; + *optr++ = '/'; + break; + case 3: + /* in 4 bytes. out: 3 bytes. */ + if (optr != out) + *optr++ = '/'; + *optr++ = '.'; + *optr++ = '.'; + break; + case 4: + /* in 4 bytes. out: 2 bytes. */ + if (optr != out) + *optr++ = '/'; + *optr++ = '.'; + break; + case 5: + /* in 4 + n bytes. out, at most: 1 + 2 * n bytes. */ + if (optr != out) + *optr++ = '/'; + if (!read_string (ptr + 4, s - 4, optr)) + goto fail; + optr += grub_strlen (optr); + break; + default: + goto fail; + } + ptr += s; + } + *optr = 0; + grub_free (raw); + return out; + + fail: + grub_free (raw); + grub_free (out); + grub_error (GRUB_ERR_BAD_FS, "invalid symlink"); + return NULL; +} + +/* Context for grub_udf_dir. */ +struct grub_udf_dir_ctx +{ + grub_fs_dir_hook_t hook; + void *hook_data; +}; + +/* Helper for grub_udf_dir. */ +static int +grub_udf_dir_iter (const char *filename, enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node, void *data) +{ + struct grub_udf_dir_ctx *ctx = data; + struct grub_dirhook_info info; + const struct grub_udf_timestamp *tstamp = NULL; + + grub_memset (&info, 0, sizeof (info)); + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + if (U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_FE) + tstamp = &node->block.fe.modification_time; + else if (U16 (node->block.fe.tag.tag_ident) == GRUB_UDF_TAG_IDENT_EFE) + tstamp = &node->block.efe.modification_time; + + if (tstamp && (U16 (tstamp->type_and_timezone) & 0xf000) == 0x1000) + { + grub_int16_t tz; + struct grub_datetime datetime; + + datetime.year = U16 (tstamp->year); + datetime.month = tstamp->month; + datetime.day = tstamp->day; + datetime.hour = tstamp->hour; + datetime.minute = tstamp->minute; + datetime.second = tstamp->second; + + tz = U16 (tstamp->type_and_timezone) & 0xfff; + if (tz & 0x800) + tz |= 0xf000; + if (tz == -2047) + tz = 0; + + info.mtimeset = !!grub_datetime2unixtime (&datetime, &info.mtime); + + info.mtime -= 60 * tz; + } + if (!info.dir) + info.size = U64 (node->block.fe.file_size); + grub_free (node); + return ctx->hook (filename, &info, ctx->hook_data); +} + +static grub_err_t +grub_udf_dir (grub_device_t device, const char *path, + grub_fs_dir_hook_t hook, void *hook_data) +{ + struct grub_udf_dir_ctx ctx = { hook, hook_data }; + struct grub_udf_data *data = 0; + struct grub_fshelp_node *rootnode = 0; + struct grub_fshelp_node *foundnode = 0; + + grub_dl_ref (my_mod); + + data = grub_udf_mount (device->disk); + if (!data) + goto fail; + + rootnode = grub_malloc (get_fshelp_size (data)); + if (!rootnode) + goto fail; + + if (grub_udf_read_icb (data, &data->root_icb, rootnode)) + goto fail; + + if (grub_fshelp_find_file (path, rootnode, + &foundnode, + grub_udf_iterate_dir, grub_udf_read_symlink, + GRUB_FSHELP_DIR)) + goto fail; + + grub_udf_iterate_dir (foundnode, grub_udf_dir_iter, &ctx); + + if (foundnode != rootnode) + grub_free (foundnode); + +fail: + grub_free (rootnode); + + grub_free (data); + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_err_t +grub_udf_open (struct grub_file *file, const char *name) +{ + struct grub_udf_data *data; + struct grub_fshelp_node *rootnode = 0; + struct grub_fshelp_node *foundnode; + + grub_dl_ref (my_mod); + + data = grub_udf_mount (file->device->disk); + if (!data) + goto fail; + + rootnode = grub_malloc (get_fshelp_size (data)); + if (!rootnode) + goto fail; + + if (grub_udf_read_icb (data, &data->root_icb, rootnode)) + goto fail; + + if (grub_fshelp_find_file (name, rootnode, + &foundnode, + grub_udf_iterate_dir, grub_udf_read_symlink, + GRUB_FSHELP_REG)) + goto fail; + + file->data = foundnode; + file->offset = 0; + file->size = U64 (foundnode->block.fe.file_size); + + grub_free (rootnode); + + return 0; + +fail: + grub_dl_unref (my_mod); + + grub_free (data); + grub_free (rootnode); + + return grub_errno; +} + +static grub_ssize_t +grub_udf_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_fshelp_node *node = (struct grub_fshelp_node *) file->data; + + return grub_udf_read_file (node, file->read_hook, file->read_hook_data, + file->offset, len, buf); +} + +static grub_err_t +grub_udf_close (grub_file_t file) +{ + if (file->data) + { + struct grub_fshelp_node *node = (struct grub_fshelp_node *) file->data; + + grub_free (node->data); + grub_free (node); + } + + grub_dl_unref (my_mod); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_udf_label (grub_device_t device, char **label) +{ + struct grub_udf_data *data; + data = grub_udf_mount (device->disk); + + if (data) + { + *label = read_dstring (data->lvd.ident, sizeof (data->lvd.ident)); + grub_free (data); + } + else + *label = 0; + + return grub_errno; +} + +static char * +gen_uuid_from_volset (char *volset_ident) +{ + grub_size_t i; + grub_size_t len; + grub_size_t nonhexpos; + grub_uint8_t buf[17]; + char *uuid; + + len = grub_strlen (volset_ident); + if (len < 8) + return NULL; + + uuid = grub_malloc (17); + if (!uuid) + return NULL; + + if (len > 16) + len = 16; + + grub_memset (buf, 0, sizeof (buf)); + grub_memcpy (buf, volset_ident, len); + + nonhexpos = 16; + for (i = 0; i < 16; ++i) + { + if (!grub_isxdigit (buf[i])) + { + nonhexpos = i; + break; + } + } + + if (nonhexpos < 8) + { + grub_snprintf (uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x", + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + } + else if (nonhexpos < 16) + { + for (i = 0; i < 8; ++i) + uuid[i] = grub_tolower (buf[i]); + grub_snprintf (uuid+8, 9, "%02x%02x%02x%02x", + buf[8], buf[9], buf[10], buf[11]); + } + else + { + for (i = 0; i < 16; ++i) + uuid[i] = grub_tolower (buf[i]); + uuid[16] = 0; + } + + return uuid; +} + +static grub_err_t +grub_udf_uuid (grub_device_t device, char **uuid) +{ + char *volset_ident; + struct grub_udf_data *data; + data = grub_udf_mount (device->disk); + + if (data) + { + volset_ident = read_dstring (data->pvd.volset_ident, sizeof (data->pvd.volset_ident)); + if (volset_ident) + { + *uuid = gen_uuid_from_volset (volset_ident); + grub_free (volset_ident); + } + else + *uuid = 0; + grub_free (data); + } + else + *uuid = 0; + + return grub_errno; +} + +grub_uint64_t grub_udf_get_file_offset(grub_file_t file) +{ + grub_disk_addr_t sector; + struct grub_fshelp_node *node = (struct grub_fshelp_node *)file->data; + + sector = grub_udf_read_block(node, 0); + + return 512 * (sector << node->data->lbshift); +} + +grub_uint64_t grub_udf_get_last_pd_size_offset(void) +{ + return g_last_pd_length_offset; +} + +grub_uint64_t grub_udf_get_last_file_attr_offset +( + grub_file_t file, + grub_uint32_t *startBlock, + grub_uint64_t *fe_entry_size_offset +) +{ + grub_uint64_t attr_offset; + struct grub_fshelp_node *node; + struct grub_udf_data *data; + + node = (struct grub_fshelp_node *)file->data; + data = node->data; + + *startBlock = data->pds[data->pms[0]->type1.part_num].start; + + attr_offset = g_last_fileattr_read_sector * 2048 + g_last_fileattr_offset; + + if (GRUB_UDF_TAG_IDENT_FE == g_last_fileattr_read_sector_tag_ident) + { + *fe_entry_size_offset = g_last_fileattr_read_sector * 2048 + OFFSET_OF(struct grub_udf_file_entry, file_size); + } + else + { + *fe_entry_size_offset = g_last_fileattr_read_sector * 2048 + OFFSET_OF(struct grub_udf_extended_file_entry, file_size); + } + + return attr_offset; +} + +static struct grub_fs grub_udf_fs = { + .name = "udf", + .fs_dir = grub_udf_dir, + .fs_open = grub_udf_open, + .fs_read = grub_udf_read, + .fs_close = grub_udf_close, + .fs_label = grub_udf_label, + .fs_uuid = grub_udf_uuid, +#ifdef GRUB_UTIL + .reserved_first_sector = 1, + .blocklist_install = 1, +#endif + .next = 0 +}; + +GRUB_MOD_INIT (udf) +{ + grub_fs_register (&grub_udf_fs); + my_mod = mod; +} + +GRUB_MOD_FINI (udf) +{ + grub_fs_unregister (&grub_udf_fs); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/xfs.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/xfs.c new file mode 100644 index 0000000..310059e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/xfs.c @@ -0,0 +1,1356 @@ +/* xfs.c - XFS. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define NSEC_PER_SEC ((grub_int64_t) 1000000000) + +// GRUB 2.04 doesn't have safemath.h +// #include + +// gcc < 5.1 doesn't support __builtin_add_overflow and __builtin_mul_overflow +// #define grub_add(a, b, res) __builtin_add_overflow(a, b, res) +// #define grub_mul(a, b, res) __builtin_mul_overflow(a, b, res) +// Warning: This is unsafe! +#define grub_add(a, b, res) ({ *(res) = (a) + (b); 0; }) + +#define grub_mul(a, b, res) ({ *(res) = (a) * (b); 0; }) + +#define XFS_INODE_EXTENTS 9 + +#define XFS_INODE_FORMAT_INO 1 +#define XFS_INODE_FORMAT_EXT 2 +#define XFS_INODE_FORMAT_BTREE 3 + +/* Superblock version field flags */ +#define XFS_SB_VERSION_NUMBITS 0x000f +#define XFS_SB_VERSION_ATTRBIT 0x0010 +#define XFS_SB_VERSION_NLINKBIT 0x0020 +#define XFS_SB_VERSION_QUOTABIT 0x0040 +#define XFS_SB_VERSION_ALIGNBIT 0x0080 +#define XFS_SB_VERSION_DALIGNBIT 0x0100 +#define XFS_SB_VERSION_LOGV2BIT 0x0400 +#define XFS_SB_VERSION_SECTORBIT 0x0800 +#define XFS_SB_VERSION_EXTFLGBIT 0x1000 +#define XFS_SB_VERSION_DIRV2BIT 0x2000 +#define XFS_SB_VERSION_MOREBITSBIT 0x8000 +#define XFS_SB_VERSION_BITS_SUPPORTED \ + (XFS_SB_VERSION_NUMBITS | \ + XFS_SB_VERSION_ATTRBIT | \ + XFS_SB_VERSION_NLINKBIT | \ + XFS_SB_VERSION_QUOTABIT | \ + XFS_SB_VERSION_ALIGNBIT | \ + XFS_SB_VERSION_DALIGNBIT | \ + XFS_SB_VERSION_LOGV2BIT | \ + XFS_SB_VERSION_SECTORBIT | \ + XFS_SB_VERSION_EXTFLGBIT | \ + XFS_SB_VERSION_DIRV2BIT | \ + XFS_SB_VERSION_MOREBITSBIT) + +/* Recognized xfs format versions */ +#define XFS_SB_VERSION_4 4 /* Good old XFS filesystem */ +#define XFS_SB_VERSION_5 5 /* CRC enabled filesystem */ + +/* features2 field flags */ +#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */ +#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */ +#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32-bit project ids */ +#define XFS_SB_VERSION2_FTYPE 0x00000200 /* inode type in dir */ +#define XFS_SB_VERSION2_BITS_SUPPORTED \ + (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ + XFS_SB_VERSION2_ATTR2BIT | \ + XFS_SB_VERSION2_PROJID32BIT | \ + XFS_SB_VERSION2_FTYPE) + +/* Inode flags2 flags */ +#define XFS_DIFLAG2_BIGTIME_BIT 3 +#define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT) +#define XFS_DIFLAG2_NREXT64_BIT 4 +#define XFS_DIFLAG2_NREXT64 (1 << XFS_DIFLAG2_NREXT64_BIT) + +/* incompat feature flags */ +#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ +#define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */ +#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ +#define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */ +#define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4) /* needs xfs_repair */ +#define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */ +#define XFS_SB_FEAT_INCOMPAT_EXCHRANGE (1 << 6) /* exchangerange supported */ +#define XFS_SB_FEAT_INCOMPAT_PARENT (1 << 7) /* parent pointers */ +#define XFS_SB_FEAT_INCOMPAT_METADIR (1 << 8) /* metadata dir tree */ + +/* + * Directory entries with ftype are explicitly handled by GRUB code. + * + * We do not currently read the inode btrees, so it is safe to read filesystems + * with the XFS_SB_FEAT_INCOMPAT_SPINODES feature. + * + * We do not currently verify metadata UUID, so it is safe to read filesystems + * with the XFS_SB_FEAT_INCOMPAT_META_UUID feature. + * + * We do not currently replay the log, so it is safe to read filesystems + * with the XFS_SB_FEAT_INCOMPAT_EXCHRANGE feature. + * + * We do not currently read directory parent pointers, so it is safe to read + * filesystems with the XFS_SB_FEAT_INCOMPAT_PARENT feature. + * + * We do not currently look at realtime or quota metadata, so it is safe to + * read filesystems with the XFS_SB_FEAT_INCOMPAT_METADIR feature. + */ +#define XFS_SB_FEAT_INCOMPAT_SUPPORTED \ + (XFS_SB_FEAT_INCOMPAT_FTYPE | \ + XFS_SB_FEAT_INCOMPAT_SPINODES | \ + XFS_SB_FEAT_INCOMPAT_META_UUID | \ + XFS_SB_FEAT_INCOMPAT_BIGTIME | \ + XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR | \ + XFS_SB_FEAT_INCOMPAT_NREXT64 | \ + XFS_SB_FEAT_INCOMPAT_EXCHRANGE | \ + XFS_SB_FEAT_INCOMPAT_PARENT | \ + XFS_SB_FEAT_INCOMPAT_METADIR) + +struct grub_xfs_sblock +{ + grub_uint8_t magic[4]; + grub_uint32_t bsize; + grub_uint8_t unused1[24]; + grub_uint16_t uuid[8]; + grub_uint8_t unused2[8]; + grub_uint64_t rootino; + grub_uint8_t unused3[20]; + grub_uint32_t agsize; + grub_uint8_t unused4[12]; + grub_uint16_t version; + grub_uint8_t unused5[6]; + grub_uint8_t label[12]; + grub_uint8_t log2_bsize; + grub_uint8_t log2_sect; + grub_uint8_t log2_inode; + grub_uint8_t log2_inop; + grub_uint8_t log2_agblk; + grub_uint8_t unused6[67]; + grub_uint8_t log2_dirblk; + grub_uint8_t unused7[7]; + grub_uint32_t features2; + grub_uint8_t unused8[4]; + grub_uint32_t sb_features_compat; + grub_uint32_t sb_features_ro_compat; + grub_uint32_t sb_features_incompat; + grub_uint32_t sb_features_log_incompat; +} GRUB_PACKED; + +struct grub_xfs_dir_header +{ + grub_uint8_t count; + grub_uint8_t largeino; + union + { + grub_uint32_t i4; + grub_uint64_t i8; + } GRUB_PACKED parent; +} GRUB_PACKED; + +/* Structure for directory entry inlined in the inode */ +struct grub_xfs_dir_entry +{ + grub_uint8_t len; + grub_uint16_t offset; + char name[1]; + /* Inode number follows, 32 / 64 bits. */ +} GRUB_PACKED; + +/* Structure for directory entry in a block */ +struct grub_xfs_dir2_entry +{ + grub_uint64_t inode; + grub_uint8_t len; +} GRUB_PACKED; + +struct grub_xfs_extent +{ + /* This should be a bitfield but bietfields are unportable, so just have + a raw array and functions extracting useful info from it. + */ + grub_uint32_t raw[4]; +} GRUB_PACKED; + +struct grub_xfs_btree_node +{ + grub_uint8_t magic[4]; + grub_uint16_t level; + grub_uint16_t numrecs; + grub_uint64_t left; + grub_uint64_t right; + /* In V5 here follow crc, uuid, etc. */ + /* Then follow keys and block pointers */ +} GRUB_PACKED; + +struct grub_xfs_btree_root +{ + grub_uint16_t level; + grub_uint16_t numrecs; + grub_uint64_t keys[1]; +} GRUB_PACKED; + +struct grub_xfs_time_legacy +{ + grub_uint32_t sec; + grub_uint32_t nanosec; +} GRUB_PACKED; + +/* + * The struct grub_xfs_inode layout was taken from the + * struct xfs_dinode_core which is described here: + * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf + */ +struct grub_xfs_inode +{ + grub_uint8_t magic[2]; + grub_uint16_t mode; + grub_uint8_t version; + grub_uint8_t format; + grub_uint8_t unused2[18]; + grub_uint64_t nextents_big; + grub_uint64_t atime; + grub_uint64_t mtime; + grub_uint64_t ctime; + grub_uint64_t size; + grub_uint64_t nblocks; + grub_uint32_t extsize; + grub_uint32_t nextents; + grub_uint16_t unused3; + grub_uint8_t fork_offset; + grub_uint8_t unused4[17]; /* Last member of inode v2. */ + grub_uint8_t unused5[20]; /* First member of inode v3. */ + grub_uint64_t flags2; + grub_uint8_t unused6[48]; /* Last member of inode v3. */ +} GRUB_PACKED; + +#define XFS_V3_INODE_SIZE sizeof(struct grub_xfs_inode) +/* Size of struct grub_xfs_inode v2, up to unused4 member included. */ +#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76) + +struct grub_xfs_dir_leaf_entry +{ + grub_uint32_t hashval; + grub_uint32_t address; +} GRUB_PACKED; + +struct grub_xfs_dirblock_tail +{ + grub_uint32_t leaf_count; + grub_uint32_t leaf_stale; +} GRUB_PACKED; + +struct grub_fshelp_node +{ + struct grub_xfs_data *data; + grub_uint64_t ino; + int inode_read; + struct grub_xfs_inode inode; +}; + +struct grub_xfs_data +{ + grub_size_t data_size; + struct grub_xfs_sblock sblock; + grub_disk_t disk; + int pos; + int bsize; + grub_uint32_t agsize; + unsigned int hasftype:1; + unsigned int hascrc:1; + struct grub_fshelp_node diropen; +}; + +static grub_dl_t my_mod; + +static int grub_xfs_sb_hascrc(struct grub_xfs_data *data) +{ + return (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) == + grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5); +} + +static int grub_xfs_sb_hasftype(struct grub_xfs_data *data) +{ + if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) == + grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5) && + data->sblock.sb_features_incompat & grub_cpu_to_be32_compile_time(XFS_SB_FEAT_INCOMPAT_FTYPE)) + return 1; + if (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_MOREBITSBIT) && + data->sblock.features2 & grub_cpu_to_be32_compile_time(XFS_SB_VERSION2_FTYPE)) + return 1; + return 0; +} + +static int grub_xfs_sb_valid(struct grub_xfs_data *data) +{ + grub_dprintf("xfs", "Validating superblock\n"); + if (grub_strncmp ((char *) (data->sblock.magic), "XFSB", 4) + || data->sblock.log2_bsize < GRUB_DISK_SECTOR_BITS + || ((int) data->sblock.log2_bsize + + (int) data->sblock.log2_dirblk) >= 27) + { + grub_error (GRUB_ERR_BAD_FS, "not a XFS filesystem"); + return 0; + } + if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) == + grub_cpu_to_be16_compile_time(XFS_SB_VERSION_5)) + { + grub_dprintf("xfs", "XFS v5 superblock detected\n"); + if (data->sblock.sb_features_incompat & + grub_cpu_to_be32_compile_time(~XFS_SB_FEAT_INCOMPAT_SUPPORTED)) + { + grub_error (GRUB_ERR_BAD_FS, "XFS filesystem has unsupported " + "incompatible features"); + return 0; + } + return 1; + } + else if ((data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_NUMBITS)) == + grub_cpu_to_be16_compile_time(XFS_SB_VERSION_4)) + { + grub_dprintf("xfs", "XFS v4 superblock detected\n"); + if (!(data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_DIRV2BIT))) + { + grub_error (GRUB_ERR_BAD_FS, "XFS filesystem without V2 directories " + "is unsupported"); + return 0; + } + if (data->sblock.version & grub_cpu_to_be16_compile_time(~XFS_SB_VERSION_BITS_SUPPORTED) || + (data->sblock.version & grub_cpu_to_be16_compile_time(XFS_SB_VERSION_MOREBITSBIT) && + data->sblock.features2 & grub_cpu_to_be16_compile_time(~XFS_SB_VERSION2_BITS_SUPPORTED))) + { + grub_error (GRUB_ERR_BAD_FS, "XFS filesystem has unsupported version " + "bits"); + return 0; + } + return 1; + } + + grub_error (GRUB_ERR_BAD_FS, "unsupported XFS filesystem version"); + return 0; +} + +static int +grub_xfs_sb_needs_repair (struct grub_xfs_data *data) +{ + return ((data->sblock.version & + grub_cpu_to_be16_compile_time (XFS_SB_VERSION_NUMBITS)) == + grub_cpu_to_be16_compile_time (XFS_SB_VERSION_5) && + (data->sblock.sb_features_incompat & + grub_cpu_to_be32_compile_time (XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR))); +} + +/* Filetype information as used in inodes. */ +#define FILETYPE_INO_MASK 0170000 +#define FILETYPE_INO_REG 0100000 +#define FILETYPE_INO_DIRECTORY 0040000 +#define FILETYPE_INO_SYMLINK 0120000 + +static inline int +GRUB_XFS_INO_AGBITS(struct grub_xfs_data *data) +{ + return ((data)->sblock.log2_agblk + (data)->sblock.log2_inop); +} + +static inline grub_uint64_t +GRUB_XFS_INO_INOINAG (struct grub_xfs_data *data, + grub_uint64_t ino) +{ + return (ino & ((1LL << GRUB_XFS_INO_AGBITS (data)) - 1)); +} + +static inline grub_uint64_t +GRUB_XFS_INO_AG (struct grub_xfs_data *data, + grub_uint64_t ino) +{ + return (ino >> GRUB_XFS_INO_AGBITS (data)); +} + +static inline grub_disk_addr_t +GRUB_XFS_FSB_TO_BLOCK (struct grub_xfs_data *data, grub_disk_addr_t fsb) +{ + return ((fsb >> data->sblock.log2_agblk) * data->agsize + + (fsb & ((1LL << data->sblock.log2_agblk) - 1))); +} + +static inline grub_uint64_t +GRUB_XFS_EXTENT_OFFSET (struct grub_xfs_extent *exts, int ex) +{ + return ((grub_be_to_cpu32 (exts[ex].raw[0]) & ~(1 << 31)) << 23 + | grub_be_to_cpu32 (exts[ex].raw[1]) >> 9); +} + +static inline grub_uint64_t +GRUB_XFS_EXTENT_BLOCK (struct grub_xfs_extent *exts, int ex) +{ + return ((grub_uint64_t) (grub_be_to_cpu32 (exts[ex].raw[1]) + & (0x1ff)) << 43 + | (grub_uint64_t) grub_be_to_cpu32 (exts[ex].raw[2]) << 11 + | grub_be_to_cpu32 (exts[ex].raw[3]) >> 21); +} + +static inline grub_uint64_t +GRUB_XFS_EXTENT_SIZE (struct grub_xfs_extent *exts, int ex) +{ + return (grub_be_to_cpu32 (exts[ex].raw[3]) & ((1 << 21) - 1)); +} + +static inline grub_uint64_t +grub_xfs_inode_block (struct grub_xfs_data *data, + grub_uint64_t ino) +{ + long long int inoinag = GRUB_XFS_INO_INOINAG (data, ino); + long long ag = GRUB_XFS_INO_AG (data, ino); + long long block; + + block = (inoinag >> data->sblock.log2_inop) + ag * data->agsize; + block <<= (data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS); + return block; +} + + +static inline int +grub_xfs_inode_offset (struct grub_xfs_data *data, + grub_uint64_t ino) +{ + int inoag = GRUB_XFS_INO_INOINAG (data, ino); + return ((inoag & ((1 << data->sblock.log2_inop) - 1)) << + data->sblock.log2_inode); +} + +static inline grub_size_t +grub_xfs_inode_size(struct grub_xfs_data *data) +{ + return (grub_size_t)1 << data->sblock.log2_inode; +} + +/* + * Returns size occupied by XFS inode stored in memory - we store struct + * grub_fshelp_node there but on disk inode size may be actually larger than + * struct grub_xfs_inode so we need to account for that so that we can read + * from disk directly into in-memory structure. + */ +static inline grub_size_t +grub_xfs_fshelp_size(struct grub_xfs_data *data) +{ + return sizeof (struct grub_fshelp_node) - sizeof (struct grub_xfs_inode) + + grub_xfs_inode_size(data); +} + +/* This should return void * but XFS code is error-prone with alignment, so + return char to retain cast-align. + */ +static char * +grub_xfs_inode_data(struct grub_xfs_inode *inode) +{ + if (inode->version <= 2) + return ((char *)inode) + XFS_V2_INODE_SIZE; + return ((char *)inode) + XFS_V3_INODE_SIZE; +} + +static struct grub_xfs_dir_entry * +grub_xfs_inline_de(struct grub_xfs_dir_header *head) +{ + /* + With small inode numbers the header is 4 bytes smaller because of + smaller parent pointer + */ + return (struct grub_xfs_dir_entry *) + (((char *) head) + sizeof(struct grub_xfs_dir_header) - + (head->largeino ? 0 : sizeof(grub_uint32_t))); +} + +static grub_uint8_t * +grub_xfs_inline_de_inopos(struct grub_xfs_data *data, + struct grub_xfs_dir_entry *de) +{ + return ((grub_uint8_t *)(de + 1)) + de->len - 1 + (data->hasftype ? 1 : 0); +} + +static struct grub_xfs_dir_entry * +grub_xfs_inline_next_de(struct grub_xfs_data *data, + struct grub_xfs_dir_header *head, + struct grub_xfs_dir_entry *de) +{ + char *p = (char *)de + sizeof(struct grub_xfs_dir_entry) - 1 + de->len; + + p += head->largeino ? sizeof(grub_uint64_t) : sizeof(grub_uint32_t); + if (data->hasftype) + p++; + + return (struct grub_xfs_dir_entry *)p; +} + +static struct grub_xfs_dirblock_tail * +grub_xfs_dir_tail(struct grub_xfs_data *data, void *dirblock) +{ + int dirblksize = 1 << (data->sblock.log2_bsize + data->sblock.log2_dirblk); + + return (struct grub_xfs_dirblock_tail *) + ((char *)dirblock + dirblksize - sizeof (struct grub_xfs_dirblock_tail)); +} + +static struct grub_xfs_dir2_entry * +grub_xfs_first_de(struct grub_xfs_data *data, void *dirblock) +{ + if (data->hascrc) + return (struct grub_xfs_dir2_entry *)((char *)dirblock + 64); + return (struct grub_xfs_dir2_entry *)((char *)dirblock + 16); +} + +static struct grub_xfs_dir2_entry * +grub_xfs_next_de(struct grub_xfs_data *data, struct grub_xfs_dir2_entry *de) +{ + int size = sizeof (struct grub_xfs_dir2_entry) + de->len + 2 /* Tag */; + + if (data->hasftype) + size++; /* File type */ + return (struct grub_xfs_dir2_entry *)(((char *)de) + ALIGN_UP(size, 8)); +} + +/* This should return void * but XFS code is error-prone with alignment, so + return char to retain cast-align. + */ +static char * +grub_xfs_btree_keys(struct grub_xfs_data *data, + struct grub_xfs_btree_node *leaf) +{ + char *keys = (char *)(leaf + 1); + + if (data->hascrc) + keys += 48; /* skip crc, uuid, ... */ + return keys; +} + +static grub_err_t +grub_xfs_read_inode (struct grub_xfs_data *data, grub_uint64_t ino, + struct grub_xfs_inode *inode) +{ + grub_uint64_t block = grub_xfs_inode_block (data, ino); + int offset = grub_xfs_inode_offset (data, ino); + + grub_dprintf("xfs", "Reading inode (%" PRIuGRUB_UINT64_T ") - %" PRIuGRUB_UINT64_T ", %d\n", + ino, block, offset); + /* Read the inode. */ + if (grub_disk_read (data->disk, block, offset, grub_xfs_inode_size(data), + inode)) + return grub_errno; + + if (grub_strncmp ((char *) inode->magic, "IN", 2)) + return grub_error (GRUB_ERR_BAD_FS, "not a correct XFS inode"); + + return 0; +} + +static grub_uint64_t +get_fsb (const void *keys, int idx) +{ + const char *p = (const char *) keys + sizeof(grub_uint64_t) * idx; + return grub_be_to_cpu64 (grub_get_unaligned64 (p)); +} + +static int +grub_xfs_inode_has_large_extent_counts (const struct grub_xfs_inode *inode) +{ + return inode->version >= 3 && + (inode->flags2 & grub_cpu_to_be64_compile_time (XFS_DIFLAG2_NREXT64)); +} + +static grub_uint64_t +grub_xfs_get_inode_nextents (struct grub_xfs_inode *inode) +{ + return (grub_xfs_inode_has_large_extent_counts (inode)) ? + grub_be_to_cpu64 (inode->nextents_big) : + grub_be_to_cpu32 (inode->nextents); +} + +static grub_disk_addr_t +grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) +{ + struct grub_xfs_btree_node *leaf = 0; + grub_uint64_t ex, nrec; + struct grub_xfs_extent *exts; + grub_uint64_t ret = 0; + + if (node->inode.format == XFS_INODE_FORMAT_BTREE) + { + struct grub_xfs_btree_root *root; + const char *keys; + int recoffset; + + leaf = grub_malloc (node->data->bsize); + if (leaf == 0) + return 0; + + root = (struct grub_xfs_btree_root *) grub_xfs_inode_data(&node->inode); + nrec = grub_be_to_cpu16 (root->numrecs); + keys = (char *) &root->keys[0]; + if (node->inode.fork_offset) + recoffset = (node->inode.fork_offset - 1) / 2; + else + recoffset = (grub_xfs_inode_size(node->data) + - ((char *) keys - (char *) &node->inode)) + / (2 * sizeof (grub_uint64_t)); + do + { + grub_uint64_t i; + grub_addr_t keys_end, data_end; + + if (grub_mul (sizeof (grub_uint64_t), nrec, &keys_end) || + grub_add ((grub_addr_t) keys, keys_end, &keys_end) || + grub_add ((grub_addr_t) node->data, node->data->data_size, &data_end) || + keys_end > data_end) + { + grub_error (GRUB_ERR_BAD_FS, "invalid number of XFS root keys"); + grub_free (leaf); + return 0; + } + + for (i = 0; i < nrec; i++) + { + if (fileblock < get_fsb(keys, i)) + break; + } + + /* Sparse block. */ + if (i == 0) + { + grub_free (leaf); + return 0; + } + + if (grub_disk_read (node->data->disk, + GRUB_XFS_FSB_TO_BLOCK (node->data, get_fsb (keys, i - 1 + recoffset)) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS), + 0, node->data->bsize, leaf)) + { + grub_free (leaf); + return 0; + } + + if ((!node->data->hascrc && + grub_strncmp ((char *) leaf->magic, "BMAP", 4)) || + (node->data->hascrc && + grub_strncmp ((char *) leaf->magic, "BMA3", 4))) + { + grub_free (leaf); + grub_error (GRUB_ERR_BAD_FS, "not a correct XFS BMAP node"); + return 0; + } + + nrec = grub_be_to_cpu16 (leaf->numrecs); + keys = grub_xfs_btree_keys(node->data, leaf); + recoffset = ((node->data->bsize - ((char *) keys + - (char *) leaf)) + / (2 * sizeof (grub_uint64_t))); + } + while (leaf->level); + exts = (struct grub_xfs_extent *) keys; + } + else if (node->inode.format == XFS_INODE_FORMAT_EXT) + { + grub_addr_t exts_end = 0; + grub_addr_t data_end = 0; + + nrec = grub_xfs_get_inode_nextents (&node->inode); + exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode); + + if (grub_mul (sizeof (struct grub_xfs_extent), nrec, &exts_end) || + grub_add ((grub_addr_t) node->data, exts_end, &exts_end) || + grub_add ((grub_addr_t) node->data, node->data->data_size, &data_end) || + exts_end > data_end) + { + grub_error (GRUB_ERR_BAD_FS, "invalid number of XFS extents"); + return 0; + } + } + else + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "XFS does not support inode format %d yet", + node->inode.format); + return 0; + } + + /* Iterate over each extent to figure out which extent has + the block we are looking for. */ + for (ex = 0; ex < nrec; ex++) + { + grub_uint64_t start = GRUB_XFS_EXTENT_BLOCK (exts, ex); + grub_uint64_t offset = GRUB_XFS_EXTENT_OFFSET (exts, ex); + grub_uint64_t size = GRUB_XFS_EXTENT_SIZE (exts, ex); + + /* Sparse block. */ + if (fileblock < offset) + break; + else if (fileblock < offset + size) + { + ret = (fileblock - offset + start); + break; + } + } + + grub_free (leaf); + + return GRUB_XFS_FSB_TO_BLOCK(node->data, ret); +} + + +/* Read LEN bytes from the file described by DATA starting with byte + POS. Return the amount of read bytes in READ. */ +static grub_ssize_t +grub_xfs_read_file (grub_fshelp_node_t node, + grub_disk_read_hook_t read_hook, void *read_hook_data, + grub_off_t pos, grub_size_t len, char *buf, grub_uint32_t header_size) +{ + return grub_fshelp_read_file (node->data->disk, node, + read_hook, read_hook_data, + pos, len, buf, grub_xfs_read_block, + grub_be_to_cpu64 (node->inode.size) + header_size, + node->data->sblock.log2_bsize + - GRUB_DISK_SECTOR_BITS, 0); +} + + +static char * +grub_xfs_read_symlink (grub_fshelp_node_t node) +{ + grub_ssize_t size = grub_be_to_cpu64 (node->inode.size); + grub_size_t sz; + + if (size < 0) + { + grub_error (GRUB_ERR_BAD_FS, "invalid symlink"); + return 0; + } + + switch (node->inode.format) + { + case XFS_INODE_FORMAT_INO: + return grub_strndup (grub_xfs_inode_data(&node->inode), size); + + case XFS_INODE_FORMAT_EXT: + { + char *symlink; + grub_ssize_t numread; + int off = 0; + + if (node->data->hascrc) + off = 56; + + if (grub_add (size, 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink size overflow")); + return 0; + } + symlink = grub_malloc (sz); + if (!symlink) + return 0; + + node->inode.size = grub_be_to_cpu64 (size + off); + numread = grub_xfs_read_file (node, 0, 0, off, size, symlink, off); + if (numread != size) + { + grub_free (symlink); + return 0; + } + symlink[size] = '\0'; + return symlink; + } + } + + return 0; +} + + +static enum grub_fshelp_filetype +grub_xfs_mode_to_filetype (grub_uint16_t mode) +{ + if ((grub_be_to_cpu16 (mode) + & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY) + return GRUB_FSHELP_DIR; + else if ((grub_be_to_cpu16 (mode) + & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK) + return GRUB_FSHELP_SYMLINK; + else if ((grub_be_to_cpu16 (mode) + & FILETYPE_INO_MASK) == FILETYPE_INO_REG) + return GRUB_FSHELP_REG; + return GRUB_FSHELP_UNKNOWN; +} + + +/* Context for grub_xfs_iterate_dir. */ +struct grub_xfs_iterate_dir_ctx +{ + grub_fshelp_iterate_dir_hook_t hook; + void *hook_data; + struct grub_fshelp_node *diro; +}; + +/* Helper for grub_xfs_iterate_dir. */ +static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename, + struct grub_xfs_iterate_dir_ctx *ctx) +{ + struct grub_fshelp_node *fdiro; + grub_err_t err; + grub_size_t sz; + + if (grub_add (grub_xfs_fshelp_size(ctx->diro->data), 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory data size overflow")); + grub_print_error (); + return 0; + } + fdiro = grub_malloc (sz); + if (!fdiro) + { + grub_print_error (); + return 0; + } + + /* The inode should be read, otherwise the filetype can + not be determined. */ + fdiro->ino = ino; + fdiro->inode_read = 1; + fdiro->data = ctx->diro->data; + err = grub_xfs_read_inode (ctx->diro->data, ino, &fdiro->inode); + if (err) + { + grub_print_error (); + grub_free (fdiro); + return 0; + } + + return ctx->hook (filename, grub_xfs_mode_to_filetype (fdiro->inode.mode), + fdiro, ctx->hook_data); +} + +static int +grub_xfs_iterate_dir (grub_fshelp_node_t dir, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) +{ + struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir; + struct grub_xfs_iterate_dir_ctx ctx = { + .hook = hook, + .hook_data = hook_data, + .diro = diro + }; + + switch (diro->inode.format) + { + case XFS_INODE_FORMAT_INO: + { + struct grub_xfs_dir_header *head = (struct grub_xfs_dir_header *) grub_xfs_inode_data(&diro->inode); + struct grub_xfs_dir_entry *de = grub_xfs_inline_de(head); + int smallino = !head->largeino; + int i; + grub_uint64_t parent; + + /* If small inode numbers are used to pack the direntry, the + parent inode number is small too. */ + if (smallino) + parent = grub_be_to_cpu32 (head->parent.i4); + else + parent = grub_be_to_cpu64 (head->parent.i8); + + /* Synthesize the direntries for `.' and `..'. */ + if (iterate_dir_call_hook (diro->ino, ".", &ctx)) + return 1; + + if (iterate_dir_call_hook (parent, "..", &ctx)) + return 1; + + for (i = 0; i < head->count && + (grub_uint8_t *) de < ((grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)); i++) + { + grub_uint64_t ino; + grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de); + grub_uint8_t c; + + if ((inopos + (smallino ? 4 : 8)) > (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)) + { + grub_error (GRUB_ERR_BAD_FS, "invalid XFS inode"); + return 0; + } + + + /* inopos might be unaligned. */ + if (smallino) + ino = (((grub_uint32_t) inopos[0]) << 24) + | (((grub_uint32_t) inopos[1]) << 16) + | (((grub_uint32_t) inopos[2]) << 8) + | (((grub_uint32_t) inopos[3]) << 0); + else + ino = (((grub_uint64_t) inopos[0]) << 56) + | (((grub_uint64_t) inopos[1]) << 48) + | (((grub_uint64_t) inopos[2]) << 40) + | (((grub_uint64_t) inopos[3]) << 32) + | (((grub_uint64_t) inopos[4]) << 24) + | (((grub_uint64_t) inopos[5]) << 16) + | (((grub_uint64_t) inopos[6]) << 8) + | (((grub_uint64_t) inopos[7]) << 0); + + c = de->name[de->len]; + de->name[de->len] = '\0'; + if (iterate_dir_call_hook (ino, de->name, &ctx)) + { + de->name[de->len] = c; + return 1; + } + de->name[de->len] = c; + + de = grub_xfs_inline_next_de(dir->data, head, de); + } + break; + } + + case XFS_INODE_FORMAT_BTREE: + case XFS_INODE_FORMAT_EXT: + { + grub_ssize_t numread; + char *dirblock; + grub_uint64_t blk; + int dirblk_size, dirblk_log2; + + dirblk_log2 = (dir->data->sblock.log2_bsize + + dir->data->sblock.log2_dirblk); + dirblk_size = 1 << dirblk_log2; + + dirblock = grub_malloc (dirblk_size); + if (! dirblock) + return 0; + + /* Iterate over every block the directory has. */ + for (blk = 0; + blk < (grub_be_to_cpu64 (dir->inode.size) + >> dirblk_log2); + blk++) + { + struct grub_xfs_dir2_entry *direntry = + grub_xfs_first_de(dir->data, dirblock); + int entries = -1; + char *end = dirblock + dirblk_size; + grub_uint32_t magic; + + numread = grub_xfs_read_file (dir, 0, 0, + blk << dirblk_log2, + dirblk_size, dirblock, 0); + if (numread != dirblk_size) + { + grub_free (dirblock); + return 0; + } + + /* + * If this data block isn't actually part of the extent list then + * grub_xfs_read_file() returns a block of zeros. So, if the magic + * number field is all zeros then this block should be skipped. + */ + magic = *(grub_uint32_t *)(void *) dirblock; + if (!magic) + continue; + + /* + * Leaf and tail information are only in the data block if the number + * of extents is 1. + */ + if (grub_xfs_get_inode_nextents (&dir->inode) == 1) + { + struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock); + + end = (char *) tail; + + /* Subtract the space used by leaf nodes. */ + end -= grub_be_to_cpu32 (tail->leaf_count) * sizeof (struct grub_xfs_dir_leaf_entry); + + entries = grub_be_to_cpu32 (tail->leaf_count) - grub_be_to_cpu32 (tail->leaf_stale); + + if (!entries) + continue; + } + + /* Iterate over all entries within this block. */ + while ((char *) direntry < (char *) end) + { + grub_uint8_t *freetag; + char *filename; + + freetag = (grub_uint8_t *) direntry; + + if (grub_get_unaligned16 (freetag) == 0XFFFF) + { + grub_uint8_t *skip = (freetag + sizeof (grub_uint16_t)); + + /* This entry is not used, go to the next one. */ + direntry = (struct grub_xfs_dir2_entry *) + (((char *)direntry) + + grub_be_to_cpu16 (grub_get_unaligned16 (skip))); + + continue; + } + + filename = (char *)(direntry + 1); + if (filename + direntry->len + 1 > (char *) end) + { + grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); + return 0; + } + + /* The byte after the filename is for the filetype, padding, or + tag, which is not used by GRUB. So it can be overwritten. */ + filename[direntry->len] = '\0'; + + if (iterate_dir_call_hook (grub_be_to_cpu64(direntry->inode), + filename, &ctx)) + { + grub_free (dirblock); + return 1; + } + + /* + * The expected number of directory entries is only tracked for the + * single extent case. + */ + if (grub_xfs_get_inode_nextents (&dir->inode) == 1) + { + /* Check if last direntry in this block is reached. */ + entries--; + if (!entries) + break; + } + + /* Select the next directory entry. */ + direntry = grub_xfs_next_de(dir->data, direntry); + } + } + grub_free (dirblock); + break; + } + + default: + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "XFS does not support inode format %d yet", + diro->inode.format); + } + return 0; +} + + +static struct grub_xfs_data * +grub_xfs_mount (grub_disk_t disk) +{ + struct grub_xfs_data *data = 0; + grub_size_t sz; + + data = grub_zalloc (sizeof (struct grub_xfs_data)); + if (!data) + return 0; + + data->data_size = sizeof (struct grub_xfs_data); + + grub_dprintf("xfs", "Reading sb\n"); + /* Read the superblock. */ + if (grub_disk_read (disk, 0, 0, + sizeof (struct grub_xfs_sblock), &data->sblock)) + goto fail; + + if (!grub_xfs_sb_valid(data)) + goto fail; + + if (grub_xfs_sb_needs_repair (data)) + grub_dprintf ("xfs", "XFS filesystem needs repair, boot may fail\n"); + + if (grub_add (grub_xfs_inode_size (data), + sizeof (struct grub_xfs_data) - sizeof (struct grub_xfs_inode) + 1, &sz)) + goto fail; + + data = grub_realloc (data, sz); + + if (! data) + goto fail; + + data->data_size = sz; + data->diropen.data = data; + data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino); + data->diropen.inode_read = 1; + data->bsize = grub_be_to_cpu32 (data->sblock.bsize); + data->agsize = grub_be_to_cpu32 (data->sblock.agsize); + data->hasftype = grub_xfs_sb_hasftype(data); + data->hascrc = grub_xfs_sb_hascrc(data); + + data->disk = disk; + data->pos = 0; + grub_dprintf("xfs", "Reading root ino %" PRIuGRUB_UINT64_T "\n", + grub_cpu_to_be64(data->sblock.rootino)); + + grub_xfs_read_inode (data, data->diropen.ino, &data->diropen.inode); + + return data; + fail: + + if (grub_errno == GRUB_ERR_OUT_OF_RANGE || grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_FS, "not an XFS filesystem"); + + grub_free (data); + + return 0; +} + +/* Context for grub_xfs_dir. */ +struct grub_xfs_dir_ctx +{ + grub_fs_dir_hook_t hook; + void *hook_data; +}; + +/* Bigtime inodes helpers. */ +#define XFS_BIGTIME_EPOCH_OFFSET (-(grub_int64_t) GRUB_INT32_MIN) + +static int grub_xfs_inode_has_bigtime (const struct grub_xfs_inode *inode) +{ + return inode->version >= 3 && + (inode->flags2 & grub_cpu_to_be64_compile_time (XFS_DIFLAG2_BIGTIME)); +} + +static grub_int64_t +grub_xfs_get_inode_time (struct grub_xfs_inode *inode) +{ + struct grub_xfs_time_legacy *lts; + + if (grub_xfs_inode_has_bigtime (inode)) + return grub_divmod64 (grub_be_to_cpu64 (inode->mtime), NSEC_PER_SEC, NULL) - XFS_BIGTIME_EPOCH_OFFSET; + + lts = (struct grub_xfs_time_legacy *) &inode->mtime; + return grub_be_to_cpu32 (lts->sec); +} + +/* Helper for grub_xfs_dir. */ +static int +grub_xfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype, + grub_fshelp_node_t node, void *data) +{ + struct grub_xfs_dir_ctx *ctx = data; + struct grub_dirhook_info info; + + grub_memset (&info, 0, sizeof (info)); + if (node->inode_read) + { + info.mtimeset = 1; + info.mtime = grub_xfs_get_inode_time (&node->inode); + } + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + grub_free (node); + return ctx->hook (filename, &info, ctx->hook_data); +} + +static grub_err_t +grub_xfs_dir (grub_device_t device, const char *path, + grub_fs_dir_hook_t hook, void *hook_data) +{ + struct grub_xfs_dir_ctx ctx = { hook, hook_data }; + struct grub_xfs_data *data = 0; + struct grub_fshelp_node *fdiro = 0; + + grub_dl_ref (my_mod); + + data = grub_xfs_mount (device->disk); + if (!data) + goto mount_fail; + + grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_xfs_iterate_dir, + grub_xfs_read_symlink, GRUB_FSHELP_DIR); + if (grub_errno) + goto fail; + + grub_xfs_iterate_dir (fdiro, grub_xfs_dir_iter, &ctx); + + fail: + if (fdiro != &data->diropen) + grub_free (fdiro); + grub_free (data); + + mount_fail: + + grub_dl_unref (my_mod); + + return grub_errno; +} + + +/* Open a file named NAME and initialize FILE. */ +static grub_err_t +grub_xfs_open (struct grub_file *file, const char *name) +{ + struct grub_xfs_data *data; + struct grub_fshelp_node *fdiro = 0; + + grub_dl_ref (my_mod); + + data = grub_xfs_mount (file->device->disk); + if (!data) + goto mount_fail; + + grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_xfs_iterate_dir, + grub_xfs_read_symlink, GRUB_FSHELP_REG); + if (grub_errno) + goto fail; + + if (!fdiro->inode_read) + { + grub_xfs_read_inode (data, fdiro->ino, &fdiro->inode); + if (grub_errno) + goto fail; + } + + if (fdiro != &data->diropen) + { + grub_memcpy (&data->diropen, fdiro, grub_xfs_fshelp_size(data)); + grub_free (fdiro); + } + + file->size = grub_be_to_cpu64 (data->diropen.inode.size); + file->data = data; + file->offset = 0; + + return 0; + + fail: + if (fdiro != &data->diropen) + grub_free (fdiro); + grub_free (data); + + mount_fail: + grub_dl_unref (my_mod); + + return grub_errno; +} + + +static grub_ssize_t +grub_xfs_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_xfs_data *data = + (struct grub_xfs_data *) file->data; + + return grub_xfs_read_file (&data->diropen, + file->read_hook, file->read_hook_data, + file->offset, len, buf, 0); +} + + +static grub_err_t +grub_xfs_close (grub_file_t file) +{ + grub_free (file->data); + + grub_dl_unref (my_mod); + + return GRUB_ERR_NONE; +} + + +static grub_err_t +grub_xfs_label (grub_device_t device, char **label) +{ + struct grub_xfs_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_xfs_mount (disk); + if (data) + *label = grub_strndup ((char *) (data->sblock.label), 12); + else + *label = 0; + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + +static grub_err_t +grub_xfs_uuid (grub_device_t device, char **uuid) +{ + struct grub_xfs_data *data; + grub_disk_t disk = device->disk; + + grub_dl_ref (my_mod); + + data = grub_xfs_mount (disk); + if (data) + { + *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + grub_be_to_cpu16 (data->sblock.uuid[0]), + grub_be_to_cpu16 (data->sblock.uuid[1]), + grub_be_to_cpu16 (data->sblock.uuid[2]), + grub_be_to_cpu16 (data->sblock.uuid[3]), + grub_be_to_cpu16 (data->sblock.uuid[4]), + grub_be_to_cpu16 (data->sblock.uuid[5]), + grub_be_to_cpu16 (data->sblock.uuid[6]), + grub_be_to_cpu16 (data->sblock.uuid[7])); + } + else + *uuid = NULL; + + grub_dl_unref (my_mod); + + grub_free (data); + + return grub_errno; +} + +static struct grub_fs grub_xfs_fs = + { + .name = "xfs", + .fs_dir = grub_xfs_dir, + .fs_open = grub_xfs_open, + .fs_read = grub_xfs_read, + .fs_close = grub_xfs_close, + .fs_label = grub_xfs_label, + .fs_uuid = grub_xfs_uuid, +#ifdef GRUB_UTIL + .reserved_first_sector = 0, + .blocklist_install = 1, +#endif + .next = 0 + }; + +GRUB_MOD_INIT(xfs) +{ + //grub_xfs_fs.mod = mod; + grub_fs_register (&grub_xfs_fs); + my_mod = mod; +} + +GRUB_MOD_FINI(xfs) +{ + grub_fs_unregister (&grub_xfs_fs); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/zfs/zfs_lz4.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/zfs/zfs_lz4.c new file mode 100644 index 0000000..e72f2fe --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/fs/zfs/zfs_lz4.c @@ -0,0 +1,285 @@ +/* + * LZ4 - Fast LZ compression algorithm + * Header File + * Copyright (C) 2011-2013, Yann Collet. + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at : + * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html + * - LZ4 source repository : http://code.google.com/p/lz4/ + */ + +#include +#include +#include +#include + +int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, + int isize, int maxOutputSize); + +/* + * CPU Feature Detection + */ + +/* 32 or 64 bits ? */ +#if (GRUB_CPU_SIZEOF_VOID_P == 8) +#define LZ4_ARCH64 1 +#else +#define LZ4_ARCH64 0 +#endif + +/* + * Compiler Options + */ + + +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#if (GCC_VERSION >= 302) || (defined (__INTEL_COMPILER) && __INTEL_COMPILER >= 800) || defined(__clang__) +#define expect(expr, value) (__builtin_expect((expr), (value))) +#else +#define expect(expr, value) (expr) +#endif + +#define likely(expr) expect((expr) != 0, 1) +#define unlikely(expr) expect((expr) != 0, 0) + +/* Basic types */ +#define BYTE grub_uint8_t +#define U16 grub_uint16_t +#define U32 grub_uint32_t +#define S32 grub_int32_t +#define U64 grub_uint64_t + +typedef struct _U16_S { + U16 v; +} GRUB_PACKED U16_S; +typedef struct _U32_S { + U32 v; +} GRUB_PACKED U32_S; +typedef struct _U64_S { + U64 v; +} GRUB_PACKED U64_S; + +#define A64(x) (((U64_S *)(x))->v) +#define A32(x) (((U32_S *)(x))->v) +#define A16(x) (((U16_S *)(x))->v) + +/* + * Constants + */ +#define MINMATCH 4 + +#define COPYLENGTH 8 +#define LASTLITERALS 5 + +#define ML_BITS 4 +#define ML_MASK ((1U< s_len) + return grub_error(GRUB_ERR_BAD_FS,"lz4 decompression failed."); + + /* + * Returns 0 on success (decompression function returned non-negative) + * and appropriate error on failure (decompression function returned negative). + */ + return (LZ4_uncompress_unknownOutputSize((char*)s_start + 4, d_start, bufsiz, + d_len) < 0)?grub_error(GRUB_ERR_BAD_FS,"lz4 decompression failed."):0; +} + +int +LZ4_uncompress_unknownOutputSize(const char *source, + char *dest, int isize, int maxOutputSize) +{ + /* Local Variables */ + const BYTE * ip = (const BYTE *) source; + const BYTE *const iend = ip + isize; + const BYTE * ref; + + BYTE * op = (BYTE *) dest; + BYTE *const oend = op + maxOutputSize; + BYTE *cpy; + + grub_size_t dec[] = { 0, 3, 2, 3, 0, 0, 0, 0 }; + + /* Main Loop */ + while (ip < iend) { + BYTE token; + int length; + + /* get runlength */ + token = *ip++; + if ((length = (token >> ML_BITS)) == RUN_MASK) { + int s = 255; + while ((ip < iend) && (s == 255)) { + s = *ip++; + length += s; + } + } + /* copy literals */ + if ((grub_addr_t) length > ~(grub_addr_t)op) + goto _output_error; + cpy = op + length; + if ((cpy > oend - COPYLENGTH) || + (ip + length > iend - COPYLENGTH)) { + if (cpy > oend) + /* + * Error: request to write beyond destination + * buffer. + */ + goto _output_error; + if (ip + length > iend) + /* + * Error : request to read beyond source + * buffer. + */ + goto _output_error; + grub_memcpy(op, ip, length); + op += length; + ip += length; + if (ip < iend) + /* Error : LZ4 format violation */ + goto _output_error; + /* Necessarily EOF, due to parsing restrictions. */ + break; + } + LZ4_WILDCOPY(ip, op, cpy); + ip -= (op - cpy); + op = cpy; + + /* get offset */ + LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); + ip += 2; + if (ref < (BYTE * const) dest) + /* + * Error: offset creates reference outside of + * destination buffer. + */ + goto _output_error; + + /* get matchlength */ + if ((length = (token & ML_MASK)) == ML_MASK) { + while (ip < iend) { + int s = *ip++; + length += s; + if (s == 255) + continue; + break; + } + } + /* copy repeated sequence */ + if unlikely(op - ref < STEPSIZE) { +#if LZ4_ARCH64 + grub_size_t dec2table[] = { 0, 0, 0, -1, 0, 1, 2, 3 }; + grub_size_t dec2 = dec2table[op - ref]; +#else + const int dec2 = 0; +#endif + *op++ = *ref++; + *op++ = *ref++; + *op++ = *ref++; + *op++ = *ref++; + ref -= dec[op - ref]; + A32(op) = A32(ref); + op += STEPSIZE - 4; + ref -= dec2; + } else { + LZ4_COPYSTEP(ref, op); + } + cpy = op + length - (STEPSIZE - 4); + if (cpy > oend - COPYLENGTH) { + if (cpy > oend) + /* + * Error: request to write outside of + * destination buffer. + */ + goto _output_error; + LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); + while (op < cpy) + *op++ = *ref++; + op = cpy; + if (op == oend) + /* + * Check EOF (should never happen, since last + * 5 bytes are supposed to be literals). + */ + break; + continue; + } + LZ4_SECURECOPY(ref, op, cpy); + op = cpy; /* correction */ + } + + /* end of decoding */ + return (int)(((char *)op) - dest); + + /* write overflow error detected */ + _output_error: + return (int)(-(((char *)ip) - source)); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gfxmenu.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gfxmenu.c new file mode 100644 index 0000000..bc0e562 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gfxmenu.c @@ -0,0 +1,165 @@ +/* gfxmenu.c - Graphical menu interface controller. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +extern int g_ventoy_menu_refresh; + +static grub_gfxmenu_view_t cached_view; + +static void +grub_gfxmenu_viewer_fini (void *data __attribute__ ((unused))) +{ +} + +/* FIXME: Previously 't' changed to text menu is it necessary? */ +static grub_err_t +grub_gfxmenu_try (int entry, grub_menu_t menu, int nested) +{ + int force_refresh = 0; + grub_gfxmenu_view_t view = NULL; + const char *theme_path; + char *full_theme_path = 0; + struct grub_menu_viewer *instance; + grub_err_t err; + struct grub_video_mode_info mode_info; + + theme_path = grub_env_get ("theme"); + if (! theme_path) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), + "theme"); + + err = grub_video_get_info (&mode_info); + if (err) + return err; + + instance = grub_zalloc (sizeof (*instance)); + if (!instance) + return grub_errno; + + if (theme_path[0] != '/' && theme_path[0] != '(') + { + const char *prefix; + prefix = grub_env_get ("prefix"); + full_theme_path = grub_xasprintf ("%s/themes/%s", + prefix, + theme_path); + } + + if (g_ventoy_menu_refresh) + { + g_ventoy_menu_refresh = 0; + force_refresh = 1; + } + + if (force_refresh || + !cached_view || grub_strcmp (cached_view->theme_path, + full_theme_path ? : theme_path) != 0 + || cached_view->screen.width != mode_info.width + || cached_view->screen.height != mode_info.height) + { + grub_gfxmenu_view_destroy (cached_view); + /* Create the view. */ + cached_view = grub_gfxmenu_view_new (full_theme_path ? : theme_path, + mode_info.width, + mode_info.height); + } + grub_free (full_theme_path); + + if (! cached_view) + { + grub_free (instance); + return grub_errno; + } + + view = cached_view; + + view->double_repaint = (mode_info.mode_type + & GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED) + && !(mode_info.mode_type & GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP); + view->selected = entry; + view->menu = menu; + view->nested = nested; + view->first_timeout = -1; + if (menu->size) + view->menu_title_offset = grub_zalloc (sizeof (*view->menu_title_offset) * menu->size); + + grub_video_set_viewport (0, 0, mode_info.width, mode_info.height); + if (view->double_repaint) + { + grub_video_swap_buffers (); + grub_video_set_viewport (0, 0, mode_info.width, mode_info.height); + } + + grub_gfxmenu_view_draw (view); + + instance->data = view; + instance->set_chosen_entry = grub_gfxmenu_set_chosen_entry; + instance->fini = grub_gfxmenu_viewer_fini; + instance->print_timeout = grub_gfxmenu_print_timeout; + instance->clear_timeout = grub_gfxmenu_clear_timeout; + if (view->menu_title_offset) + instance->scroll_chosen_entry = grub_gfxmenu_scroll_chosen_entry; + + grub_menu_register_viewer (instance); + + return GRUB_ERR_NONE; +} + +GRUB_MOD_INIT (gfxmenu) +{ + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_gfxmenu_try_hook && term->fullscreen) + { + term->fullscreen (); + break; + } + + grub_gfxmenu_try_hook = grub_gfxmenu_try; +} + +GRUB_MOD_FINI (gfxmenu) +{ + grub_gfxmenu_view_destroy (cached_view); + grub_gfxmenu_try_hook = NULL; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c new file mode 100644 index 0000000..432089e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_label.c @@ -0,0 +1,324 @@ +/* gui_label.c - GUI component to display a line of text. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +extern int g_ventoy_memdisk_mode; +extern int g_ventoy_iso_raw; +extern int g_ventoy_grub2_mode; +extern int g_ventoy_wimboot_mode; +extern int g_ventoy_iso_uefi_drv; +extern char g_ventoy_hotkey_tip[256]; + +static const char *align_options[] = +{ + "left", + "center", + "right", + 0 +}; + +enum align_mode { + align_left, + align_center, + align_right +}; + +struct grub_gui_label +{ + struct grub_gui_component comp; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int visible; + char *text; + char *template; + grub_font_t font; + grub_video_rgba_color_t color; + int value; + int vtoytip; + enum align_mode align; +}; + +typedef struct grub_gui_label *grub_gui_label_t; + +extern const char * g_ventoy_tip_msg1; +extern const char * g_ventoy_tip_msg2; + +static void +label_destroy (void *vself) +{ + grub_gui_label_t self = vself; + grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self); + grub_free (self->text); + grub_free (self->template); + grub_free (self); +} + +static const char * +label_get_id (void *vself) +{ + grub_gui_label_t self = vself; + return self->id; +} + +static int +label_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return grub_strcmp (type, "component") == 0; +} + +static void +label_paint (void *vself, const grub_video_rect_t *region) +{ + const char *text; + grub_gui_label_t self = vself; + + if (! self->visible) + return; + + if (!grub_video_have_common_points (region, &self->bounds)) + return; + + if (self->vtoytip == 1) { + text = g_ventoy_tip_msg1 ? g_ventoy_tip_msg1 : ""; + } else if (self->vtoytip == 2) { + text = g_ventoy_tip_msg2 ? g_ventoy_tip_msg2 : ""; + } else { + text = self->text; + } + + /* Calculate the starting x coordinate. */ + int left_x; + if (self->align == align_left) + left_x = 0; + else if (self->align == align_center) + left_x = (self->bounds.width + - grub_font_get_string_width (self->font, text)) / 2; + else if (self->align == align_right) + left_x = (self->bounds.width + - grub_font_get_string_width (self->font, text)); + else + return; /* Invalid alignment. */ + + if (left_x < 0 || left_x > (int) self->bounds.width) + left_x = 0; + + grub_video_rect_t vpsave; + grub_gui_set_viewport (&self->bounds, &vpsave); + grub_font_draw_string (text, + self->font, + grub_video_map_rgba_color (self->color), + left_x, + grub_font_get_ascent (self->font)); + grub_gui_restore_viewport (&vpsave); +} + +static void +label_set_parent (void *vself, grub_gui_container_t parent) +{ + grub_gui_label_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +label_get_parent (void *vself) +{ + grub_gui_label_t self = vself; + return self->parent; +} + +static void +label_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + grub_gui_label_t self = vself; + self->bounds = *bounds; +} + +static void +label_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + grub_gui_label_t self = vself; + *bounds = self->bounds; +} + +static void +label_get_minimal_size (void *vself, unsigned *width, unsigned *height) +{ + grub_gui_label_t self = vself; + *width = grub_font_get_string_width (self->font, self->text); + *height = (grub_font_get_ascent (self->font) + + grub_font_get_descent (self->font)); +} + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static void +label_set_state (void *vself, int visible, int start __attribute__ ((unused)), + int current, int end __attribute__ ((unused))) +{ + grub_gui_label_t self = vself; + self->value = -current; + self->visible = visible; + grub_free (self->text); + self->text = grub_xasprintf (self->template ? : "%d", self->value); +} + +static grub_err_t +label_set_property (void *vself, const char *name, const char *value) +{ + grub_gui_label_t self = vself; + if (grub_strcmp (name, "text") == 0) + { + grub_free (self->text); + grub_free (self->template); + if (! value) + { + self->template = NULL; + self->text = grub_strdup (""); + } + else + { + if (grub_strcmp (value, "@KEYMAP_LONG@") == 0) + value = _("Press enter to boot the selected OS, " + "`e' to edit the commands before booting " + "or `c' for a command-line. ESC to return previous menu."); + else if (grub_strcmp (value, "@KEYMAP_MIDDLE@") == 0) + value = _("Press enter to boot the selected OS, " + "`e' to edit the commands before booting " + "or `c' for a command-line."); + else if (grub_strcmp (value, "@KEYMAP_SHORT@") == 0) + value = _("enter: boot, `e': options, `c': cmd-line"); + /* FIXME: Add more templates here if needed. */ + + else if (grub_strcmp (value, "@VTOY_MEM_DISK@") == 0) { + value = g_ventoy_memdisk_mode ? grub_env_get("VTOY_MEM_DISK_STR") : " "; + } + else if (grub_strcmp (value, "@VTOY_ISO_RAW@") == 0) { + value = g_ventoy_iso_raw ? grub_env_get("VTOY_ISO_RAW_STR") : " "; + } + else if (grub_strcmp (value, "@VTOY_GRUB2_MODE@") == 0) { + value = g_ventoy_grub2_mode ? grub_env_get("VTOY_GRUB2_MODE_STR") : " "; + } + else if (grub_strcmp (value, "@VTOY_WIMBOOT_MODE@") == 0) { + value = g_ventoy_wimboot_mode ? grub_env_get("VTOY_WIMBOOT_MODE_STR") : " "; + } + else if (grub_strcmp (value, "@VTOY_ISO_UEFI_DRV@") == 0) { + value = g_ventoy_iso_uefi_drv ? grub_env_get("VTOY_ISO_UEFI_DRV_STR") : " "; + } + else if (grub_strcmp (value, "@VTOY_HOTKEY_TIP@") == 0) { + value = g_ventoy_hotkey_tip; + } else if (value[0] == '@' && value[1] == '@' && value[2]) { + value = grub_env_get(value + 2); + if (!value) + value = " "; + } + + self->template = grub_strdup (value); + self->text = grub_xasprintf (value, self->value); + } + } + else if (grub_strcmp (name, "font") == 0) + { + self->font = grub_font_get (value); + } + else if (grub_strcmp (name, "color") == 0) + { + grub_video_parse_color (value, &self->color); + } + else if (grub_strcmp (name, "align") == 0) + { + int i; + for (i = 0; align_options[i]; i++) + { + if (grub_strcmp (align_options[i], value) == 0) + { + self->align = i; /* Set the alignment mode. */ + break; + } + } + } + else if (grub_strcmp (name, "visible") == 0) + { + self->visible = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_gfxmenu_timeout_unregister ((grub_gui_component_t) self); + grub_free (self->id); + if (value) { + self->id = grub_strdup (value); + if (grub_strcmp(value, "VTOY_MENU_TIP_1") == 0) { + self->vtoytip = 1; + } else if (grub_strcmp(value, "VTOY_MENU_TIP_2") == 0) { + self->vtoytip = 2; + } + } + else + self->id = 0; + if (self->id && grub_strcmp (self->id, GRUB_GFXMENU_TIMEOUT_COMPONENT_ID) + == 0) + grub_gfxmenu_timeout_register ((grub_gui_component_t) self, + label_set_state); + } + return GRUB_ERR_NONE; +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +static struct grub_gui_component_ops label_ops = +{ + .destroy = label_destroy, + .get_id = label_get_id, + .is_instance = label_is_instance, + .paint = label_paint, + .set_parent = label_set_parent, + .get_parent = label_get_parent, + .set_bounds = label_set_bounds, + .get_bounds = label_get_bounds, + .get_minimal_size = label_get_minimal_size, + .set_property = label_set_property +}; + +grub_gui_component_t +grub_gui_label_new (void) +{ + grub_gui_label_t label; + label = grub_zalloc (sizeof (*label)); + if (! label) + return 0; + label->comp.ops = &label_ops; + label->visible = 1; + label->text = grub_strdup (""); + label->font = grub_font_get ("Unknown Regular 16"); + label->color.red = 0; + label->color.green = 0; + label->color.blue = 0; + label->color.alpha = 255; + label->align = align_left; + return (grub_gui_component_t) label; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_list.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_list.c new file mode 100644 index 0000000..58db03a --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/gui_list.c @@ -0,0 +1,961 @@ +/* gui_list.c - GUI component to display a selectable list of items. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +enum scrollbar_slice_mode { + SCROLLBAR_SLICE_WEST, + SCROLLBAR_SLICE_CENTER, + SCROLLBAR_SLICE_EAST +}; + +struct grub_gui_list_impl +{ + struct grub_gui_list list; + + grub_gui_container_t parent; + grub_video_rect_t bounds; + char *id; + int visible; + + int icon_width; + int icon_height; + int item_height; + int item_padding; + int item_icon_space; + int item_spacing; + grub_font_t item_font; + int selected_item_font_inherit; + grub_font_t selected_item_font; + grub_video_rgba_color_t item_color; + int selected_item_color_inherit; + grub_video_rgba_color_t selected_item_color; + + int draw_scrollbar; + int need_to_recreate_scrollbar; + char *scrollbar_frame_pattern; + char *scrollbar_thumb_pattern; + grub_gfxmenu_box_t scrollbar_frame; + grub_gfxmenu_box_t scrollbar_thumb; + int scrollbar_thumb_overlay; + int scrollbar_width; + enum scrollbar_slice_mode scrollbar_slice; + int scrollbar_left_pad; + int scrollbar_right_pad; + int scrollbar_top_pad; + int scrollbar_bottom_pad; + + int first_shown_index; + + int need_to_recreate_boxes; + char *theme_dir; + char *menu_box_pattern; + char *item_box_pattern; + int selected_item_box_pattern_inherit; + char *selected_item_box_pattern; + grub_gfxmenu_box_t menu_box; + grub_gfxmenu_box_t selected_item_box; + grub_gfxmenu_box_t item_box; + + grub_gfxmenu_icon_manager_t icon_manager; + + grub_gfxmenu_view_t view; +}; + +typedef struct grub_gui_list_impl *list_impl_t; + +static void +list_destroy (void *vself) +{ + list_impl_t self = vself; + + grub_free (self->theme_dir); + grub_free (self->menu_box_pattern); + grub_free (self->item_box_pattern); + grub_free (self->selected_item_box_pattern); + if (self->menu_box) + self->menu_box->destroy (self->menu_box); + if (self->item_box) + self->item_box->destroy (self->item_box); + if (self->selected_item_box) + self->selected_item_box->destroy (self->selected_item_box); + if (self->icon_manager) + grub_gfxmenu_icon_manager_destroy (self->icon_manager); + if (self->scrollbar_thumb) + self->scrollbar_thumb->destroy (self->scrollbar_thumb); + if (self->scrollbar_frame) + self->scrollbar_frame->destroy (self->scrollbar_frame); + grub_free (self->scrollbar_thumb_pattern); + grub_free (self->scrollbar_frame_pattern); + grub_free (self); +} + +static int +get_num_shown_items (list_impl_t self) +{ + int boxpad = self->item_padding; + int item_vspace = self->item_spacing; + int item_height = self->item_height; + + grub_gfxmenu_box_t box = self->menu_box; + int box_top_pad = box->get_top_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + grub_gfxmenu_box_t itembox = self->item_box; + grub_gfxmenu_box_t selbox = self->selected_item_box; + int item_top_pad = itembox->get_top_pad (itembox); + int item_bottom_pad = itembox->get_bottom_pad (itembox); + int sel_top_pad = selbox->get_top_pad (selbox); + int sel_bottom_pad = selbox->get_bottom_pad (selbox); + int max_top_pad = grub_max (item_top_pad, sel_top_pad); + int max_bottom_pad = grub_max (item_bottom_pad, sel_bottom_pad); + + if (item_height + item_vspace <= 0) + return 1; + + return (self->bounds.height + item_vspace - 2 * boxpad + - max_top_pad - max_bottom_pad + - box_top_pad - box_bottom_pad) / (item_height + item_vspace); +} + +static int +check_boxes (list_impl_t self) +{ + if (self->need_to_recreate_boxes) + { + grub_gui_recreate_box (&self->menu_box, + self->menu_box_pattern, + self->theme_dir); + + grub_gui_recreate_box (&self->item_box, + self->item_box_pattern, + self->theme_dir); + + grub_gui_recreate_box (&self->selected_item_box, + self->selected_item_box_pattern, + self->theme_dir); + + self->need_to_recreate_boxes = 0; + } + + return (self->menu_box != 0 && self->selected_item_box != 0 + && self->item_box != 0); +} + +static int +check_scrollbar (list_impl_t self) +{ + if (self->need_to_recreate_scrollbar) + { + grub_gui_recreate_box (&self->scrollbar_frame, + self->scrollbar_frame_pattern, + self->theme_dir); + + grub_gui_recreate_box (&self->scrollbar_thumb, + self->scrollbar_thumb_pattern, + self->theme_dir); + + self->need_to_recreate_scrollbar = 0; + } + + if (self->scrollbar_frame == 0 || self->scrollbar_thumb == 0) + return 0; + + /* Sanity checks. */ + grub_gfxmenu_box_t frame = self->scrollbar_frame; + grub_gfxmenu_box_t thumb = self->scrollbar_thumb; + grub_gfxmenu_box_t menu = self->menu_box; + int min_width = frame->get_left_pad (frame) + + frame->get_right_pad (frame); + int min_height = frame->get_top_pad (frame) + + frame->get_bottom_pad (frame) + + self->scrollbar_top_pad + self->scrollbar_bottom_pad + + menu->get_top_pad (menu) + + menu->get_bottom_pad (menu); + if (!self->scrollbar_thumb_overlay) + { + min_width += thumb->get_left_pad (thumb) + + thumb->get_right_pad (thumb); + min_height += thumb->get_top_pad (thumb) + + thumb->get_bottom_pad (thumb); + } + if (min_width <= self->scrollbar_width + && min_height <= (int) self->bounds.height) + return 1; + + /* Unprintable dimenstions. */ + self->draw_scrollbar = 0; + return 0; +} + +static const char * +list_get_id (void *vself) +{ + list_impl_t self = vself; + return self->id; +} + +static int +list_is_instance (void *vself __attribute__((unused)), const char *type) +{ + return (grub_strcmp (type, "component") == 0 + || grub_strcmp (type, "list") == 0); +} + +static struct grub_video_bitmap * +get_item_icon (list_impl_t self, int item_index) +{ + grub_menu_entry_t entry; + entry = grub_menu_get_entry (self->view->menu, item_index); + if (! entry) + return 0; + + return grub_gfxmenu_icon_manager_get_icon (self->icon_manager, entry); +} + +static void +make_selected_item_visible (list_impl_t self) +{ + int selected_index = self->view->selected; + if (selected_index < 0) + return; /* No item is selected. */ + int num_shown_items = get_num_shown_items (self); + int last_shown_index = self->first_shown_index + (num_shown_items - 1); + if (selected_index < self->first_shown_index) + self->first_shown_index = selected_index; + else if (selected_index > last_shown_index) + self->first_shown_index = selected_index - (num_shown_items - 1); +} + +/* Draw a scrollbar on the menu. */ +static void +draw_scrollbar (list_impl_t self, + int value, int extent, int min, int max, + int scrollbar_width, int scrollbar_height) +{ + unsigned thumby, thumbheight; + + grub_gfxmenu_box_t frame = self->scrollbar_frame; + grub_gfxmenu_box_t thumb = self->scrollbar_thumb; + int frame_vertical_pad = (frame->get_top_pad (frame) + + frame->get_bottom_pad (frame)); + int frame_horizontal_pad = (frame->get_left_pad (frame) + + frame->get_right_pad (frame)); + unsigned thumb_vertical_pad = (thumb->get_top_pad (thumb) + + thumb->get_bottom_pad (thumb)); + int thumb_horizontal_pad = (thumb->get_left_pad (thumb) + + thumb->get_right_pad (thumb)); + int tracktop = frame->get_top_pad (frame); + unsigned tracklen; + if (scrollbar_height <= frame_vertical_pad) + tracklen = 0; + else + tracklen = scrollbar_height - frame_vertical_pad; + frame->set_content_size (frame, + scrollbar_width - frame_horizontal_pad, + tracklen); + if (self->scrollbar_thumb_overlay) + { + tracklen += thumb_vertical_pad; + tracktop -= thumb->get_top_pad (thumb); + } + if (value <= min || max <= min) + thumby = 0; + else + thumby = ((unsigned) tracklen * (value - min)) + / ((unsigned) (max - min)); + if (max <= min) + thumbheight = 1; + else + thumbheight = ((unsigned) (tracklen * extent) + / ((unsigned) (max - min))) + 1; + /* Rare occasion: too many entries or too low height. */ + if (thumbheight < thumb_vertical_pad) + { + thumbheight = thumb_vertical_pad; + if (value <= min || max <= extent + || tracklen <= thumb_vertical_pad) + thumby = 0; + else + thumby = ((unsigned) ((tracklen - thumb_vertical_pad) * (value - min)) + / ((unsigned)(max - extent))); + } + thumby += tracktop; + int thumbx = frame->get_left_pad (frame); + int thumbwidth = scrollbar_width - frame_horizontal_pad; + if (!self->scrollbar_thumb_overlay) + thumbwidth -= thumb_horizontal_pad; + else + thumbx -= thumb->get_left_pad (thumb); + thumb->set_content_size (thumb, thumbwidth, + thumbheight - thumb_vertical_pad); + frame->draw (frame, 0, 0); + thumb->draw (thumb, thumbx, thumby); +} + +/* Draw the list of items. */ +static void +draw_menu (list_impl_t self, int num_shown_items) +{ + if (! self->menu_box || ! self->selected_item_box || ! self->item_box) + return; + + int boxpad = self->item_padding; + int icon_text_space = self->item_icon_space; + int item_vspace = self->item_spacing; + + int ascent = grub_font_get_ascent (self->item_font); + int descent = grub_font_get_descent (self->item_font); + int selected_ascent = grub_font_get_ascent (self->selected_item_font); + int selected_descent = grub_font_get_descent (self->selected_item_font); + int text_box_height = self->item_height; + + make_selected_item_visible (self); + + grub_gfxmenu_box_t itembox = self->item_box; + grub_gfxmenu_box_t selbox = self->selected_item_box; + int item_leftpad = itembox->get_left_pad (itembox); + int item_rightpad = itembox->get_right_pad (itembox); + int item_border_width = item_leftpad + item_rightpad; + int item_toppad = itembox->get_top_pad (itembox); + int sel_leftpad = selbox->get_left_pad (selbox); + int sel_rightpad = selbox->get_right_pad (selbox); + int sel_border_width = sel_leftpad + sel_rightpad; + int sel_toppad = selbox->get_top_pad (selbox); + + int max_leftpad = grub_max (item_leftpad, sel_leftpad); + int max_toppad = grub_max (item_toppad, sel_toppad); + int item_top = 0; + int menu_index; + int visible_index; + struct grub_video_rect oviewport; + + grub_video_get_viewport (&oviewport.x, &oviewport.y, + &oviewport.width, &oviewport.height); + grub_video_set_viewport (oviewport.x + boxpad, + oviewport.y + boxpad, + oviewport.width - 2 * boxpad, + oviewport.height - 2 * boxpad); + + int cwidth = oviewport.width - 2 * boxpad; + + itembox->set_content_size (itembox, cwidth - item_border_width, + text_box_height); + selbox->set_content_size (selbox, cwidth - sel_border_width, + text_box_height); + + int text_left_offset = self->icon_width + icon_text_space; + int item_text_top_offset = (text_box_height - (ascent + descent)) / 2 + ascent; + int sel_text_top_offset = (text_box_height - (selected_ascent + + selected_descent)) / 2 + + selected_ascent; + + grub_video_rect_t svpsave, sviewport; + sviewport.x = max_leftpad + text_left_offset; + int text_viewport_width = cwidth - sviewport.x; + sviewport.height = text_box_height; + + grub_video_color_t item_color; + grub_video_color_t sel_color; + item_color = grub_video_map_rgba_color (self->item_color); + sel_color = grub_video_map_rgba_color (self->selected_item_color); + + int item_box_top_offset = max_toppad - item_toppad; + int sel_box_top_offset = max_toppad - sel_toppad; + int item_viewport_width = text_viewport_width - item_rightpad; + int sel_viewport_width = text_viewport_width - sel_rightpad; + int tmp_icon_top_offset = (text_box_height - self->icon_height) / 2; + int item_icon_top_offset = item_toppad + tmp_icon_top_offset; + int sel_icon_top_offset = sel_toppad + tmp_icon_top_offset; + + for (visible_index = 0, menu_index = self->first_shown_index; + visible_index < num_shown_items && menu_index < self->view->menu->size; + visible_index++, menu_index++) + { + int is_selected = (menu_index == self->view->selected); + struct grub_video_bitmap *icon; + grub_font_t font; + grub_video_color_t color; + int text_top_offset; + int top_pad; + int icon_top_offset; + int viewport_width; + + if (is_selected) + { + selbox->draw (selbox, 0, item_top + sel_box_top_offset); + font = self->selected_item_font; + color = sel_color; + text_top_offset = sel_text_top_offset; + top_pad = sel_toppad; + icon_top_offset = sel_icon_top_offset; + viewport_width = sel_viewport_width; + } + else + { + itembox->draw (itembox, 0, item_top + item_box_top_offset); + font = self->item_font; + color = item_color; + text_top_offset = item_text_top_offset; + top_pad = item_toppad; + icon_top_offset = item_icon_top_offset; + viewport_width = item_viewport_width; + } + + icon = get_item_icon (self, menu_index); + if (icon != 0) + grub_video_blit_bitmap (icon, GRUB_VIDEO_BLIT_BLEND, + max_leftpad, + item_top + icon_top_offset, + 0, 0, self->icon_width, self->icon_height); + + const char *item_title = + grub_menu_get_entry (self->view->menu, menu_index)->title; + + + int off = self->view->menu_title_offset[menu_index]; + const char *scrolled_title = + grub_utf8_offset_code (item_title, grub_strlen (item_title), off); + if (scrolled_title) + item_title = scrolled_title; + + sviewport.y = item_top + top_pad; + sviewport.width = viewport_width; + grub_gui_set_viewport (&sviewport, &svpsave); + grub_font_draw_string (item_title, + font, + color, + 0, + text_top_offset); + grub_gui_restore_viewport (&svpsave); + + item_top += text_box_height + item_vspace; + } + grub_video_set_viewport (oviewport.x, + oviewport.y, + oviewport.width, + oviewport.height); +} + +static void +list_paint (void *vself, const grub_video_rect_t *region) +{ + list_impl_t self = vself; + grub_video_rect_t vpsave; + + if (! self->visible) + return; + if (!grub_video_have_common_points (region, &self->bounds)) + return; + + check_boxes (self); + + if (! self->menu_box || ! self->selected_item_box || ! self->item_box) + return; + + grub_gui_set_viewport (&self->bounds, &vpsave); + { + grub_gfxmenu_box_t box = self->menu_box; + int box_left_pad = box->get_left_pad (box); + int box_top_pad = box->get_top_pad (box); + int box_right_pad = box->get_right_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + grub_video_rect_t vpsave2, content_rect; + int num_shown_items = get_num_shown_items (self); + int drawing_scrollbar = (self->draw_scrollbar + && (num_shown_items < self->view->menu->size) + && check_scrollbar (self)); + int scrollbar_width = self->scrollbar_width; + + content_rect.x = box_left_pad; + content_rect.y = box_top_pad; + content_rect.width = self->bounds.width - box_left_pad - box_right_pad; + content_rect.height = self->bounds.height - box_top_pad - box_bottom_pad; + + box->set_content_size (box, content_rect.width, content_rect.height); + + box->draw (box, 0, 0); + + switch (self->scrollbar_slice) + { + case SCROLLBAR_SLICE_WEST: + content_rect.x += self->scrollbar_right_pad; + content_rect.width -= self->scrollbar_right_pad; + break; + case SCROLLBAR_SLICE_CENTER: + if (drawing_scrollbar) + content_rect.width -= scrollbar_width + self->scrollbar_left_pad + + self->scrollbar_right_pad; + break; + case SCROLLBAR_SLICE_EAST: + content_rect.width -= self->scrollbar_left_pad; + break; + } + + grub_gui_set_viewport (&content_rect, &vpsave2); + draw_menu (self, num_shown_items); + grub_gui_restore_viewport (&vpsave2); + + if (drawing_scrollbar) + { + content_rect.y += self->scrollbar_top_pad; + content_rect.height -= self->scrollbar_top_pad + + self->scrollbar_bottom_pad; + content_rect.width = scrollbar_width; + switch (self->scrollbar_slice) + { + case SCROLLBAR_SLICE_WEST: + if (box_left_pad > scrollbar_width) + { + content_rect.x = box_left_pad - scrollbar_width; + content_rect.width = scrollbar_width; + } + else + { + content_rect.x = 0; + content_rect.width = box_left_pad; + } + break; + case SCROLLBAR_SLICE_CENTER: + content_rect.x = self->bounds.width - box_right_pad + - scrollbar_width - self->scrollbar_right_pad; + content_rect.width = scrollbar_width; + break; + case SCROLLBAR_SLICE_EAST: + content_rect.x = self->bounds.width - box_right_pad; + content_rect.width = box_right_pad; + break; + } + + grub_gui_set_viewport (&content_rect, &vpsave2); + draw_scrollbar (self, + self->first_shown_index, num_shown_items, + 0, self->view->menu->size, + scrollbar_width, + content_rect.height); + grub_gui_restore_viewport (&vpsave2); + } + } + + grub_gui_restore_viewport (&vpsave); +} + +static void +list_set_parent (void *vself, grub_gui_container_t parent) +{ + list_impl_t self = vself; + self->parent = parent; +} + +static grub_gui_container_t +list_get_parent (void *vself) +{ + list_impl_t self = vself; + return self->parent; +} + +static void +list_set_bounds (void *vself, const grub_video_rect_t *bounds) +{ + list_impl_t self = vself; + self->bounds = *bounds; +} + +static void +list_get_bounds (void *vself, grub_video_rect_t *bounds) +{ + list_impl_t self = vself; + *bounds = self->bounds; +} + +static void +list_get_minimal_size (void *vself, unsigned *width, unsigned *height) +{ + list_impl_t self = vself; + + if (check_boxes (self)) + { + int boxpad = self->item_padding; + int item_vspace = self->item_spacing; + int item_height = self->item_height; + int num_items = 3; + + grub_gfxmenu_box_t box = self->menu_box; + int box_left_pad = box->get_left_pad (box); + int box_top_pad = box->get_top_pad (box); + int box_right_pad = box->get_right_pad (box); + int box_bottom_pad = box->get_bottom_pad (box); + unsigned width_s; + + grub_gfxmenu_box_t selbox = self->selected_item_box; + int sel_top_pad = selbox->get_top_pad (selbox); + int sel_bottom_pad = selbox->get_bottom_pad (selbox); + int sel_left_pad = selbox->get_left_pad (selbox); + int sel_right_pad = selbox->get_right_pad (selbox); + + grub_gfxmenu_box_t itembox = self->item_box; + int item_top_pad = itembox->get_top_pad (itembox); + int item_bottom_pad = itembox->get_bottom_pad (itembox); + int item_left_pad = itembox->get_left_pad (itembox); + int item_right_pad = itembox->get_right_pad (itembox); + + int max_left_pad = grub_max (item_left_pad, sel_left_pad); + int max_right_pad = grub_max (item_right_pad, sel_right_pad); + int max_top_pad = grub_max (item_top_pad, sel_top_pad); + int max_bottom_pad = grub_max (item_bottom_pad, sel_bottom_pad); + + *width = grub_font_get_string_width (self->item_font, "Typical OS"); + width_s = grub_font_get_string_width (self->selected_item_font, + "Typical OS"); + if (*width < width_s) + *width = width_s; + + *width += 2 * boxpad + box_left_pad + box_right_pad + + max_left_pad + max_right_pad + + self->item_icon_space + self->icon_width; + + switch (self->scrollbar_slice) + { + case SCROLLBAR_SLICE_WEST: + *width += self->scrollbar_right_pad; + break; + case SCROLLBAR_SLICE_CENTER: + *width += self->scrollbar_width + self->scrollbar_left_pad + + self->scrollbar_right_pad; + break; + case SCROLLBAR_SLICE_EAST: + *width += self->scrollbar_left_pad; + break; + } + + /* Set the menu box height to fit the items. */ + *height = (item_height * num_items + + item_vspace * (num_items - 1) + + 2 * boxpad + + box_top_pad + box_bottom_pad + + max_top_pad + max_bottom_pad); + } + else + { + *width = 0; + *height = 0; + } +} + +static grub_err_t +list_set_property (void *vself, const char *name, const char *value) +{ + list_impl_t self = vself; + if (grub_strcmp (name, "item_font") == 0) + { + self->item_font = grub_font_get (value); + if (self->selected_item_font_inherit) + self->selected_item_font = self->item_font; + } + else if (grub_strcmp (name, "selected_item_font") == 0) + { + if (! value || grub_strcmp (value, "inherit") == 0) + { + self->selected_item_font = self->item_font; + self->selected_item_font_inherit = 1; + } + else + { + self->selected_item_font = grub_font_get (value); + self->selected_item_font_inherit = 0; + } + } + else if (grub_strcmp (name, "item_color") == 0) + { + grub_video_rgba_color_t color; + if (grub_video_parse_color (value, &color) == GRUB_ERR_NONE) + { + self->item_color = color; + if (self->selected_item_color_inherit) + self->selected_item_color = self->item_color; + } + } + else if (grub_strcmp (name, "selected_item_color") == 0) + { + if (! value || grub_strcmp (value, "inherit") == 0) + { + self->selected_item_color = self->item_color; + self->selected_item_color_inherit = 1; + } + else + { + grub_video_rgba_color_t color; + if (grub_video_parse_color (value, &color) + == GRUB_ERR_NONE) + { + self->selected_item_color = color; + self->selected_item_color_inherit = 0; + } + } + } + else if (grub_strcmp (name, "icon_width") == 0) + { + self->icon_width = grub_strtol (value, 0, 10); + grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, + self->icon_width, + self->icon_height); + } + else if (grub_strcmp (name, "icon_height") == 0) + { + self->icon_height = grub_strtol (value, 0, 10); + grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, + self->icon_width, + self->icon_height); + } + else if (grub_strcmp (name, "item_height") == 0) + { + self->item_height = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "item_padding") == 0) + { + self->item_padding = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "item_icon_space") == 0) + { + self->item_icon_space = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "item_spacing") == 0) + { + self->item_spacing = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "visible") == 0) + { + self->visible = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "menu_pixmap_style") == 0) + { + self->need_to_recreate_boxes = 1; + grub_free (self->menu_box_pattern); + self->menu_box_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "item_pixmap_style") == 0) + { + self->need_to_recreate_boxes = 1; + grub_free (self->item_box_pattern); + self->item_box_pattern = value ? grub_strdup (value) : 0; + if (self->selected_item_box_pattern_inherit) + { + grub_free (self->selected_item_box_pattern); + self->selected_item_box_pattern = value ? grub_strdup (value) : 0; + } + } + else if (grub_strcmp (name, "selected_item_pixmap_style") == 0) + { + if (!value || grub_strcmp (value, "inherit") == 0) + { + grub_free (self->selected_item_box_pattern); + char *tmp = self->item_box_pattern; + self->selected_item_box_pattern = tmp ? grub_strdup (tmp) : 0; + self->selected_item_box_pattern_inherit = 1; + } + else + { + self->need_to_recreate_boxes = 1; + grub_free (self->selected_item_box_pattern); + self->selected_item_box_pattern = value ? grub_strdup (value) : 0; + self->selected_item_box_pattern_inherit = 0; + } + } + else if (grub_strcmp (name, "scrollbar_frame") == 0) + { + self->need_to_recreate_scrollbar = 1; + grub_free (self->scrollbar_frame_pattern); + self->scrollbar_frame_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "scrollbar_thumb") == 0) + { + self->need_to_recreate_scrollbar = 1; + grub_free (self->scrollbar_thumb_pattern); + self->scrollbar_thumb_pattern = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "scrollbar_thumb_overlay") == 0) + { + self->scrollbar_thumb_overlay = grub_strcmp (value, "true") == 0; + } + else if (grub_strcmp (name, "scrollbar_width") == 0) + { + self->scrollbar_width = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "scrollbar_slice") == 0) + { + if (grub_strcmp (value, "west") == 0) + self->scrollbar_slice = SCROLLBAR_SLICE_WEST; + else if (grub_strcmp (value, "center") == 0) + self->scrollbar_slice = SCROLLBAR_SLICE_CENTER; + else if (grub_strcmp (value, "east") == 0) + self->scrollbar_slice = SCROLLBAR_SLICE_EAST; + } + else if (grub_strcmp (name, "scrollbar_left_pad") == 0) + { + self->scrollbar_left_pad = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "scrollbar_right_pad") == 0) + { + self->scrollbar_right_pad = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "scrollbar_top_pad") == 0) + { + self->scrollbar_top_pad = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "scrollbar_bottom_pad") == 0) + { + self->scrollbar_bottom_pad = grub_strtol (value, 0, 10); + } + else if (grub_strcmp (name, "scrollbar") == 0) + { + self->draw_scrollbar = grub_strcmp (value, "false") != 0; + } + else if (grub_strcmp (name, "theme_dir") == 0) + { + self->need_to_recreate_boxes = 1; + grub_free (self->theme_dir); + self->theme_dir = value ? grub_strdup (value) : 0; + } + else if (grub_strcmp (name, "id") == 0) + { + grub_free (self->id); + if (value) + self->id = grub_strdup (value); + else + self->id = 0; + } + return grub_errno; +} + +/* Set necessary information that the gfxmenu view provides. */ +static void +list_set_view_info (void *vself, + grub_gfxmenu_view_t view) +{ + list_impl_t self = vself; + grub_gfxmenu_icon_manager_set_theme_path (self->icon_manager, + view->theme_path); + self->view = view; +} + +/* Refresh list variables */ +static void +list_refresh_info (void *vself, + grub_gfxmenu_view_t view) +{ + list_impl_t self = vself; + if (view->nested) + self->first_shown_index = 0; +} + +static struct grub_gui_component_ops list_comp_ops = + { + .destroy = list_destroy, + .get_id = list_get_id, + .is_instance = list_is_instance, + .paint = list_paint, + .set_parent = list_set_parent, + .get_parent = list_get_parent, + .set_bounds = list_set_bounds, + .get_bounds = list_get_bounds, + .get_minimal_size = list_get_minimal_size, + .set_property = list_set_property + }; + +static struct grub_gui_list_ops list_ops = +{ + .set_view_info = list_set_view_info, + .refresh_list = list_refresh_info +}; + +grub_gui_component_t +grub_gui_list_new (void) +{ + list_impl_t self; + grub_font_t default_font; + grub_video_rgba_color_t default_fg_color; + + self = grub_zalloc (sizeof (*self)); + if (! self) + return 0; + + self->list.ops = &list_ops; + self->list.component.ops = &list_comp_ops; + + self->visible = 1; + + default_font = grub_font_get ("Unknown Regular 16"); + default_fg_color = grub_video_rgba_color_rgb (0, 0, 0); + + self->icon_width = 32; + self->icon_height = 32; + self->item_height = 42; + self->item_padding = 14; + self->item_icon_space = 4; + self->item_spacing = 16; + self->item_font = default_font; + self->selected_item_font_inherit = 1; /* Default to using the item_font. */ + self->selected_item_font = default_font; + self->item_color = default_fg_color; + self->selected_item_color_inherit = 1; /* Default to using the item_color. */ + self->selected_item_color = default_fg_color; + + self->draw_scrollbar = 1; + self->need_to_recreate_scrollbar = 1; + self->scrollbar_frame = 0; + self->scrollbar_thumb = 0; + self->scrollbar_frame_pattern = 0; + self->scrollbar_thumb_pattern = 0; + self->scrollbar_thumb_overlay = 0; + self->scrollbar_width = 16; + self->scrollbar_slice = SCROLLBAR_SLICE_EAST; + self->scrollbar_left_pad = 2; + self->scrollbar_right_pad = 0; + self->scrollbar_top_pad = 0; + self->scrollbar_bottom_pad = 0; + + self->first_shown_index = 0; + + self->need_to_recreate_boxes = 0; + self->theme_dir = 0; + self->menu_box_pattern = 0; + self->item_box_pattern = 0; + self->selected_item_box_pattern_inherit = 1;/*Default to using the item_box.*/ + self->selected_item_box_pattern = 0; + self->menu_box = grub_gfxmenu_create_box (0, 0); + self->item_box = grub_gfxmenu_create_box (0, 0); + self->selected_item_box = grub_gfxmenu_create_box (0, 0); + + self->icon_manager = grub_gfxmenu_icon_manager_new (); + if (! self->icon_manager) + { + self->list.component.ops->destroy (self); + return 0; + } + grub_gfxmenu_icon_manager_set_icon_size (self->icon_manager, + self->icon_width, + self->icon_height); + return (grub_gui_component_t) self; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/theme_loader.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/theme_loader.c new file mode 100644 index 0000000..974dcb5 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/theme_loader.c @@ -0,0 +1,893 @@ +/* theme_loader.c - Theme file loader for gfxmenu. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_err_t +parse_proportional_spec (const char *value, signed *abs, grub_fixed_signed_t *prop); + +/* Construct a new box widget using ABSPATTERN to find the pixmap files for + it, storing the new box instance at *BOXPTR. + PATTERN should be of the form: "(hd0,0)/somewhere/style*.png". + The '*' then gets substituted with the various pixmap names that the + box uses. */ +static grub_err_t +recreate_box_absolute (grub_gfxmenu_box_t *boxptr, const char *abspattern) +{ + char *prefix; + char *suffix; + char *star; + grub_gfxmenu_box_t box; + + star = grub_strchr (abspattern, '*'); + if (! star) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "missing `*' in box pixmap pattern `%s'", abspattern); + + /* Prefix: Get the part before the '*'. */ + prefix = grub_malloc (star - abspattern + 1); + if (! prefix) + return grub_errno; + + grub_memcpy (prefix, abspattern, star - abspattern); + prefix[star - abspattern] = '\0'; + + /* Suffix: Everything after the '*' is the suffix. */ + suffix = star + 1; + + box = grub_gfxmenu_create_box (prefix, suffix); + grub_free (prefix); + if (! box) + return grub_errno; + + if (*boxptr) + (*boxptr)->destroy (*boxptr); + *boxptr = box; + return grub_errno; +} + + +/* Construct a new box widget using PATTERN to find the pixmap files for it, + storing the new widget at *BOXPTR. PATTERN should be of the form: + "somewhere/style*.png". The '*' then gets substituted with the various + pixmap names that the widget uses. + + Important! The value of *BOXPTR must be initialized! It must either + (1) Be 0 (a NULL pointer), or + (2) Be a pointer to a valid 'grub_gfxmenu_box_t' instance. + In this case, the previous instance is destroyed. */ +grub_err_t +grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr, + const char *pattern, const char *theme_dir) +{ + char *abspattern; + + /* Check arguments. */ + if (! pattern) + { + /* If no pixmap pattern is given, then just create an empty box. */ + if (*boxptr) + (*boxptr)->destroy (*boxptr); + *boxptr = grub_gfxmenu_create_box (0, 0); + return grub_errno; + } + + if (! theme_dir) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "styled box missing theme directory"); + + /* Resolve to an absolute path. */ + abspattern = grub_resolve_relative_path (theme_dir, pattern); + if (! abspattern) + return grub_errno; + + /* Create the box. */ + recreate_box_absolute (boxptr, abspattern); + grub_free (abspattern); + return grub_errno; +} + +static grub_err_t +theme_get_unsigned_int_from_proportional (const char *value, + unsigned absolute_value, + unsigned int *parsed_value) +{ + grub_err_t err; + grub_fixed_signed_t frac; + signed pixels; + err = parse_proportional_spec (value, &pixels, &frac); + if (err != GRUB_ERR_NONE) + return err; + int result = grub_fixed_sfs_multiply (absolute_value, frac) + pixels; + if (result < 0) + result = 0; + *parsed_value = result; + return GRUB_ERR_NONE; +} + +/* Set the specified property NAME on the view to the given string VALUE. + The caller is responsible for the lifetimes of NAME and VALUE. */ +static grub_err_t +theme_set_string (grub_gfxmenu_view_t view, + const char *name, + const char *value, + const char *theme_dir, + const char *filename, + int line_num, + int col_num) +{ + if (! grub_strcmp ("title-font", name)) + view->title_font = grub_font_get (value); + else if (! grub_strcmp ("message-font", name)) + view->message_font = grub_font_get (value); + else if (! grub_strcmp ("terminal-font", name)) + { + grub_free (view->terminal_font_name); + view->terminal_font_name = grub_strdup (value); + if (! view->terminal_font_name) + return grub_errno; + } + else if (! grub_strcmp ("title-color", name)) + grub_video_parse_color (value, &view->title_color); + else if (! grub_strcmp ("message-color", name)) + grub_video_parse_color (value, &view->message_color); + else if (! grub_strcmp ("message-bg-color", name)) + grub_video_parse_color (value, &view->message_bg_color); + else if (! grub_strcmp("menu-tip-left", name)) + grub_env_set("VTOY_TIP_LEFT", value); + else if (! grub_strcmp("menu-tip-top", name)) + grub_env_set("VTOY_TIP_TOP", value); + else if (! grub_strcmp("menu-tip-color", name)) + grub_env_set("VTOY_TIP_COLOR", value); + else if (! grub_strcmp ("desktop-image", name)) + { + struct grub_video_bitmap *raw_bitmap; + char *path; + path = grub_resolve_relative_path (theme_dir, value); + if (! path) + return grub_errno; + if (grub_video_bitmap_load (&raw_bitmap, path) != GRUB_ERR_NONE) + { + grub_free (path); + return grub_errno; + } + grub_free(path); + grub_video_bitmap_destroy (view->raw_desktop_image); + view->raw_desktop_image = raw_bitmap; + } + else if (! grub_strcmp ("desktop-image-scale-method", name)) + { + if (! value || ! grub_strcmp ("stretch", value)) + view->desktop_image_scale_method = + GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH; + else if (! grub_strcmp ("crop", value)) + view->desktop_image_scale_method = + GRUB_VIDEO_BITMAP_SELECTION_METHOD_CROP; + else if (! grub_strcmp ("padding", value)) + view->desktop_image_scale_method = + GRUB_VIDEO_BITMAP_SELECTION_METHOD_PADDING; + else if (! grub_strcmp ("fitwidth", value)) + view->desktop_image_scale_method = + GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITWIDTH; + else if (! grub_strcmp ("fitheight", value)) + view->desktop_image_scale_method = + GRUB_VIDEO_BITMAP_SELECTION_METHOD_FITHEIGHT; + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Unsupported scale method: %s", + value); + } + else if (! grub_strcmp ("desktop-image-h-align", name)) + { + if (! grub_strcmp ("left", value)) + view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_LEFT; + else if (! grub_strcmp ("center", value)) + view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_CENTER; + else if (! grub_strcmp ("right", value)) + view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_RIGHT; + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Unsupported horizontal align method: %s", + value); + } + else if (! grub_strcmp ("desktop-image-v-align", name)) + { + if (! grub_strcmp ("top", value)) + view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_TOP; + else if (! grub_strcmp ("center", value)) + view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_CENTER; + else if (! grub_strcmp ("bottom", value)) + view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_BOTTOM; + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Unsupported vertical align method: %s", + value); + } + else if (! grub_strcmp ("desktop-color", name)) + grub_video_parse_color (value, &view->desktop_color); + else if (! grub_strcmp ("terminal-box", name)) + { + grub_err_t err; + err = grub_gui_recreate_box (&view->terminal_box, value, theme_dir); + if (err != GRUB_ERR_NONE) + return err; + } + else if (! grub_strcmp ("terminal-border", name)) + { + view->terminal_border = grub_strtoul (value, 0, 10); + if (grub_errno) + return grub_errno; + } + else if (! grub_strcmp ("terminal-left", name)) + { + unsigned int tmp; + int err = theme_get_unsigned_int_from_proportional (value, + view->screen.width, + &tmp); + if (err != GRUB_ERR_NONE) + return err; + view->terminal_rect.x = tmp; + } + else if (! grub_strcmp ("terminal-top", name)) + { + unsigned int tmp; + int err = theme_get_unsigned_int_from_proportional (value, + view->screen.height, + &tmp); + if (err != GRUB_ERR_NONE) + return err; + view->terminal_rect.y = tmp; + } + else if (! grub_strcmp ("terminal-width", name)) + { + unsigned int tmp; + int err = theme_get_unsigned_int_from_proportional (value, + view->screen.width, + &tmp); + if (err != GRUB_ERR_NONE) + return err; + view->terminal_rect.width = tmp; + } + else if (! grub_strcmp ("terminal-height", name)) + { + unsigned int tmp; + int err = theme_get_unsigned_int_from_proportional (value, + view->screen.height, + &tmp); + if (err != GRUB_ERR_NONE) + return err; + view->terminal_rect.height = tmp; + } + else if (! grub_strcmp ("title-text", name)) + { + grub_free (view->title_text); + view->title_text = grub_strdup (value); + if (! view->title_text) + return grub_errno; + } + else if (! grub_strcmp ("ventoy_left_top_color", name)) + return grub_errno; + else + { + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "%s:%d:%d unknown property `%s'", + filename, line_num, col_num, name); + } + return grub_errno; +} + +struct parsebuf +{ + char *buf; + int pos; + int len; + int line_num; + int col_num; + const char *filename; + char *theme_dir; + grub_gfxmenu_view_t view; +}; + +static int +has_more (struct parsebuf *p) +{ + return p->pos < p->len; +} + +static int +read_char (struct parsebuf *p) +{ + if (has_more (p)) + { + char c; + c = p->buf[p->pos++]; + if (c == '\n') + { + p->line_num++; + p->col_num = 1; + } + else + { + p->col_num++; + } + return c; + } + else + return -1; +} + +static int +peek_char (struct parsebuf *p) +{ + if (has_more (p)) + return p->buf[p->pos]; + else + return -1; +} + +static int +is_whitespace (char c) +{ + return (c == ' ' + || c == '\t' + || c == '\r' + || c == '\n' + || c == '\f'); +} + +static void +skip_whitespace (struct parsebuf *p) +{ + while (has_more (p) && is_whitespace(peek_char (p))) + read_char (p); +} + +static void +advance_to_next_line (struct parsebuf *p) +{ + int c; + + /* Eat characters up to the newline. */ + do + { + c = read_char (p); + } + while (c != -1 && c != '\n'); +} + +static int +is_identifier_char (int c) +{ + return (c != -1 + && (grub_isalpha(c) + || grub_isdigit(c) + || c == '_' + || c == '-')); +} + +static char * +read_identifier (struct parsebuf *p) +{ + /* Index of the first character of the identifier in p->buf. */ + int start; + /* Next index after the last character of the identifer in p->buf. */ + int end; + + skip_whitespace (p); + + /* Capture the start of the identifier. */ + start = p->pos; + + /* Scan for the end. */ + while (is_identifier_char (peek_char (p))) + read_char (p); + end = p->pos; + + if (end - start < 1) + return 0; + + return grub_new_substring (p->buf, start, end); +} + +static char * +read_expression (struct parsebuf *p) +{ + int start; + int end; + + skip_whitespace (p); + if (peek_char (p) == '"') + { + /* Read as a quoted string. + The quotation marks are not included in the expression value. */ + /* Skip opening quotation mark. */ + read_char (p); + start = p->pos; + while (has_more (p) && peek_char (p) != '"') + read_char (p); + end = p->pos; + /* Skip the terminating quotation mark. */ + read_char (p); + } + else if (peek_char (p) == '(') + { + /* Read as a parenthesized string -- for tuples/coordinates. */ + /* The parentheses are included in the expression value. */ + int c; + + start = p->pos; + do + { + c = read_char (p); + } + while (c != -1 && c != ')'); + end = p->pos; + } + else if (has_more (p)) + { + /* Read as a single word -- for numeric values or words without + whitespace. */ + start = p->pos; + while (has_more (p) && ! is_whitespace (peek_char (p)) + && peek_char (p) != '}') + read_char (p); + end = p->pos; + } + else + { + /* The end of the theme file has been reached. */ + grub_error (GRUB_ERR_IO, "%s:%d:%d expression expected in theme file", + p->filename, p->line_num, p->col_num); + return 0; + } + + return grub_new_substring (p->buf, start, end); +} + +static grub_err_t +parse_proportional_spec (const char *value, signed *abs, grub_fixed_signed_t *prop) +{ + signed num; + const char *ptr; + int sig = 0; + *abs = 0; + *prop = 0; + ptr = value; + while (*ptr) + { + sig = 0; + + while (*ptr == '-' || *ptr == '+') + { + if (*ptr == '-') + sig = !sig; + ptr++; + } + + num = grub_strtoul (ptr, (char **) &ptr, 0); + if (grub_errno) + return grub_errno; + if (sig) + num = -num; + if (*ptr == '%') + { + *prop += grub_fixed_fsf_divide (grub_signed_to_fixed (num), 100); + ptr++; + } + else + *abs += num; + } + return GRUB_ERR_NONE; +} + + +/* Read a GUI object specification from the theme file. + Any components created will be added to the GUI container PARENT. */ +static grub_err_t +read_object (struct parsebuf *p, grub_gui_container_t parent) +{ + grub_video_rect_t bounds; + + char *name; + name = read_identifier (p); + if (! name) + goto cleanup; + + grub_gui_component_t component = 0; + if (grub_strcmp (name, "label") == 0) + { + component = grub_gui_label_new (); + } + else if (grub_strcmp (name, "image") == 0) + { + component = grub_gui_image_new (); + } + else if (grub_strcmp (name, "vbox") == 0) + { + component = (grub_gui_component_t) grub_gui_vbox_new (); + } + else if (grub_strcmp (name, "hbox") == 0) + { + component = (grub_gui_component_t) grub_gui_hbox_new (); + } + else if (grub_strcmp (name, "canvas") == 0) + { + component = (grub_gui_component_t) grub_gui_canvas_new (); + } + else if (grub_strcmp (name, "progress_bar") == 0) + { + component = grub_gui_progress_bar_new (); + } + else if (grub_strcmp (name, "circular_progress") == 0) + { + component = grub_gui_circular_progress_new (); + } + else if (grub_strcmp (name, "boot_menu") == 0) + { + component = grub_gui_list_new (); + } + else + { + /* Unknown type. */ + grub_error (GRUB_ERR_IO, "%s:%d:%d unknown object type `%s'", + p->filename, p->line_num, p->col_num, name); + goto cleanup; + } + + if (! component) + goto cleanup; + + /* Inform the component about the theme so it can find its resources. */ + component->ops->set_property (component, "theme_dir", p->theme_dir); + component->ops->set_property (component, "theme_path", p->filename); + + /* Add the component as a child of PARENT. */ + bounds.x = 0; + bounds.y = 0; + bounds.width = -1; + bounds.height = -1; + component->ops->set_bounds (component, &bounds); + parent->ops->add (parent, component); + + skip_whitespace (p); + if (read_char (p) != '{') + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d expected `{' after object type name `%s'", + p->filename, p->line_num, p->col_num, name); + goto cleanup; + } + + while (has_more (p)) + { + skip_whitespace (p); + + /* Check whether the end has been encountered. */ + if (peek_char (p) == '}') + { + /* Skip the closing brace. */ + read_char (p); + break; + } + + if (peek_char (p) == '#') + { + /* Skip comments. */ + advance_to_next_line (p); + continue; + } + + if (peek_char (p) == '+') + { + /* Skip the '+'. */ + read_char (p); + + /* Check whether this component is a container. */ + if (component->ops->is_instance (component, "container")) + { + /* Read the sub-object recursively and add it as a child. */ + if (read_object (p, (grub_gui_container_t) component) != 0) + goto cleanup; + /* After reading the sub-object, resume parsing, expecting + another property assignment or sub-object definition. */ + continue; + } + else + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d attempted to add object to non-container", + p->filename, p->line_num, p->col_num); + goto cleanup; + } + } + + char *property; + property = read_identifier (p); + if (! property) + { + grub_error (GRUB_ERR_IO, "%s:%d:%d identifier expected in theme file", + p->filename, p->line_num, p->col_num); + goto cleanup; + } + + skip_whitespace (p); + if (read_char (p) != '=') + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d expected `=' after property name `%s'", + p->filename, p->line_num, p->col_num, property); + grub_free (property); + goto cleanup; + } + skip_whitespace (p); + + char *value; + value = read_expression (p); + if (! value) + { + grub_free (property); + goto cleanup; + } + + /* Handle the property value. */ + if (grub_strcmp (property, "left") == 0) + parse_proportional_spec (value, &component->x, &component->xfrac); + else if (grub_strcmp (property, "top") == 0) + parse_proportional_spec (value, &component->y, &component->yfrac); + else if (grub_strcmp (property, "width") == 0) + parse_proportional_spec (value, &component->w, &component->wfrac); + else if (grub_strcmp (property, "height") == 0) + parse_proportional_spec (value, &component->h, &component->hfrac); + else + /* General property handling. */ + component->ops->set_property (component, property, value); + + grub_free (value); + grub_free (property); + if (grub_errno != GRUB_ERR_NONE) + goto cleanup; + } + +cleanup: + grub_free (name); + return grub_errno; +} + +static grub_err_t +read_property (struct parsebuf *p) +{ + char *name; + + /* Read the property name. */ + name = read_identifier (p); + if (! name) + { + advance_to_next_line (p); + return grub_errno; + } + + /* Skip whitespace before separator. */ + skip_whitespace (p); + + /* Read separator. */ + if (read_char (p) != ':') + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d missing separator after property name `%s'", + p->filename, p->line_num, p->col_num, name); + goto done; + } + + /* Skip whitespace after separator. */ + skip_whitespace (p); + + /* Get the value based on its type. */ + if (peek_char (p) == '"') + { + /* String value (e.g., '"My string"'). */ + char *value = read_expression (p); + if (! value) + { + grub_error (GRUB_ERR_IO, "%s:%d:%d missing property value", + p->filename, p->line_num, p->col_num); + goto done; + } + /* If theme_set_string results in an error, grub_errno will be returned + below. */ + theme_set_string (p->view, name, value, p->theme_dir, + p->filename, p->line_num, p->col_num); + grub_free (value); + } + else + { + grub_error (GRUB_ERR_IO, + "%s:%d:%d property value invalid; " + "enclose literal values in quotes (\")", + p->filename, p->line_num, p->col_num); + + grub_printf("File: %s\nLine:%d Column:%d\n" + "property value invalid; enclose literal values in quotes (\")\n\n", + p->filename, p->line_num, p->col_num); + + goto done; + } + +done: + grub_free (name); + return grub_errno; +} + +extern int g_menu_update_mode; + +/* Set properties on the view based on settings from the specified + theme file. */ +grub_err_t +grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, const char *theme_path) +{ + int flag = 0; + grub_file_t file; + struct parsebuf p; + + p.view = view; + p.theme_dir = grub_get_dirname (theme_path); + + file = grub_file_open (theme_path, GRUB_FILE_TYPE_THEME); + if (! file) + { + grub_free (p.theme_dir); + return grub_errno; + } + + p.len = grub_file_size (file); + p.buf = grub_malloc (p.len + 8192); + p.pos = 0; + p.line_num = 1; + p.col_num = 1; + p.filename = theme_path; + if (! p.buf) + { + grub_file_close (file); + grub_free (p.theme_dir); + return grub_errno; + } + if (grub_file_read (file, p.buf, p.len) != p.len) + { + grub_free (p.buf); + grub_file_close (file); + grub_free (p.theme_dir); + return grub_errno; + } + +{ + const char *checkret = grub_env_get("VTOY_CHKDEV_RESULT_STRING"); + if (checkret == NULL || checkret[0] != '0') + { + p.len += grub_snprintf(p.buf + p.len, 4096, "\n+ hbox{\n left = 1%%\n top = 90%%\n" + " + label {text = \"[Unofficial Ventoy]\" color = \"red\" align = \"left\"}\n" + "}\n"); + } +} + + + + if (view->canvas) + view->canvas->component.ops->destroy (view->canvas); + + view->canvas = grub_gui_canvas_new (); + if (!view->canvas) + goto fail; + ((grub_gui_component_t) view->canvas) + ->ops->set_bounds ((grub_gui_component_t) view->canvas, + &view->screen); + +parse: + while (has_more (&p)) + { + /* Skip comments (lines beginning with #). */ + if (peek_char (&p) == '#') + { + advance_to_next_line (&p); + continue; + } + + /* Find the first non-whitespace character. */ + skip_whitespace (&p); + + /* Handle the content. */ + if (peek_char (&p) == '+') + { + /* Skip the '+'. */ + read_char (&p); + read_object (&p, view->canvas); + } + else + { + read_property (&p); + } + + if (grub_errno != GRUB_ERR_NONE) + goto fail; + } + + +if (flag == 0) +{ + const char *tip = grub_env_get("VTOY_MENU_TIP_ENABLE"); + if (tip && tip[0] == '1') + { + char tmpmsg[512]; + + grub_memset(tmpmsg, 'w', 500); + tmpmsg[500] = 0; + + g_menu_update_mode = 1; + p.len += grub_snprintf(p.buf + p.len, 4096, + "\n+ vbox{\n left = %s\n top = %s\n" + "+ label { id=\"VTOY_MENU_TIP_1\" text = \"%s\" color = \"%s\" align = \"%s\"}\n" + "+ label { id=\"VTOY_MENU_TIP_2\" text = \"%s\" color = \"%s\" align = \"%s\"}\n" + "}\n", + grub_env_get("VTOY_TIP_LEFT"), + grub_env_get("VTOY_TIP_TOP"), + tmpmsg, + grub_env_get("VTOY_TIP_COLOR"), + grub_env_get("VTOY_TIP_ALIGN"), + tmpmsg, + grub_env_get("VTOY_TIP_COLOR"), + grub_env_get("VTOY_TIP_ALIGN") + ); + + flag = 1; + goto parse; + } +} + + + + /* Set the new theme path. */ + grub_free (view->theme_path); + view->theme_path = grub_strdup (theme_path); + goto cleanup; + +fail: + if (view->canvas) + { + view->canvas->component.ops->destroy (view->canvas); + view->canvas = 0; + } + +cleanup: + grub_free (p.buf); + grub_file_close (file); + grub_free (p.theme_dir); + return grub_errno; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/view.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/view.c new file mode 100644 index 0000000..b1487d2 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/gfxmenu/view.c @@ -0,0 +1,694 @@ +/* view.c - Graphical menu interface MVC view. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +init_terminal (grub_gfxmenu_view_t view); +static void +init_background (grub_gfxmenu_view_t view); +static grub_gfxmenu_view_t term_view; + +/* Create a new view object, loading the theme specified by THEME_PATH and + associating MODEL with the view. */ +grub_gfxmenu_view_t +grub_gfxmenu_view_new (const char *theme_path, + int width, int height) +{ + grub_gfxmenu_view_t view; + grub_font_t default_font; + grub_video_rgba_color_t default_fg_color; + grub_video_rgba_color_t default_bg_color; + + view = grub_malloc (sizeof (*view)); + if (! view) + return 0; + + while (grub_gfxmenu_timeout_notifications) + { + struct grub_gfxmenu_timeout_notify *p; + p = grub_gfxmenu_timeout_notifications; + grub_gfxmenu_timeout_notifications = grub_gfxmenu_timeout_notifications->next; + grub_free (p); + } + + view->screen.x = 0; + view->screen.y = 0; + view->screen.width = width; + view->screen.height = height; + + view->need_to_check_sanity = 1; + view->terminal_border = 3; + view->terminal_rect.width = view->screen.width * 7 / 10; + view->terminal_rect.height = view->screen.height * 7 / 10; + view->terminal_rect.x = view->screen.x + (view->screen.width + - view->terminal_rect.width) / 2; + view->terminal_rect.y = view->screen.y + (view->screen.height + - view->terminal_rect.height) / 2; + + default_font = grub_font_get ("Unknown Regular 16"); + default_fg_color = grub_video_rgba_color_rgb (0, 0, 0); + default_bg_color = grub_video_rgba_color_rgb (255, 255, 255); + + view->canvas = 0; + + view->title_font = default_font; + view->message_font = default_font; + view->terminal_font_name = grub_strdup ("Fixed 10"); + view->title_color = default_fg_color; + view->message_color = default_bg_color; + view->message_bg_color = default_fg_color; + view->raw_desktop_image = 0; + view->scaled_desktop_image = 0; + view->desktop_image_scale_method = GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH; + view->desktop_image_h_align = GRUB_VIDEO_BITMAP_H_ALIGN_CENTER; + view->desktop_image_v_align = GRUB_VIDEO_BITMAP_V_ALIGN_CENTER; + view->desktop_color = default_bg_color; + view->terminal_box = grub_gfxmenu_create_box (0, 0); + view->title_text = grub_strdup (_("GRUB Boot Menu")); + view->progress_message_text = 0; + view->theme_path = 0; + + /* Set the timeout bar's frame. */ + view->progress_message_frame.width = view->screen.width * 4 / 5; + view->progress_message_frame.height = 50; + view->progress_message_frame.x = view->screen.x + + (view->screen.width - view->progress_message_frame.width) / 2; + view->progress_message_frame.y = view->screen.y + + view->screen.height - 90 - 20 - view->progress_message_frame.height; + + if (grub_gfxmenu_view_load_theme (view, theme_path) != 0) + { + grub_gfxmenu_view_destroy (view); + return 0; + } + + return view; +} + +/* Destroy the view object. All used memory is freed. */ +void +grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view) +{ + if (!view) + return; + while (grub_gfxmenu_timeout_notifications) + { + struct grub_gfxmenu_timeout_notify *p; + p = grub_gfxmenu_timeout_notifications; + grub_gfxmenu_timeout_notifications = grub_gfxmenu_timeout_notifications->next; + grub_free (p); + } + grub_video_bitmap_destroy (view->raw_desktop_image); + grub_video_bitmap_destroy (view->scaled_desktop_image); + if (view->terminal_box) + view->terminal_box->destroy (view->terminal_box); + grub_free (view->terminal_font_name); + grub_free (view->title_text); + grub_free (view->progress_message_text); + grub_free (view->theme_path); + if (view->menu_title_offset) + grub_free (view->menu_title_offset); + if (view->canvas) + view->canvas->component.ops->destroy (view->canvas); + grub_free (view); +} + +static void +redraw_background (grub_gfxmenu_view_t view, + const grub_video_rect_t *bounds) +{ + if (view->scaled_desktop_image) + { + struct grub_video_bitmap *img = view->scaled_desktop_image; + grub_video_blit_bitmap (img, GRUB_VIDEO_BLIT_REPLACE, + bounds->x, bounds->y, + bounds->x - view->screen.x, + bounds->y - view->screen.y, + bounds->width, bounds->height); + } + else + { + grub_video_fill_rect (grub_video_map_rgba_color (view->desktop_color), + bounds->x, bounds->y, + bounds->width, bounds->height); + } +} + +static void +draw_title (grub_gfxmenu_view_t view) +{ + if (! view->title_text) + return; + + /* Center the title. */ + int title_width = grub_font_get_string_width (view->title_font, + view->title_text); + int x = (view->screen.width - title_width) / 2; + int y = 40 + grub_font_get_ascent (view->title_font); + grub_font_draw_string (view->title_text, + view->title_font, + grub_video_map_rgba_color (view->title_color), + x, y); +} + +struct progress_value_data +{ + int visible; + int start; + int end; + int value; +}; + +struct grub_gfxmenu_timeout_notify *grub_gfxmenu_timeout_notifications; + +static void +update_timeouts (int visible, int start, int value, int end) +{ + struct grub_gfxmenu_timeout_notify *cur; + + for (cur = grub_gfxmenu_timeout_notifications; cur; cur = cur->next) + cur->set_state (cur->self, visible, start, value, end); +} + +static void +redraw_timeouts (struct grub_gfxmenu_view *view) +{ + struct grub_gfxmenu_timeout_notify *cur; + + for (cur = grub_gfxmenu_timeout_notifications; cur; cur = cur->next) + { + grub_video_rect_t bounds; + cur->self->ops->get_bounds (cur->self, &bounds); + grub_video_set_area_status (GRUB_VIDEO_AREA_ENABLED); + grub_gfxmenu_view_redraw (view, &bounds); + } +} + +void +grub_gfxmenu_print_timeout (int timeout, void *data) +{ + struct grub_gfxmenu_view *view = data; + + if (view->first_timeout == -1) + view->first_timeout = timeout; + + update_timeouts (1, -view->first_timeout, -timeout, 0); + redraw_timeouts (view); + grub_video_swap_buffers (); + if (view->double_repaint) + redraw_timeouts (view); +} + +void +grub_gfxmenu_clear_timeout (void *data) +{ + struct grub_gfxmenu_view *view = data; + + update_timeouts (0, 1, 0, 0); + redraw_timeouts (view); + grub_video_swap_buffers (); + if (view->double_repaint) + redraw_timeouts (view); +} + +static void +update_menu_visit (grub_gui_component_t component, + void *userdata) +{ + grub_gfxmenu_view_t view; + view = userdata; + if (component->ops->is_instance (component, "list")) + { + grub_gui_list_t list = (grub_gui_list_t) component; + list->ops->set_view_info (list, view); + } +} + +/* Update any boot menu components with the current menu model and + theme path. */ +static void +update_menu_components (grub_gfxmenu_view_t view) +{ + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + update_menu_visit, view); +} + +static void +refresh_menu_visit (grub_gui_component_t component, + void *userdata) +{ + grub_gfxmenu_view_t view; + view = userdata; + if (component->ops->is_instance (component, "list")) + { + grub_gui_list_t list = (grub_gui_list_t) component; + list->ops->refresh_list (list, view); + } +} + +/* Refresh list information (useful for submenus) */ +static void +refresh_menu_components (grub_gfxmenu_view_t view) +{ + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + refresh_menu_visit, view); +} + +static void +draw_message (grub_gfxmenu_view_t view) +{ + char *text = view->progress_message_text; + grub_video_rect_t f = view->progress_message_frame; + if (! text) + return; + + grub_font_t font = view->message_font; + grub_video_color_t color = grub_video_map_rgba_color (view->message_color); + + /* Border. */ + grub_video_fill_rect (color, + f.x-1, f.y-1, f.width+2, f.height+2); + /* Fill. */ + grub_video_fill_rect (grub_video_map_rgba_color (view->message_bg_color), + f.x, f.y, f.width, f.height); + + /* Center the text. */ + int text_width = grub_font_get_string_width (font, text); + int x = f.x + (f.width - text_width) / 2; + int y = (f.y + (f.height - grub_font_get_descent (font)) / 2 + + grub_font_get_ascent (font) / 2); + grub_font_draw_string (text, font, color, x, y); +} + +void +grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, + const grub_video_rect_t *region) +{ + if (grub_video_have_common_points (&view->terminal_rect, region)) + grub_gfxterm_schedule_repaint (); + + grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); + grub_video_area_status_t area_status; + grub_video_get_area_status (&area_status); + if (area_status == GRUB_VIDEO_AREA_ENABLED) + grub_video_set_region (region->x, region->y, + region->width, region->height); + + redraw_background (view, region); + if (view->canvas) + view->canvas->component.ops->paint (view->canvas, region); + draw_title (view); + if (grub_video_have_common_points (&view->progress_message_frame, region)) + draw_message (view); + + if (area_status == GRUB_VIDEO_AREA_ENABLED) + grub_video_set_area_status (GRUB_VIDEO_AREA_ENABLED); +} + +void +grub_gfxmenu_view_draw (grub_gfxmenu_view_t view) +{ + init_terminal (view); + + init_background (view); + + /* Clear the screen; there may be garbage left over in video memory. */ + grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), + view->screen.x, view->screen.y, + view->screen.width, view->screen.height); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_video_fill_rect (grub_video_map_rgb (0, 0, 0), + view->screen.x, view->screen.y, + view->screen.width, view->screen.height); + + refresh_menu_components (view); + update_menu_components (view); + + grub_video_set_area_status (GRUB_VIDEO_AREA_DISABLED); + grub_gfxmenu_view_redraw (view, &view->screen); + grub_video_swap_buffers (); + if (view->double_repaint) + { + grub_video_set_area_status (GRUB_VIDEO_AREA_DISABLED); + grub_gfxmenu_view_redraw (view, &view->screen); + } + +} + +static void +redraw_menu_visit (grub_gui_component_t component, + void *userdata) +{ + grub_gfxmenu_view_t view; + view = userdata; + if (component->ops->is_instance (component, "list")) + { + grub_video_rect_t bounds; + + component->ops->get_bounds (component, &bounds); + grub_video_set_area_status (GRUB_VIDEO_AREA_ENABLED); + grub_gfxmenu_view_redraw (view, &bounds); + } +} + +extern int g_menu_update_mode; + +static void grub_gfxmenu_update_all(grub_gfxmenu_view_t view) +{ + grub_video_set_area_status(GRUB_VIDEO_AREA_DISABLED); + grub_gfxmenu_view_redraw(view, &view->screen); +} + +void +grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view) +{ + update_menu_components (view); + + if (g_menu_update_mode) + grub_gfxmenu_update_all(view); + else + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + redraw_menu_visit, view); + + grub_video_swap_buffers (); + if (view->double_repaint) + { + if (g_menu_update_mode) + grub_gfxmenu_update_all(view); + else + grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas, + redraw_menu_visit, view); + } +} + + +void +grub_gfxmenu_set_chosen_entry (int entry, void *data) +{ + grub_gfxmenu_view_t view = data; + + view->selected = entry; + grub_gfxmenu_redraw_menu (view); + + +} + +void +grub_gfxmenu_scroll_chosen_entry (void *data, int diren) +{ + grub_gfxmenu_view_t view = data; + const char *item_title; + int off; + int max; + + if (!view->menu->size) + return; + + item_title = grub_menu_get_entry (view->menu, view->selected)->title; + off = view->menu_title_offset[view->selected] + diren; + max = grub_utf8_get_num_code (item_title, grub_strlen(item_title)); + + if (diren == 1000000) + off = (max >= 20) ? (max - 20) : 0; + else if (off < 0) + off = 0; + else if (off > max) + off = max; + + view->menu_title_offset[view->selected] = off; + grub_gfxmenu_redraw_menu (view); +} + +static void +grub_gfxmenu_draw_terminal_box (void) +{ + grub_gfxmenu_box_t term_box; + + term_box = term_view->terminal_box; + if (!term_box) + return; + + grub_video_set_area_status (GRUB_VIDEO_AREA_DISABLED); + + term_box->set_content_size (term_box, term_view->terminal_rect.width, + term_view->terminal_rect.height); + + term_box->draw (term_box, + term_view->terminal_rect.x - term_box->get_left_pad (term_box), + term_view->terminal_rect.y - term_box->get_top_pad (term_box)); +} + +static void +get_min_terminal (grub_font_t terminal_font, + unsigned int border_width, + unsigned int *min_terminal_width, + unsigned int *min_terminal_height) +{ + struct grub_font_glyph *glyph; + glyph = grub_font_get_glyph (terminal_font, 'M'); + *min_terminal_width = (glyph? glyph->device_width : 8) * 80 + + 2 * border_width; + *min_terminal_height = grub_font_get_max_char_height (terminal_font) * 24 + + 2 * border_width; +} + +static void +terminal_sanity_check (grub_gfxmenu_view_t view) +{ + if (!view->need_to_check_sanity) + return; + + /* terminal_font was checked before in the init_terminal function. */ + grub_font_t terminal_font = grub_font_get (view->terminal_font_name); + + /* Non-negative numbers below. */ + int scr_x = view->screen.x; + int scr_y = view->screen.y; + int scr_width = view->screen.width; + int scr_height = view->screen.height; + int term_x = view->terminal_rect.x; + int term_y = view->terminal_rect.y; + int term_width = view->terminal_rect.width; + int term_height = view->terminal_rect.height; + + /* Check that border_width isn't too big. */ + unsigned int border_width = view->terminal_border; + unsigned int min_terminal_width; + unsigned int min_terminal_height; + get_min_terminal (terminal_font, border_width, + &min_terminal_width, &min_terminal_height); + if (border_width > 3 && ((int) min_terminal_width >= scr_width + || (int) min_terminal_height >= scr_height)) + { + border_width = 3; + get_min_terminal (terminal_font, border_width, + &min_terminal_width, &min_terminal_height); + } + + /* Sanity checks. */ + if (term_width > scr_width) + term_width = scr_width; + if (term_height > scr_height) + term_height = scr_height; + + if (scr_width <= (int) min_terminal_width + || scr_height <= (int) min_terminal_height) + { + /* The screen resulution is too low. Use all space, except a small border + to show the user, that it is a window. Then center the window. */ + term_width = scr_width - 6 * border_width; + term_height = scr_height - 6 * border_width; + term_x = scr_x + (scr_width - term_width) / 2; + term_y = scr_y + (scr_height - term_height) / 2; + } + else if (term_width < (int) min_terminal_width + || term_height < (int) min_terminal_height) + { + /* The screen resolution is big enough. Make sure, that terminal screen + dimensions aren't less than minimal values. Then center the window. */ + term_width = (int) min_terminal_width; + term_height = (int) min_terminal_height; + term_x = scr_x + (scr_width - term_width) / 2; + term_y = scr_y + (scr_height - term_height) / 2; + } + + /* At this point w and h are satisfying. */ + if (term_x + term_width > scr_width) + term_x = scr_width - term_width; + if (term_y + term_height > scr_height) + term_y = scr_height - term_height; + + /* Write down corrected data. */ + view->terminal_rect.x = (unsigned int) term_x; + view->terminal_rect.y = (unsigned int) term_y; + view->terminal_rect.width = (unsigned int) term_width; + view->terminal_rect.height = (unsigned int) term_height; + view->terminal_border = border_width; + + view->need_to_check_sanity = 0; +} + +static void +init_terminal (grub_gfxmenu_view_t view) +{ + grub_font_t terminal_font; + + terminal_font = grub_font_get (view->terminal_font_name); + if (!terminal_font) + { + grub_error (GRUB_ERR_BAD_FONT, "no font loaded"); + return; + } + + /* Check that terminal window size and position are sane. */ + terminal_sanity_check (view); + + term_view = view; + + /* Note: currently there is no API for changing the gfxterm font + on the fly, so whatever font the initially loaded theme specifies + will be permanent. */ + grub_gfxterm_set_window (GRUB_VIDEO_RENDER_TARGET_DISPLAY, + view->terminal_rect.x, + view->terminal_rect.y, + view->terminal_rect.width, + view->terminal_rect.height, + view->double_repaint, + terminal_font, + view->terminal_border); + grub_gfxterm_decorator_hook = grub_gfxmenu_draw_terminal_box; +} + +static void +init_background (grub_gfxmenu_view_t view) +{ + if (view->scaled_desktop_image || (!view->raw_desktop_image)) + return; + + struct grub_video_bitmap *scaled_bitmap; + if (view->desktop_image_scale_method == + GRUB_VIDEO_BITMAP_SELECTION_METHOD_STRETCH) + grub_video_bitmap_create_scaled (&scaled_bitmap, + view->screen.width, + view->screen.height, + view->raw_desktop_image, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + else + grub_video_bitmap_scale_proportional (&scaled_bitmap, + view->screen.width, + view->screen.height, + view->raw_desktop_image, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST, + view->desktop_image_scale_method, + view->desktop_image_v_align, + view->desktop_image_h_align); + if (! scaled_bitmap) + return; + view->scaled_desktop_image = scaled_bitmap; + +} + +/* FIXME: previously notifications were displayed in special case. + Is it necessary? + */ +#if 0 +/* Sets MESSAGE as the progress message for the view. + MESSAGE can be 0, in which case no message is displayed. */ +static void +set_progress_message (grub_gfxmenu_view_t view, const char *message) +{ + grub_free (view->progress_message_text); + if (message) + view->progress_message_text = grub_strdup (message); + else + view->progress_message_text = 0; +} + +static void +notify_booting (grub_menu_entry_t entry, void *userdata) +{ + grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata; + + char *s = grub_malloc (100 + grub_strlen (entry->title)); + if (!s) + return; + + grub_sprintf (s, "Booting '%s'", entry->title); + set_progress_message (view, s); + grub_free (s); + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); +} + +static void +notify_fallback (grub_menu_entry_t entry, void *userdata) +{ + grub_gfxmenu_view_t view = (grub_gfxmenu_view_t) userdata; + + char *s = grub_malloc (100 + grub_strlen (entry->title)); + if (!s) + return; + + grub_sprintf (s, "Falling back to '%s'", entry->title); + set_progress_message (view, s); + grub_free (s); + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); + grub_video_swap_buffers (); + if (view->double_repaint) + grub_gfxmenu_view_redraw (view, &view->progress_message_frame); +} + +static void +notify_execution_failure (void *userdata __attribute__ ((unused))) +{ +} + + +static struct grub_menu_execute_callback execute_callback = +{ + .notify_booting = notify_booting, + .notify_fallback = notify_fallback, + .notify_failure = notify_execution_failure +}; + +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/corecmd.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/corecmd.c new file mode 100644 index 0000000..ea82436 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/corecmd.c @@ -0,0 +1,200 @@ +/* corecmd.c - critical commands which are registered in kernel */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* set ENVVAR=VALUE */ +static grub_err_t +grub_core_cmd_set (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + char *var; + char *val; + + if (argc < 1) + { + struct grub_env_var *env; + FOR_SORTED_ENV (env) + grub_printf ("%s=%s\n", env->name, grub_env_get (env->name)); + return 0; + } + + var = argv[0]; + val = grub_strchr (var, '='); + if (! val) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not an assignment"); + + val[0] = 0; + grub_env_set (var, val + 1); + val[0] = '='; + + return 0; +} + +static grub_err_t +grub_core_cmd_unset (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("one argument expected")); + + grub_env_unset (argv[0]); + return 0; +} + +/* insmod MODULE */ +static grub_err_t +grub_core_cmd_insmod (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_dl_t mod; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); + + /* For simple, just disable insmod when SecureBoot is enabled. */ + if (g_sys_sb && g_sb_policy == VTOY_SB_POLICY_CHECK) + { + return grub_error (GRUB_ERR_BAD_SIGNATURE, "Cannot insmod when SecureBoot is enabled and Policy is check."); + } + + if (grub_strcmp(argv[0], "steamenv") == 0) { + grub_printf("Ventoy skip module steamenv ...\n"); + return 0; + } + + if (argv[0][0] == '/' || argv[0][0] == '(' || argv[0][0] == '+') + mod = grub_dl_load_file (argv[0]); + else + mod = grub_dl_load (argv[0]); + + if (mod) + grub_dl_ref (mod); + + return 0; +} + +static int +grub_mini_print_devices (const char *name, void *data __attribute__ ((unused))) +{ + grub_printf ("(%s) ", name); + + return 0; +} + +static int +grub_mini_print_files (const char *filename, + const struct grub_dirhook_info *info, + void *data __attribute__ ((unused))) +{ + grub_printf ("%s%s ", filename, info->dir ? "/" : ""); + + return 0; +} + +/* ls [ARG] */ +static grub_err_t +grub_core_cmd_ls (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + if (argc < 1) + { + grub_device_iterate (grub_mini_print_devices, NULL); + grub_xputs ("\n"); + grub_refresh (); + } + else + { + char *device_name; + grub_device_t dev = 0; + grub_fs_t fs; + char *path; + + device_name = grub_file_get_device_name (argv[0]); + if (grub_errno) + goto fail; + dev = grub_device_open (device_name); + if (! dev) + goto fail; + + fs = grub_fs_probe (dev); + path = grub_strchr (argv[0], ')'); + if (! path) + path = argv[0]; + else + path++; + + if (! *path && ! device_name) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument"); + goto fail; + } + + if (! *path) + { + if (grub_errno == GRUB_ERR_UNKNOWN_FS) + grub_errno = GRUB_ERR_NONE; + + grub_printf ("(%s): Filesystem is %s.\n", + device_name, fs ? fs->name : "unknown"); + } + else if (fs) + { + (fs->fs_dir) (dev, path, grub_mini_print_files, NULL); + grub_xputs ("\n"); + grub_refresh (); + } + + fail: + if (dev) + grub_device_close (dev); + + grub_free (device_name); + } + + return grub_errno; +} + +void +grub_register_core_commands (void) +{ + grub_command_t cmd; + cmd = grub_register_command ("set", grub_core_cmd_set, + N_("[ENVVAR=VALUE]"), + N_("Set an environment variable.")); + if (cmd) + cmd->flags |= GRUB_COMMAND_FLAG_EXTRACTOR; + grub_register_command ("unset", grub_core_cmd_unset, + N_("ENVVAR"), + N_("Remove an environment variable.")); + grub_register_command ("ls", grub_core_cmd_ls, + N_("[ARG]"), N_("List devices or files.")); + grub_register_command ("insmod", grub_core_cmd_insmod, + N_("MODULE"), N_("Insert a module.")); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/disk.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/disk.c new file mode 100644 index 0000000..da54dc3 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/disk.c @@ -0,0 +1,646 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GRUB_CACHE_TIMEOUT 10 + +/* The last time the disk was used. */ +static grub_uint64_t grub_last_time = 0; + +struct grub_disk_cache grub_disk_cache_table[GRUB_DISK_CACHE_NUM]; + +void (*grub_disk_firmware_fini) (void); +int grub_disk_firmware_is_tainted; + +#if DISK_CACHE_STATS +static unsigned long grub_disk_cache_hits; +static unsigned long grub_disk_cache_misses; + +void +grub_disk_cache_get_performance (unsigned long *hits, unsigned long *misses) +{ + *hits = grub_disk_cache_hits; + *misses = grub_disk_cache_misses; +} +#endif + +grub_err_t (*grub_disk_write_weak) (grub_disk_t disk, + grub_disk_addr_t sector, + grub_off_t offset, + grub_size_t size, + const void *buf); +#include "disk_common.c" + +void +grub_disk_cache_invalidate_all (void) +{ + unsigned i; + + for (i = 0; i < GRUB_DISK_CACHE_NUM; i++) + { + struct grub_disk_cache *cache = grub_disk_cache_table + i; + + if (cache->data && ! cache->lock) + { + grub_free (cache->data); + cache->data = 0; + } + } +} + +static char * +grub_disk_cache_fetch (unsigned long dev_id, unsigned long disk_id, + grub_disk_addr_t sector) +{ + struct grub_disk_cache *cache; + unsigned cache_index; + + cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector); + cache = grub_disk_cache_table + cache_index; + + if (cache->dev_id == dev_id && cache->disk_id == disk_id + && cache->sector == sector) + { + cache->lock = 1; +#if DISK_CACHE_STATS + grub_disk_cache_hits++; +#endif + return cache->data; + } + +#if DISK_CACHE_STATS + grub_disk_cache_misses++; +#endif + + return 0; +} + +static void +grub_disk_cache_unlock (unsigned long dev_id, unsigned long disk_id, + grub_disk_addr_t sector) +{ + struct grub_disk_cache *cache; + unsigned cache_index; + + cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector); + cache = grub_disk_cache_table + cache_index; + + if (cache->dev_id == dev_id && cache->disk_id == disk_id + && cache->sector == sector) + cache->lock = 0; +} + +static grub_err_t +grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id, + grub_disk_addr_t sector, const char *data) +{ + unsigned cache_index; + struct grub_disk_cache *cache; + + cache_index = grub_disk_cache_get_index (dev_id, disk_id, sector); + cache = grub_disk_cache_table + cache_index; + + cache->lock = 1; + grub_free (cache->data); + cache->data = 0; + cache->lock = 0; + + cache->data = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS); + if (! cache->data) + return grub_errno; + + grub_memcpy (cache->data, data, + GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS); + cache->dev_id = dev_id; + cache->disk_id = disk_id; + cache->sector = sector; + + return GRUB_ERR_NONE; +} + + + +grub_disk_dev_t grub_disk_dev_list; + +void +grub_disk_dev_register (grub_disk_dev_t dev) +{ + dev->next = grub_disk_dev_list; + grub_disk_dev_list = dev; +} + +void +grub_disk_dev_unregister (grub_disk_dev_t dev) +{ + grub_disk_dev_t *p, q; + + for (p = &grub_disk_dev_list, q = *p; q; p = &(q->next), q = q->next) + if (q == dev) + { + *p = q->next; + break; + } +} + +/* Return the location of the first ',', if any, which is not + escaped by a '\'. */ +static const char * +find_part_sep (const char *name) +{ + const char *p = name; + char c; + + while ((c = *p++) != '\0') + { + if (c == '\\' && *p == ',') + p++; + else if (c == ',') + return p - 1; + } + return NULL; +} + +grub_disk_t +grub_disk_open (const char *name) +{ + const char *p; + grub_disk_t disk; + grub_disk_dev_t dev; + char *raw = (char *) name; + grub_uint64_t current_time; + + grub_dprintf ("disk", "Opening `%s'...\n", name); + + disk = (grub_disk_t) grub_zalloc (sizeof (*disk)); + if (! disk) + return 0; + disk->log_sector_size = GRUB_DISK_SECTOR_BITS; + /* Default 1MiB of maximum agglomerate. */ + disk->max_agglomerate = 1048576 >> (GRUB_DISK_SECTOR_BITS + + GRUB_DISK_CACHE_BITS); + + p = find_part_sep (name); + if (p) + { + grub_size_t len = p - name; + + raw = grub_malloc (len + 1); + if (! raw) + goto fail; + + grub_memcpy (raw, name, len); + raw[len] = '\0'; + disk->name = grub_strdup (raw); + } + else + disk->name = grub_strdup (name); + if (! disk->name) + goto fail; + + for (dev = grub_disk_dev_list; dev; dev = dev->next) + { + if ((dev->disk_open) (raw, disk) == GRUB_ERR_NONE) + break; + else if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE) + grub_errno = GRUB_ERR_NONE; + else + goto fail; + } + + if (! dev) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), + name); + goto fail; + } + if (disk->log_sector_size > GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS + || disk->log_sector_size < GRUB_DISK_SECTOR_BITS) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "sector sizes of %d bytes aren't supported yet", + (1 << disk->log_sector_size)); + goto fail; + } + + disk->dev = dev; + + if (p) + { + disk->partition = grub_partition_probe (disk, p + 1); + if (! disk->partition) + { + /* TRANSLATORS: It means that the specified partition e.g. + hd0,msdos1=/dev/sda1 doesn't exist. */ + grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such partition")); + goto fail; + } + } + + /* The cache will be invalidated about 2 seconds after a device was + closed. */ + current_time = grub_get_time_ms (); + + if (current_time > (grub_last_time + + GRUB_CACHE_TIMEOUT * 1000)) + grub_disk_cache_invalidate_all (); + + grub_last_time = current_time; + + fail: + + if (raw && raw != name) + grub_free (raw); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_error_push (); + grub_dprintf ("disk", "Opening `%s' failed.\n", name); + grub_error_pop (); + + grub_disk_close (disk); + return 0; + } + + return disk; +} + +void +grub_disk_close (grub_disk_t disk) +{ + grub_partition_t part; + grub_dprintf ("disk", "Closing `%s'.\n", disk->name); + + if (disk->dev && disk->dev->disk_close) + (disk->dev->disk_close) (disk); + + /* Reset the timer. */ + grub_last_time = grub_get_time_ms (); + + while (disk->partition) + { + part = disk->partition->parent; + grub_free (disk->partition); + disk->partition = part; + } + grub_free ((void *) disk->name); + grub_free (disk); +} + +/* Small read (less than cache size and not pass across cache unit boundaries). + sector is already adjusted and is divisible by cache unit size. + */ +static grub_err_t +grub_disk_read_small_real (grub_disk_t disk, grub_disk_addr_t sector, + grub_off_t offset, grub_size_t size, void *buf) +{ + char *data; + char *tmp_buf; + + /* Fetch the cache. */ + data = grub_disk_cache_fetch (disk->dev->id, disk->id, sector); + if (data) + { + /* Just copy it! */ + grub_memcpy (buf, data + offset, size); + grub_disk_cache_unlock (disk->dev->id, disk->id, sector); + return GRUB_ERR_NONE; + } + + /* Allocate a temporary buffer. */ + tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS); + if (! tmp_buf) + return grub_errno; + + /* Otherwise read data from the disk actually. */ + if (disk->total_sectors == GRUB_DISK_SIZE_UNKNOWN + || sector + GRUB_DISK_CACHE_SIZE + < (disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS))) + { + grub_err_t err; + err = (disk->dev->disk_read) (disk, transform_sector (disk, sector), + 1U << (GRUB_DISK_CACHE_BITS + + GRUB_DISK_SECTOR_BITS + - disk->log_sector_size), tmp_buf); + if (!err) + { + /* Copy it and store it in the disk cache. */ + grub_memcpy (buf, tmp_buf + offset, size); + grub_disk_cache_store (disk->dev->id, disk->id, + sector, tmp_buf); + grub_free (tmp_buf); + return GRUB_ERR_NONE; + } + } + + grub_free (tmp_buf); + grub_errno = GRUB_ERR_NONE; + + { + /* Uggh... Failed. Instead, just read necessary data. */ + unsigned num; + grub_disk_addr_t aligned_sector; + + sector += (offset >> GRUB_DISK_SECTOR_BITS); + offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1); + aligned_sector = (sector & ~((1ULL << (disk->log_sector_size + - GRUB_DISK_SECTOR_BITS)) + - 1)); + offset += ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS); + num = ((size + offset + (1ULL << (disk->log_sector_size)) + - 1) >> (disk->log_sector_size)); + + tmp_buf = grub_malloc (num << disk->log_sector_size); + if (!tmp_buf) + return grub_errno; + + if ((disk->dev->disk_read) (disk, transform_sector (disk, aligned_sector), + num, tmp_buf)) + { + grub_error_push (); + grub_dprintf ("disk", "%s read failed\n", disk->name); + grub_error_pop (); + grub_free (tmp_buf); + return grub_errno; + } + grub_memcpy (buf, tmp_buf + offset, size); + grub_free (tmp_buf); + return GRUB_ERR_NONE; + } +} + +static grub_err_t +grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector, + grub_off_t offset, grub_size_t size, void *buf) +{ + grub_err_t err; + + err = grub_disk_read_small_real (disk, sector, offset, size, buf); + if (err) + return err; + if (disk->read_hook) + (disk->read_hook) (sector + (offset >> GRUB_DISK_SECTOR_BITS), + offset & (GRUB_DISK_SECTOR_SIZE - 1), + size, disk->read_hook_data); + return GRUB_ERR_NONE; +} + +grub_err_t grub_disk_blocklist_read(void *chunklist, grub_uint64_t sector, + grub_uint64_t size, grub_uint32_t log_sector_size) +{ + grub_uint64_t sizeshift; + ventoy_img_chunk *last_chunk = NULL; + ventoy_img_chunk *new_chunk = NULL; + ventoy_img_chunk_list *chunk_list = (ventoy_img_chunk_list *)chunklist; + + sizeshift = (size >> log_sector_size); + if (sizeshift == 0) + { + sizeshift = 1; + } + + if (chunk_list->cur_chunk == 0) + { + chunk_list->chunk[0].img_start_sector = 0; + chunk_list->chunk[0].img_end_sector = (size >> 11) - 1; + chunk_list->chunk[0].disk_start_sector = sector; + chunk_list->chunk[0].disk_end_sector = sector + sizeshift - 1; + chunk_list->cur_chunk = 1; + return 0; + } + + last_chunk = chunk_list->chunk + chunk_list->cur_chunk - 1; + if (last_chunk->disk_end_sector + 1 == sector) + { + last_chunk->img_end_sector += (size >> 11); + last_chunk->disk_end_sector += sizeshift; + return 0; + } + + if (chunk_list->cur_chunk == chunk_list->max_chunk) + { + new_chunk = grub_realloc(chunk_list->chunk, chunk_list->max_chunk * 2 * sizeof(ventoy_img_chunk)); + if (NULL == new_chunk) + { + return -1; + } + chunk_list->chunk = new_chunk; + chunk_list->max_chunk *= 2; + + /* issue: update last_chunk */ + last_chunk = chunk_list->chunk + chunk_list->cur_chunk - 1; + } + + new_chunk = chunk_list->chunk + chunk_list->cur_chunk; + new_chunk->img_start_sector = last_chunk->img_end_sector + 1; + new_chunk->img_end_sector = new_chunk->img_start_sector + (size >> 11) - 1; + new_chunk->disk_start_sector = sector; + new_chunk->disk_end_sector = sector + sizeshift - 1; + + chunk_list->cur_chunk++; + + return 0; +} + +grub_err_t grub_disk_blocklist_read2(grub_disk_t disk, grub_uint64_t sector, + grub_uint64_t size, char *buf) +{ + ventoy_img_chunk_list *chunk_list = (ventoy_img_chunk_list *)(disk->read_hook_data); + + if (buf < chunk_list->buf || buf >= chunk_list->buf + VTOY_CHUNK_BUF_SIZE) + { + return 2; + } + + if ((chunk_list->buf + chunk_list->last_off) != buf) + { + chunk_list->err_code = VTOY_CHUNK_ERR_NOT_FLAT; + return 0; + } + + if (chunk_list->last_off + size > VTOY_CHUNK_BUF_SIZE) + { + chunk_list->err_code = VTOY_CHUNK_ERR_OVER_FLOW; + return 0; + } + + chunk_list->last_off += (grub_uint32_t)size; + if (chunk_list->last_off == VTOY_CHUNK_BUF_SIZE) + { + chunk_list->last_off = 0; + } + + return grub_disk_blocklist_read(chunk_list, sector, size, disk->log_sector_size); +} + +/* Read data from the disk. */ +grub_err_t +grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, + grub_off_t offset, grub_size_t size, void *buf) +{ + if (disk->read_hook == (grub_disk_read_hook_t)(void *)grub_disk_blocklist_read) + { + return grub_disk_blocklist_read((ventoy_img_chunk_list *)disk->read_hook_data, sector, size, disk->log_sector_size); + } + else if (disk->read_hook == (grub_disk_read_hook_t)(void *)grub_disk_blocklist_read2) + { + grub_err_t rv = grub_disk_blocklist_read2(disk, sector, size, (char *)buf); + if (rv != 2) + { + return rv; + } + } + + /* First of all, check if the region is within the disk. */ + if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE) + { + grub_error_push (); + grub_dprintf ("disk", "Read out of range: sector 0x%llx (%s).\n", + (unsigned long long) sector, grub_errmsg); + grub_error_pop (); + return grub_errno; + } + + /* First read until first cache boundary. */ + if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1))) + { + grub_disk_addr_t start_sector; + grub_size_t pos; + grub_err_t err; + grub_size_t len; + + start_sector = sector & ~((grub_disk_addr_t) GRUB_DISK_CACHE_SIZE - 1); + pos = (sector - start_sector) << GRUB_DISK_SECTOR_BITS; + len = ((GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS) + - pos - offset); + if (len > size) + len = size; + err = grub_disk_read_small (disk, start_sector, + offset + pos, len, buf); + if (err) + return err; + buf = (char *) buf + len; + size -= len; + offset += len; + sector += (offset >> GRUB_DISK_SECTOR_BITS); + offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1); + } + + /* Until SIZE is zero... */ + while (size >= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS)) + { + char *data = NULL; + grub_disk_addr_t agglomerate; + grub_err_t err; + + /* agglomerate read until we find a first cached entry. */ + for (agglomerate = 0; agglomerate + < (size >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS)) + && agglomerate < disk->max_agglomerate; + agglomerate++) + { + data = grub_disk_cache_fetch (disk->dev->id, disk->id, + sector + (agglomerate + << GRUB_DISK_CACHE_BITS)); + if (data) + break; + } + + if (data) + { + grub_memcpy ((char *) buf + + (agglomerate << (GRUB_DISK_CACHE_BITS + + GRUB_DISK_SECTOR_BITS)), + data, GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS); + grub_disk_cache_unlock (disk->dev->id, disk->id, + sector + (agglomerate + << GRUB_DISK_CACHE_BITS)); + } + + if (agglomerate) + { + grub_disk_addr_t i; + + err = (disk->dev->disk_read) (disk, transform_sector (disk, sector), + agglomerate << (GRUB_DISK_CACHE_BITS + + GRUB_DISK_SECTOR_BITS + - disk->log_sector_size), + buf); + if (err) + return err; + + for (i = 0; i < agglomerate; i ++) + grub_disk_cache_store (disk->dev->id, disk->id, + sector + (i << GRUB_DISK_CACHE_BITS), + (char *) buf + + (i << (GRUB_DISK_CACHE_BITS + + GRUB_DISK_SECTOR_BITS))); + + + if (disk->read_hook) + (disk->read_hook) (sector, 0, agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS), + disk->read_hook_data); + + sector += agglomerate << GRUB_DISK_CACHE_BITS; + size -= agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS); + buf = (char *) buf + + (agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS)); + } + + if (data) + { + if (disk->read_hook) + (disk->read_hook) (sector, 0, (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS), + disk->read_hook_data); + sector += GRUB_DISK_CACHE_SIZE; + buf = (char *) buf + (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS); + size -= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS); + } + } + + /* And now read the last part. */ + if (size) + { + grub_err_t err; + err = grub_disk_read_small (disk, sector, 0, size, buf); + if (err) + return err; + } + + return grub_errno; +} + +grub_uint64_t +grub_disk_get_size (grub_disk_t disk) +{ + if (disk->partition) + return grub_partition_get_len (disk->partition); + else if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN) + return disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); + else + return GRUB_DISK_SIZE_UNKNOWN; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c new file mode 100644 index 0000000..906b42c --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c @@ -0,0 +1,983 @@ +/* efi.c - generic EFI support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The handle of GRUB itself. Filled in by the startup code. */ +grub_efi_handle_t grub_efi_image_handle; + +/* The pointer to a system table. Filled in by the startup code. */ +grub_efi_system_table_t *grub_efi_system_table; + +static grub_efi_guid_t console_control_guid = GRUB_EFI_CONSOLE_CONTROL_GUID; +static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID; +static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID; + +void * +grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration) +{ + void *interface; + grub_efi_status_t status; + + status = efi_call_3 (grub_efi_system_table->boot_services->locate_protocol, + protocol, registration, &interface); + if (status != GRUB_EFI_SUCCESS) + return 0; + + return interface; +} + +/* Return the array of handles which meet the requirement. If successful, + the number of handles is stored in NUM_HANDLES. The array is allocated + from the heap. */ +grub_efi_handle_t * +grub_efi_locate_handle (grub_efi_locate_search_type_t search_type, + grub_efi_guid_t *protocol, + void *search_key, + grub_efi_uintn_t *num_handles) +{ + grub_efi_boot_services_t *b; + grub_efi_status_t status; + grub_efi_handle_t *buffer; + grub_efi_uintn_t buffer_size = 8 * sizeof (grub_efi_handle_t); + + buffer = grub_malloc (buffer_size); + if (! buffer) + return 0; + + b = grub_efi_system_table->boot_services; + status = efi_call_5 (b->locate_handle, search_type, protocol, search_key, + &buffer_size, buffer); + if (status == GRUB_EFI_BUFFER_TOO_SMALL) + { + grub_free (buffer); + buffer = grub_malloc (buffer_size); + if (! buffer) + return 0; + + status = efi_call_5 (b->locate_handle, search_type, protocol, search_key, + &buffer_size, buffer); + } + + if (status != GRUB_EFI_SUCCESS) + { + grub_free (buffer); + return 0; + } + + *num_handles = buffer_size / sizeof (grub_efi_handle_t); + return buffer; +} + +void * +grub_efi_open_protocol (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + grub_efi_uint32_t attributes) +{ + grub_efi_boot_services_t *b; + grub_efi_status_t status; + void *interface; + + b = grub_efi_system_table->boot_services; + status = efi_call_6 (b->open_protocol, handle, + protocol, + &interface, + grub_efi_image_handle, + 0, + attributes); + if (status != GRUB_EFI_SUCCESS) + return 0; + + return interface; +} + +int +grub_efi_set_text_mode (int on) +{ + grub_efi_console_control_protocol_t *c; + grub_efi_screen_mode_t mode, new_mode; + + c = grub_efi_locate_protocol (&console_control_guid, 0); + if (! c) + /* No console control protocol instance available, assume it is + already in text mode. */ + return 1; + + if (efi_call_4 (c->get_mode, c, &mode, 0, 0) != GRUB_EFI_SUCCESS) + return 0; + + new_mode = on ? GRUB_EFI_SCREEN_TEXT : GRUB_EFI_SCREEN_GRAPHICS; + if (mode != new_mode) + if (efi_call_2 (c->set_mode, c, new_mode) != GRUB_EFI_SUCCESS) + return 0; + + return 1; +} + +void +grub_efi_stall (grub_efi_uintn_t microseconds) +{ + efi_call_1 (grub_efi_system_table->boot_services->stall, microseconds); +} + +grub_efi_loaded_image_t * +grub_efi_get_loaded_image (grub_efi_handle_t image_handle) +{ + return grub_efi_open_protocol (image_handle, + &loaded_image_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); +} + +void +grub_reboot (void) +{ + grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); + efi_call_4 (grub_efi_system_table->runtime_services->reset_system, + GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); + for (;;) ; +} + +void +grub_exit (void) +{ + grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); + efi_call_4 (grub_efi_system_table->boot_services->exit, + grub_efi_image_handle, GRUB_EFI_SUCCESS, 0, 0); + for (;;) ; +} + +grub_err_t +grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map) +{ + grub_efi_runtime_services_t *r; + grub_efi_status_t status; + + r = grub_efi_system_table->runtime_services; + status = efi_call_4 (r->set_virtual_address_map, memory_map_size, + descriptor_size, descriptor_version, virtual_map); + + if (status == GRUB_EFI_SUCCESS) + return GRUB_ERR_NONE; + + return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed"); +} + +grub_err_t +grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, + void *data, grub_size_t datasize) +{ + grub_efi_status_t status; + grub_efi_runtime_services_t *r; + grub_efi_char16_t *var16; + grub_size_t len, len16; + + len = grub_strlen (var); + len16 = len * GRUB_MAX_UTF16_PER_UTF8; + var16 = grub_malloc ((len16 + 1) * sizeof (var16[0])); + if (!var16) + return grub_errno; + len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL); + var16[len16] = 0; + + r = grub_efi_system_table->runtime_services; + + status = efi_call_5 (r->set_variable, var16, guid, + (GRUB_EFI_VARIABLE_NON_VOLATILE + | GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS + | GRUB_EFI_VARIABLE_RUNTIME_ACCESS), + datasize, data); + grub_free (var16); + if (status == GRUB_EFI_SUCCESS) + return GRUB_ERR_NONE; + + return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var); +} + +void * +grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + grub_size_t *datasize_out) +{ + grub_efi_status_t status; + grub_efi_uintn_t datasize = 0; + grub_efi_runtime_services_t *r; + grub_efi_char16_t *var16; + void *data; + grub_size_t len, len16; + + *datasize_out = 0; + + len = grub_strlen (var); + len16 = len * GRUB_MAX_UTF16_PER_UTF8; + var16 = grub_malloc ((len16 + 1) * sizeof (var16[0])); + if (!var16) + return NULL; + len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL); + var16[len16] = 0; + + r = grub_efi_system_table->runtime_services; + + status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, NULL); + + if (status != GRUB_EFI_BUFFER_TOO_SMALL || !datasize) + { + grub_free (var16); + return NULL; + } + + data = grub_malloc (datasize); + if (!data) + { + grub_free (var16); + return NULL; + } + + status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data); + grub_free (var16); + + if (status == GRUB_EFI_SUCCESS) + { + *datasize_out = datasize; + return data; + } + + grub_free (data); + return NULL; +} + +#pragma GCC diagnostic ignored "-Wcast-align" + +/* Search the mods section from the PE32/PE32+ image. This code uses + a PE32 header, but should work with PE32+ as well. */ +grub_addr_t +grub_efi_modules_addr (void) +{ + grub_efi_loaded_image_t *image; + struct grub_pe32_header *header; + struct grub_pe32_coff_header *coff_header; + struct grub_pe32_section_table *sections; + struct grub_pe32_section_table *section; + struct grub_module_info *info; + grub_uint16_t i; + + image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (! image) + return 0; + + header = image->image_base; + coff_header = &(header->coff_header); + sections + = (struct grub_pe32_section_table *) ((char *) coff_header + + sizeof (*coff_header) + + coff_header->optional_header_size); + + for (i = 0, section = sections; + i < coff_header->num_sections; + i++, section++) + { + if (grub_strcmp (section->name, "mods") == 0) + break; + } + + if (i == coff_header->num_sections) + return 0; + + info = (struct grub_module_info *) ((char *) image->image_base + + section->virtual_address); + if (info->magic != GRUB_MODULE_MAGIC) + return 0; + + return (grub_addr_t) info; +} + +#pragma GCC diagnostic error "-Wcast-align" + +char * +grub_efi_get_filename (grub_efi_device_path_t *dp0) +{ + char *name = 0, *p, *pi; + grub_size_t filesize = 0; + grub_efi_device_path_t *dp; + + if (!dp0) + return NULL; + + dp = dp0; + + while (1) + { + grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); + grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); + + if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) + break; + if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE + && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) + { + grub_efi_uint16_t len; + len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4) + / sizeof (grub_efi_char16_t)); + filesize += GRUB_MAX_UTF8_PER_UTF16 * len + 2; + } + + dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); + } + + if (!filesize) + return NULL; + + dp = dp0; + + p = name = grub_malloc (filesize); + if (!name) + return NULL; + + while (1) + { + grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); + grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); + + if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) + break; + else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE + && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) + { + grub_efi_file_path_device_path_t *fp; + grub_efi_uint16_t len; + grub_efi_char16_t *dup_name; + + *p++ = '/'; + + len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4) + / sizeof (grub_efi_char16_t)); + fp = (grub_efi_file_path_device_path_t *) dp; + /* According to EFI spec Path Name is NULL terminated */ + while (len > 0 && fp->path_name[len - 1] == 0) + len--; + + dup_name = grub_malloc (len * sizeof (*dup_name)); + if (!dup_name) + { + grub_free (name); + return NULL; + } + p = (char *) grub_utf16_to_utf8 ((unsigned char *) p, + grub_memcpy (dup_name, fp->path_name, len * sizeof (*dup_name)), + len); + grub_free (dup_name); + } + + dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); + } + + *p = '\0'; + + for (pi = name, p = name; *pi;) + { + /* EFI breaks paths with backslashes. */ + if (*pi == '\\' || *pi == '/') + { + *p++ = '/'; + while (*pi == '\\' || *pi == '/') + pi++; + continue; + } + *p++ = *pi++; + } + *p = '\0'; + + return name; +} + +grub_efi_device_path_t * +grub_efi_get_device_path (grub_efi_handle_t handle) +{ + return grub_efi_open_protocol (handle, &device_path_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); +} + +/* Return the device path node right before the end node. */ +grub_efi_device_path_t * +grub_efi_find_last_device_path (const grub_efi_device_path_t *dp) +{ + grub_efi_device_path_t *next, *p; + + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) + return 0; + + for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p); + ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next); + p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next)) + ; + + return p; +} + +/* Duplicate a device path. */ +grub_efi_device_path_t * +grub_efi_duplicate_device_path (const grub_efi_device_path_t *dp) +{ + grub_efi_device_path_t *p; + grub_size_t total_size = 0; + + for (p = (grub_efi_device_path_t *) dp; + ; + p = GRUB_EFI_NEXT_DEVICE_PATH (p)) + { + total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p); + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p)) + break; + } + + p = grub_malloc (total_size); + if (! p) + return 0; + + grub_memcpy (p, dp, total_size); + return p; +} + +static void +dump_vendor_path (const char *type, grub_efi_vendor_device_path_t *vendor) +{ + grub_uint32_t vendor_data_len = vendor->header.length - sizeof (*vendor); + grub_printf ("/%sVendor(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)[%x: ", + type, + (unsigned) vendor->vendor_guid.data1, + (unsigned) vendor->vendor_guid.data2, + (unsigned) vendor->vendor_guid.data3, + (unsigned) vendor->vendor_guid.data4[0], + (unsigned) vendor->vendor_guid.data4[1], + (unsigned) vendor->vendor_guid.data4[2], + (unsigned) vendor->vendor_guid.data4[3], + (unsigned) vendor->vendor_guid.data4[4], + (unsigned) vendor->vendor_guid.data4[5], + (unsigned) vendor->vendor_guid.data4[6], + (unsigned) vendor->vendor_guid.data4[7], + vendor_data_len); + if (vendor->header.length > sizeof (*vendor)) + { + grub_uint32_t i; + for (i = 0; i < vendor_data_len; i++) + grub_printf ("%02x ", vendor->vendor_defined_data[i]); + } + grub_printf ("]"); +} + + +/* Print the chain of Device Path nodes. This is mainly for debugging. */ +void +grub_efi_print_device_path (grub_efi_device_path_t *dp) +{ + while (1) + { + grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); + grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); + grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); + + switch (type) + { + case GRUB_EFI_END_DEVICE_PATH_TYPE: + switch (subtype) + { + case GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE: + grub_printf ("/EndEntire\n"); + //grub_putchar ('\n'); + break; + case GRUB_EFI_END_THIS_DEVICE_PATH_SUBTYPE: + grub_printf ("/EndThis\n"); + //grub_putchar ('\n'); + break; + default: + grub_printf ("/EndUnknown(%x)\n", (unsigned) subtype); + break; + } + break; + + case GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE: + switch (subtype) + { + case GRUB_EFI_PCI_DEVICE_PATH_SUBTYPE: + { + grub_efi_pci_device_path_t *pci + = (grub_efi_pci_device_path_t *) dp; + grub_printf ("/PCI(%x,%x)", + (unsigned) pci->function, (unsigned) pci->device); + } + break; + case GRUB_EFI_PCCARD_DEVICE_PATH_SUBTYPE: + { + grub_efi_pccard_device_path_t *pccard + = (grub_efi_pccard_device_path_t *) dp; + grub_printf ("/PCCARD(%x)", + (unsigned) pccard->function); + } + break; + case GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE: + { + grub_efi_memory_mapped_device_path_t *mmapped + = (grub_efi_memory_mapped_device_path_t *) dp; + grub_printf ("/MMap(%x,%llx,%llx)", + (unsigned) mmapped->memory_type, + (unsigned long long) mmapped->start_address, + (unsigned long long) mmapped->end_address); + } + break; + case GRUB_EFI_VENDOR_DEVICE_PATH_SUBTYPE: + dump_vendor_path ("Hardware", + (grub_efi_vendor_device_path_t *) dp); + break; + case GRUB_EFI_CONTROLLER_DEVICE_PATH_SUBTYPE: + { + grub_efi_controller_device_path_t *controller + = (grub_efi_controller_device_path_t *) dp; + grub_printf ("/Ctrl(%x)", + (unsigned) controller->controller_number); + } + break; + default: + grub_printf ("/UnknownHW(%x)", (unsigned) subtype); + break; + } + break; + + case GRUB_EFI_ACPI_DEVICE_PATH_TYPE: + switch (subtype) + { + case GRUB_EFI_ACPI_DEVICE_PATH_SUBTYPE: + { + grub_efi_acpi_device_path_t *acpi + = (grub_efi_acpi_device_path_t *) dp; + grub_printf ("/ACPI(%x,%x)", + (unsigned) acpi->hid, + (unsigned) acpi->uid); + } + break; + case GRUB_EFI_EXPANDED_ACPI_DEVICE_PATH_SUBTYPE: + { + grub_efi_expanded_acpi_device_path_t *eacpi + = (grub_efi_expanded_acpi_device_path_t *) dp; + grub_printf ("/ACPI("); + + if (GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp)[0] == '\0') + grub_printf ("%x,", (unsigned) eacpi->hid); + else + grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_HIDSTR (dp)); + + if (GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp)[0] == '\0') + grub_printf ("%x,", (unsigned) eacpi->uid); + else + grub_printf ("%s,", GRUB_EFI_EXPANDED_ACPI_UIDSTR (dp)); + + if (GRUB_EFI_EXPANDED_ACPI_CIDSTR (dp)[0] == '\0') + grub_printf ("%x)", (unsigned) eacpi->cid); + else + grub_printf ("%s)", GRUB_EFI_EXPANDED_ACPI_CIDSTR (dp)); + } + break; + default: + grub_printf ("/UnknownACPI(%x)", (unsigned) subtype); + break; + } + break; + + case GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE: + switch (subtype) + { + case GRUB_EFI_ATAPI_DEVICE_PATH_SUBTYPE: + { + grub_efi_atapi_device_path_t *atapi + = (grub_efi_atapi_device_path_t *) dp; + grub_printf ("/ATAPI(%x,%x,%x)", + (unsigned) atapi->primary_secondary, + (unsigned) atapi->slave_master, + (unsigned) atapi->lun); + } + break; + case GRUB_EFI_SCSI_DEVICE_PATH_SUBTYPE: + { + grub_efi_scsi_device_path_t *scsi + = (grub_efi_scsi_device_path_t *) dp; + grub_printf ("/SCSI(%x,%x)", + (unsigned) scsi->pun, + (unsigned) scsi->lun); + } + break; + case GRUB_EFI_FIBRE_CHANNEL_DEVICE_PATH_SUBTYPE: + { + grub_efi_fibre_channel_device_path_t *fc + = (grub_efi_fibre_channel_device_path_t *) dp; + grub_printf ("/FibreChannel(%llx,%llx)", + (unsigned long long) fc->wwn, + (unsigned long long) fc->lun); + } + break; + case GRUB_EFI_1394_DEVICE_PATH_SUBTYPE: + { + grub_efi_1394_device_path_t *firewire + = (grub_efi_1394_device_path_t *) dp; + grub_printf ("/1394(%llx)", + (unsigned long long) firewire->guid); + } + break; + case GRUB_EFI_USB_DEVICE_PATH_SUBTYPE: + { + grub_efi_usb_device_path_t *usb + = (grub_efi_usb_device_path_t *) dp; + grub_printf ("/USB(%x,%x)", + (unsigned) usb->parent_port_number, + (unsigned) usb->usb_interface); + } + break; + case GRUB_EFI_USB_CLASS_DEVICE_PATH_SUBTYPE: + { + grub_efi_usb_class_device_path_t *usb_class + = (grub_efi_usb_class_device_path_t *) dp; + grub_printf ("/USBClass(%x,%x,%x,%x,%x)", + (unsigned) usb_class->vendor_id, + (unsigned) usb_class->product_id, + (unsigned) usb_class->device_class, + (unsigned) usb_class->device_subclass, + (unsigned) usb_class->device_protocol); + } + break; + case GRUB_EFI_I2O_DEVICE_PATH_SUBTYPE: + { + grub_efi_i2o_device_path_t *i2o + = (grub_efi_i2o_device_path_t *) dp; + grub_printf ("/I2O(%x)", (unsigned) i2o->tid); + } + break; + case GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE: + { + grub_efi_mac_address_device_path_t *mac + = (grub_efi_mac_address_device_path_t *) dp; + grub_printf ("/MacAddr(%02x:%02x:%02x:%02x:%02x:%02x,%x)", + (unsigned) mac->mac_address[0], + (unsigned) mac->mac_address[1], + (unsigned) mac->mac_address[2], + (unsigned) mac->mac_address[3], + (unsigned) mac->mac_address[4], + (unsigned) mac->mac_address[5], + (unsigned) mac->if_type); + } + break; + case GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE: + { + grub_efi_ipv4_device_path_t *ipv4 + = (grub_efi_ipv4_device_path_t *) dp; + grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)", + (unsigned) ipv4->local_ip_address[0], + (unsigned) ipv4->local_ip_address[1], + (unsigned) ipv4->local_ip_address[2], + (unsigned) ipv4->local_ip_address[3], + (unsigned) ipv4->remote_ip_address[0], + (unsigned) ipv4->remote_ip_address[1], + (unsigned) ipv4->remote_ip_address[2], + (unsigned) ipv4->remote_ip_address[3], + (unsigned) ipv4->local_port, + (unsigned) ipv4->remote_port, + (unsigned) ipv4->protocol, + (unsigned) ipv4->static_ip_address); + } + break; + case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE: + { + grub_efi_ipv6_device_path_t *ipv6 + = (grub_efi_ipv6_device_path_t *) dp; + grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)", + (unsigned) ipv6->local_ip_address[0], + (unsigned) ipv6->local_ip_address[1], + (unsigned) ipv6->local_ip_address[2], + (unsigned) ipv6->local_ip_address[3], + (unsigned) ipv6->local_ip_address[4], + (unsigned) ipv6->local_ip_address[5], + (unsigned) ipv6->local_ip_address[6], + (unsigned) ipv6->local_ip_address[7], + (unsigned) ipv6->remote_ip_address[0], + (unsigned) ipv6->remote_ip_address[1], + (unsigned) ipv6->remote_ip_address[2], + (unsigned) ipv6->remote_ip_address[3], + (unsigned) ipv6->remote_ip_address[4], + (unsigned) ipv6->remote_ip_address[5], + (unsigned) ipv6->remote_ip_address[6], + (unsigned) ipv6->remote_ip_address[7], + (unsigned) ipv6->local_port, + (unsigned) ipv6->remote_port, + (unsigned) ipv6->protocol, + (unsigned) ipv6->static_ip_address); + } + break; + case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE: + { + grub_efi_infiniband_device_path_t *ib + = (grub_efi_infiniband_device_path_t *) dp; + grub_printf ("/InfiniBand(%x,%llx,%llx,%llx)", + (unsigned) ib->port_gid[0], /* XXX */ + (unsigned long long) ib->remote_id, + (unsigned long long) ib->target_port_id, + (unsigned long long) ib->device_id); + } + break; + case GRUB_EFI_UART_DEVICE_PATH_SUBTYPE: + { + grub_efi_uart_device_path_t *uart + = (grub_efi_uart_device_path_t *) dp; + grub_printf ("/UART(%llu,%u,%x,%x)", + (unsigned long long) uart->baud_rate, + uart->data_bits, + uart->parity, + uart->stop_bits); + } + break; + case GRUB_EFI_SATA_DEVICE_PATH_SUBTYPE: + { + grub_efi_sata_device_path_t *sata; + sata = (grub_efi_sata_device_path_t *) dp; + grub_printf ("/Sata(%x,%x,%x)", + sata->hba_port, + sata->multiplier_port, + sata->lun); + } + break; + + case GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE: + dump_vendor_path ("Messaging", + (grub_efi_vendor_device_path_t *) dp); + break; + default: + grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype); + break; + } + break; + + case GRUB_EFI_MEDIA_DEVICE_PATH_TYPE: + switch (subtype) + { + case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE: + { + grub_efi_hard_drive_device_path_t *hd = (grub_efi_hard_drive_device_path_t *) dp; + grub_printf ("/HD(%u,%llx,%llx,%02x%02x%02x%02x%02x%02x%02x%02x,%x,%x)", + hd->partition_number, + (unsigned long long) hd->partition_start, + (unsigned long long) hd->partition_size, + (unsigned) hd->partition_signature[0], + (unsigned) hd->partition_signature[1], + (unsigned) hd->partition_signature[2], + (unsigned) hd->partition_signature[3], + (unsigned) hd->partition_signature[4], + (unsigned) hd->partition_signature[5], + (unsigned) hd->partition_signature[6], + (unsigned) hd->partition_signature[7], + (unsigned) hd->partmap_type, + (unsigned) hd->signature_type); + } + break; + case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE: + { + grub_efi_cdrom_device_path_t *cd + = (grub_efi_cdrom_device_path_t *) dp; + grub_printf ("/CD(%u,%llx,%llx)", + cd->boot_entry, + (unsigned long long) cd->partition_start, + (unsigned long long) cd->partition_size); + } + break; + case GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE: + dump_vendor_path ("Media", + (grub_efi_vendor_device_path_t *) dp); + break; + case GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE: + { + grub_efi_file_path_device_path_t *fp; + grub_uint8_t *buf; + fp = (grub_efi_file_path_device_path_t *) dp; + buf = grub_malloc ((len - 4) * 2 + 1); + if (buf) + { + grub_efi_char16_t *dup_name = grub_malloc (len - 4); + if (!dup_name) + { + grub_errno = GRUB_ERR_NONE; + grub_printf ("/File((null))"); + grub_free (buf); + break; + } + *grub_utf16_to_utf8 (buf, grub_memcpy (dup_name, fp->path_name, len - 4), + (len - 4) / sizeof (grub_efi_char16_t)) + = '\0'; + grub_free (dup_name); + } + else + grub_errno = GRUB_ERR_NONE; + grub_printf ("/File(%s)", buf); + grub_free (buf); + } + break; + case GRUB_EFI_PROTOCOL_DEVICE_PATH_SUBTYPE: + { + grub_efi_protocol_device_path_t *proto + = (grub_efi_protocol_device_path_t *) dp; + grub_printf ("/Protocol(%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)", + (unsigned) proto->guid.data1, + (unsigned) proto->guid.data2, + (unsigned) proto->guid.data3, + (unsigned) proto->guid.data4[0], + (unsigned) proto->guid.data4[1], + (unsigned) proto->guid.data4[2], + (unsigned) proto->guid.data4[3], + (unsigned) proto->guid.data4[4], + (unsigned) proto->guid.data4[5], + (unsigned) proto->guid.data4[6], + (unsigned) proto->guid.data4[7]); + } + break; + default: + grub_printf ("/UnknownMedia(%x)", (unsigned) subtype); + break; + } + break; + + case GRUB_EFI_BIOS_DEVICE_PATH_TYPE: + switch (subtype) + { + case GRUB_EFI_BIOS_DEVICE_PATH_SUBTYPE: + { + grub_efi_bios_device_path_t *bios + = (grub_efi_bios_device_path_t *) dp; + grub_printf ("/BIOS(%x,%x,%s)", + (unsigned) bios->device_type, + (unsigned) bios->status_flags, + (char *) (dp + 1)); + } + break; + default: + grub_printf ("/UnknownBIOS(%x)", (unsigned) subtype); + break; + } + break; + + default: + grub_printf ("/UnknownType(%x,%x)\n", + (unsigned) type, + (unsigned) subtype); + return; + break; + } + + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) + break; + + dp = (grub_efi_device_path_t *) ((char *) dp + len); + } +} + +/* Compare device paths. */ +int +grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1, + const grub_efi_device_path_t *dp2) +{ + if (! dp1 || ! dp2) + /* Return non-zero. */ + return 1; + + while (1) + { + grub_efi_uint8_t type1, type2; + grub_efi_uint8_t subtype1, subtype2; + grub_efi_uint16_t len1, len2; + int ret; + + type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1); + type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2); + + if (type1 != type2) + return (int) type2 - (int) type1; + + subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1); + subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2); + + if (subtype1 != subtype2) + return (int) subtype1 - (int) subtype2; + + len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1); + len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2); + + if (len1 != len2) + return (int) len1 - (int) len2; + + ret = grub_memcmp (dp1, dp2, len1); + if (ret != 0) + return ret; + + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1)) + break; + + dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1); + dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2); + } + + return 0; +} + +void * grub_efi_allocate_iso_buf(grub_uint64_t size) +{ + grub_efi_boot_services_t *b; + grub_efi_status_t status; + grub_efi_physical_address_t address = 0; + grub_efi_uintn_t pages = GRUB_EFI_BYTES_TO_PAGES(size); + + b = grub_efi_system_table->boot_services; + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, GRUB_EFI_RUNTIME_SERVICES_DATA, pages, &address); + if (status != GRUB_EFI_SUCCESS) + { + return NULL; + } + + return (void *)(unsigned long)address; +} + +void * grub_efi_allocate_chain_buf(grub_uint64_t size) +{ + grub_efi_boot_services_t *b; + grub_efi_status_t status; + grub_efi_physical_address_t address = 0; + grub_efi_uintn_t pages = GRUB_EFI_BYTES_TO_PAGES(size); + + b = grub_efi_system_table->boot_services; + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, GRUB_EFI_LOADER_DATA, pages, &address); + if (status != GRUB_EFI_SUCCESS) + { + return NULL; + } + + return (void *)(unsigned long)address; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/mm.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/mm.c new file mode 100644 index 0000000..ab1399f --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/mm.c @@ -0,0 +1,702 @@ +/* mm.c - generic EFI memory management */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +#if defined (__i386__) || defined (__x86_64__) +#include +#endif + +#define NEXT_MEMORY_DESCRIPTOR(desc, size) \ + ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) + +#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) +#define BYTES_TO_PAGES_DOWN(bytes) ((bytes) >> 12) +#define PAGES_TO_BYTES(pages) ((pages) << 12) + +/* The size of a memory map obtained from the firmware. This must be + a multiplier of 4KB. */ +#define MEMORY_MAP_SIZE 0x3000 + +/* The minimum and maximum heap size for GRUB itself. */ +#define MIN_HEAP_SIZE 0x100000 +#define MAX_HEAP_SIZE (1600 * 0x100000) + +static void *finish_mmap_buf = 0; +static grub_efi_uintn_t finish_mmap_size = 0; +static grub_efi_uintn_t finish_key = 0; +static grub_efi_uintn_t finish_desc_size; +static grub_efi_uint32_t finish_desc_version; +int grub_efi_is_finished = 0; + +/* 160MB 160 * 1024 * 1024 / 4096 */ +#define VTOY_CHAIN_MIN_PAGES (160 * 256) +static grub_efi_uint64_t g_total_pages; +static grub_efi_uint64_t g_org_required_pages; +static grub_efi_uint64_t g_new_required_pages; + +/* + * We need to roll back EFI allocations on exit. Remember allocations that + * we'll free on exit. + */ +struct efi_allocation; +struct efi_allocation { + grub_efi_physical_address_t address; + grub_efi_uint64_t pages; + struct efi_allocation *next; +}; +static struct efi_allocation *efi_allocated_memory; + +static void +grub_efi_store_alloc (grub_efi_physical_address_t address, + grub_efi_uintn_t pages) +{ + grub_efi_boot_services_t *b; + struct efi_allocation *alloc; + grub_efi_status_t status; + + b = grub_efi_system_table->boot_services; + status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA, + sizeof(*alloc), (void**)&alloc); + + if (status == GRUB_EFI_SUCCESS) + { + alloc->next = efi_allocated_memory; + alloc->address = address; + alloc->pages = pages; + efi_allocated_memory = alloc; + } + else + grub_printf ("Could not malloc memory to remember EFI allocation. " + "Exiting GRUB won't free all memory.\n"); +} + +static void +grub_efi_drop_alloc (grub_efi_physical_address_t address, + grub_efi_uintn_t pages) +{ + struct efi_allocation *ea, *eap; + grub_efi_boot_services_t *b; + + b = grub_efi_system_table->boot_services; + + for (eap = NULL, ea = efi_allocated_memory; ea; eap = ea, ea = ea->next) + { + if (ea->address != address || ea->pages != pages) + continue; + + /* Remove the current entry from the list. */ + if (eap) + eap->next = ea->next; + else + efi_allocated_memory = ea->next; + + /* Then free the memory backing it. */ + efi_call_1 (b->free_pool, ea); + + /* And leave, we're done. */ + break; + } +} + +/* Allocate pages. Return the pointer to the first of allocated pages. */ +void * +grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + grub_efi_uintn_t pages, + grub_efi_allocate_type_t alloctype, + grub_efi_memory_type_t memtype) +{ + grub_efi_status_t status; + grub_efi_boot_services_t *b; + + /* Limit the memory access to less than 4GB for 32-bit platforms. */ + if (address > GRUB_EFI_MAX_USABLE_ADDRESS) + return 0; + + b = grub_efi_system_table->boot_services; + status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); + if (status != GRUB_EFI_SUCCESS) + return 0; + + if (address == 0) + { + /* Uggh, the address 0 was allocated... This is too annoying, + so reallocate another one. */ + address = GRUB_EFI_MAX_USABLE_ADDRESS; + status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); + grub_efi_free_pages (0, pages); + if (status != GRUB_EFI_SUCCESS) + return 0; + } + + grub_efi_store_alloc (address, pages); + + return (void *) ((grub_addr_t) address); +} + +void * +grub_efi_allocate_any_pages (grub_efi_uintn_t pages) +{ + return grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS, + pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, + GRUB_EFI_LOADER_DATA); +} + +void * +grub_efi_allocate_fixed (grub_efi_physical_address_t address, + grub_efi_uintn_t pages) +{ + return grub_efi_allocate_pages_real (address, pages, + GRUB_EFI_ALLOCATE_ADDRESS, + GRUB_EFI_LOADER_DATA); +} + +/* Free pages starting from ADDRESS. */ +void +grub_efi_free_pages (grub_efi_physical_address_t address, + grub_efi_uintn_t pages) +{ + grub_efi_boot_services_t *b; + + b = grub_efi_system_table->boot_services; + efi_call_2 (b->free_pages, address, pages); + + grub_efi_drop_alloc (address, pages); +} + +#if defined (__i386__) || defined (__x86_64__) + +/* Helper for stop_broadcom. */ +static int +find_card (grub_pci_device_t dev, grub_pci_id_t pciid, + void *data __attribute__ ((unused))) +{ + grub_pci_address_t addr; + grub_uint8_t cap; + grub_uint16_t pm_state; + + if ((pciid & 0xffff) != GRUB_PCI_VENDOR_BROADCOM) + return 0; + + addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); + if (grub_pci_read (addr) >> 24 != GRUB_PCI_CLASS_NETWORK) + return 0; + cap = grub_pci_find_capability (dev, GRUB_PCI_CAP_POWER_MANAGEMENT); + if (!cap) + return 0; + addr = grub_pci_make_address (dev, cap + 4); + pm_state = grub_pci_read_word (addr); + pm_state = pm_state | 0x03; + grub_pci_write_word (addr, pm_state); + grub_pci_read_word (addr); + return 0; +} + +static void +stop_broadcom (void) +{ + grub_pci_iterate (find_card, NULL); +} + +#endif + +grub_err_t +grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *efi_desc_size, + grub_efi_uint32_t *efi_desc_version) +{ + grub_efi_boot_services_t *b; + grub_efi_status_t status; + +#if defined (__i386__) || defined (__x86_64__) + const grub_uint16_t apple[] = { 'A', 'p', 'p', 'l', 'e' }; + int is_apple; + + is_apple = (grub_memcmp (grub_efi_system_table->firmware_vendor, + apple, sizeof (apple)) == 0); +#endif + + while (1) + { + if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf, &finish_key, + &finish_desc_size, &finish_desc_version) < 0) + return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map"); + + if (outbuf && *outbuf_size < finish_mmap_size) + return grub_error (GRUB_ERR_IO, "memory map buffer is too small"); + + finish_mmap_buf = grub_malloc (finish_mmap_size); + if (!finish_mmap_buf) + return grub_errno; + + if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf, &finish_key, + &finish_desc_size, &finish_desc_version) <= 0) + { + grub_free (finish_mmap_buf); + return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map"); + } + + b = grub_efi_system_table->boot_services; + status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle, + finish_key); + if (status == GRUB_EFI_SUCCESS) + break; + + if (status != GRUB_EFI_INVALID_PARAMETER) + { + grub_free (finish_mmap_buf); + return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services"); + } + + grub_free (finish_mmap_buf); + grub_printf ("Trying to terminate EFI services again\n"); + } + grub_efi_is_finished = 1; + if (outbuf_size) + *outbuf_size = finish_mmap_size; + if (outbuf) + grub_memcpy (outbuf, finish_mmap_buf, finish_mmap_size); + if (map_key) + *map_key = finish_key; + if (efi_desc_size) + *efi_desc_size = finish_desc_size; + if (efi_desc_version) + *efi_desc_version = finish_desc_version; + +#if defined (__i386__) || defined (__x86_64__) + if (is_apple) + stop_broadcom (); +#endif + + return GRUB_ERR_NONE; +} + +/* + * To obtain the UEFI memory map, we must pass a buffer of sufficient size + * to hold the entire map. This function returns a sane start value for + * buffer size. + */ +grub_efi_uintn_t +grub_efi_find_mmap_size (void) +{ + grub_efi_uintn_t mmap_size = 0; + grub_efi_uintn_t desc_size; + + if (grub_efi_get_memory_map (&mmap_size, NULL, NULL, &desc_size, 0) < 0) + { + grub_error (GRUB_ERR_IO, "cannot get EFI memory map size"); + return 0; + } + + /* + * Add an extra page, since UEFI can alter the memory map itself on + * callbacks or explicit calls, including console output. + */ + return ALIGN_UP (mmap_size + GRUB_EFI_PAGE_SIZE, GRUB_EFI_PAGE_SIZE); +} + +/* Get the memory map as defined in the EFI spec. Return 1 if successful, + return 0 if partial, or return -1 if an error occurs. */ +int +grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size, + grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version) +{ + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_efi_uintn_t key; + grub_efi_uint32_t version; + grub_efi_uintn_t size; + + if (grub_efi_is_finished) + { + int ret = 1; + if (*memory_map_size < finish_mmap_size) + { + grub_memcpy (memory_map, finish_mmap_buf, *memory_map_size); + ret = 0; + } + else + { + grub_memcpy (memory_map, finish_mmap_buf, finish_mmap_size); + ret = 1; + } + *memory_map_size = finish_mmap_size; + if (map_key) + *map_key = finish_key; + if (descriptor_size) + *descriptor_size = finish_desc_size; + if (descriptor_version) + *descriptor_version = finish_desc_version; + return ret; + } + + /* Allow some parameters to be missing. */ + if (! map_key) + map_key = &key; + if (! descriptor_version) + descriptor_version = &version; + if (! descriptor_size) + descriptor_size = &size; + + b = grub_efi_system_table->boot_services; + status = efi_call_5 (b->get_memory_map, memory_map_size, memory_map, map_key, + descriptor_size, descriptor_version); + if (*descriptor_size == 0) + *descriptor_size = sizeof (grub_efi_memory_descriptor_t); + if (status == GRUB_EFI_SUCCESS) + return 1; + else if (status == GRUB_EFI_BUFFER_TOO_SMALL) + return 0; + else + return -1; +} + +/* Sort the memory map in place. */ +static void +sort_memory_map (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end) +{ + grub_efi_memory_descriptor_t *d1; + grub_efi_memory_descriptor_t *d2; + + for (d1 = memory_map; + d1 < memory_map_end; + d1 = NEXT_MEMORY_DESCRIPTOR (d1, desc_size)) + { + grub_efi_memory_descriptor_t *max_desc = d1; + + for (d2 = NEXT_MEMORY_DESCRIPTOR (d1, desc_size); + d2 < memory_map_end; + d2 = NEXT_MEMORY_DESCRIPTOR (d2, desc_size)) + { + if (max_desc->num_pages < d2->num_pages) + max_desc = d2; + } + + if (max_desc != d1) + { + grub_efi_memory_descriptor_t tmp; + + tmp = *d1; + *d1 = *max_desc; + *max_desc = tmp; + } + } +} + +/* Filter the descriptors. GRUB needs only available memory. */ +static grub_efi_memory_descriptor_t * +filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + grub_efi_memory_descriptor_t *filtered_memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end) +{ + grub_efi_memory_descriptor_t *desc; + grub_efi_memory_descriptor_t *filtered_desc; + + for (desc = memory_map, filtered_desc = filtered_memory_map; + desc < memory_map_end; + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + { + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY +#if 1 + && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS +#endif + && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 + && desc->num_pages != 0) + { + grub_memcpy (filtered_desc, desc, desc_size); + + /* Avoid less than 1MB, because some loaders seem to be confused. */ + if (desc->physical_start < 0x100000) + { + desc->num_pages -= BYTES_TO_PAGES (0x100000 + - desc->physical_start); + desc->physical_start = 0x100000; + } + +#if 1 + if (BYTES_TO_PAGES (filtered_desc->physical_start) + + filtered_desc->num_pages + > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)) + filtered_desc->num_pages + = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS) + - BYTES_TO_PAGES (filtered_desc->physical_start)); +#endif + + if (filtered_desc->num_pages == 0) + continue; + + filtered_desc = NEXT_MEMORY_DESCRIPTOR (filtered_desc, desc_size); + } + } + + return filtered_desc; +} + +/* Return the total number of pages. */ +static grub_efi_uint64_t +get_total_pages (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end) +{ + grub_efi_memory_descriptor_t *desc; + grub_efi_uint64_t total = 0; + + for (desc = memory_map; + desc < memory_map_end; + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + total += desc->num_pages; + + return total; +} + +/* Add memory regions. */ +static void +add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end, + grub_efi_uint64_t required_pages) +{ + grub_efi_memory_descriptor_t *desc; + + for (desc = memory_map; + desc < memory_map_end; + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + { + grub_efi_uint64_t pages; + grub_efi_physical_address_t start; + void *addr; + + start = desc->physical_start; + pages = desc->num_pages; + if (pages > required_pages) + { + start += PAGES_TO_BYTES (pages - required_pages); + pages = required_pages; + } + + addr = grub_efi_allocate_pages_real (start, pages, + GRUB_EFI_ALLOCATE_ADDRESS, + GRUB_EFI_LOADER_CODE); + if (! addr) + grub_fatal ("cannot allocate conventional memory %p with %u pages", + (void *) ((grub_addr_t) start), + (unsigned) pages); + + grub_mm_init_region (addr, PAGES_TO_BYTES (pages)); + + required_pages -= pages; + if (required_pages == 0) + break; + } + + if (required_pages > 0) + grub_fatal ("too little memory"); +} + +void +grub_efi_memory_fini (void) +{ + /* + * Free all stale allocations. grub_efi_free_pages() will remove + * the found entry from the list and it will always find the first + * list entry (efi_allocated_memory is the list start). Hence we + * remove all entries from the list until none is left altogether. + */ + while (efi_allocated_memory) + grub_efi_free_pages (efi_allocated_memory->address, + efi_allocated_memory->pages); +} + +#if 0 +/* Print the memory map. */ +static void +print_memory_map (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end) +{ + grub_efi_memory_descriptor_t *desc; + int i; + + for (desc = memory_map, i = 0; + desc < memory_map_end; + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size), i++) + { + grub_printf ("MD: t=%x, p=%llx, v=%llx, n=%llx, a=%llx\n", + desc->type, desc->physical_start, desc->virtual_start, + desc->num_pages, desc->attribute); + } +} +#endif + +void +grub_efi_mm_init (void) +{ + grub_efi_memory_descriptor_t *memory_map; + grub_efi_memory_descriptor_t *memory_map_end; + grub_efi_memory_descriptor_t *filtered_memory_map; + grub_efi_memory_descriptor_t *filtered_memory_map_end; + grub_efi_uintn_t map_size; + grub_efi_uintn_t desc_size; + grub_efi_uint64_t total_pages; + grub_efi_uint64_t required_pages; + int mm_status; + + /* Prepare a memory region to store two memory maps. */ + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + if (! memory_map) + grub_fatal ("cannot allocate memory"); + + /* Obtain descriptors for available memory. */ + map_size = MEMORY_MAP_SIZE; + + mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0, &desc_size, 0); + + if (mm_status == 0) + { + grub_efi_free_pages + ((grub_efi_physical_address_t) ((grub_addr_t) memory_map), + 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + + /* Freeing/allocating operations may increase memory map size. */ + map_size += desc_size * 32; + + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size)); + if (! memory_map) + grub_fatal ("cannot allocate memory"); + + mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0, + &desc_size, 0); + } + + if (mm_status < 0) + grub_fatal ("cannot get memory map"); + + memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size); + + filtered_memory_map = memory_map_end; + + filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map, + desc_size, memory_map_end); + + /* By default, request a quarter of the available memory. */ + total_pages = get_total_pages (filtered_memory_map, desc_size, + filtered_memory_map_end); + + #if defined (__mips__) && (_MIPS_SIM == _ABI64) + required_pages = (total_pages > 4096) ? (total_pages - 4096) : (total_pages >> 1); + #else + required_pages = (total_pages >> 2); + #endif + + if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE)) + required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE); + else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE)) + required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE); + + g_org_required_pages = required_pages; + if (((total_pages - required_pages) >> 2) < VTOY_CHAIN_MIN_PAGES) + { + if (total_pages > (VTOY_CHAIN_MIN_PAGES << 2)) + { + g_new_required_pages = total_pages - (VTOY_CHAIN_MIN_PAGES << 2); + if (g_new_required_pages >= 8192) + { + required_pages = g_new_required_pages; + } + } + } + + g_total_pages = total_pages; + g_new_required_pages = required_pages; + + /* Sort the filtered descriptors, so that GRUB can allocate pages + from smaller regions. */ + sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); + + /* Allocate memory regions for GRUB's memory management. */ + add_memory_regions (filtered_memory_map, desc_size, + filtered_memory_map_end, required_pages); + +#if 0 + /* For debug. */ + map_size = MEMORY_MAP_SIZE; + + if (grub_efi_get_memory_map (&map_size, memory_map, 0, &desc_size, 0) < 0) + grub_fatal ("cannot get memory map"); + + grub_printf ("printing memory map\n"); + print_memory_map (memory_map, desc_size, + NEXT_MEMORY_DESCRIPTOR (memory_map, map_size)); + grub_fatal ("Debug. "); +#endif + + /* Release the memory maps. */ + grub_efi_free_pages ((grub_addr_t) memory_map, + 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); +} + +#if defined (__aarch64__) || defined (__arm__) || defined (__riscv) +grub_err_t +grub_efi_get_ram_base(grub_addr_t *base_addr) +{ + grub_efi_memory_descriptor_t *memory_map, *desc; + grub_efi_uintn_t memory_map_size, desc_size; + int ret; + + memory_map_size = grub_efi_find_mmap_size(); + + memory_map = grub_malloc (memory_map_size); + if (! memory_map) + return GRUB_ERR_OUT_OF_MEMORY; + ret = grub_efi_get_memory_map (&memory_map_size, memory_map, NULL, + &desc_size, NULL); + + if (ret < 1) + return GRUB_ERR_BUG; + + for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS; + (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + if (desc->attribute & GRUB_EFI_MEMORY_WB) + *base_addr = grub_min (*base_addr, desc->physical_start); + + grub_free(memory_map); + + return GRUB_ERR_NONE; +} +#endif + +void grub_efi_get_reserved_page_num(grub_uint64_t *total, grub_uint64_t *org_required, grub_uint64_t *new_required) +{ + *total = g_total_pages; + *org_required = g_org_required_pages; + *new_required = g_new_required_pages; +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/env.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/env.c new file mode 100644 index 0000000..ea105fc --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/env.c @@ -0,0 +1,253 @@ +/* env.c - Environment variables */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include + +grub_uint8_t g_sys_sb = 0; +grub_uint8_t g_sb_policy = VTOY_SB_POLICY_BYPASS; + +/* The initial context. */ +static struct grub_env_context initial_context; + +/* The current context. */ +struct grub_env_context *grub_current_context = &initial_context; + +static grub_env_read_hook_t vtoy_menu_lang_read_hook; + +/* Return the hash representation of the string S. */ +static unsigned int +grub_env_hashval (const char *s) +{ + unsigned int i = 0; + + /* XXX: This can be done much more efficiently. */ + while (*s) + i += 5 * *(s++); + + return i % HASHSZ; +} + +static struct grub_env_var * +grub_env_find (const char *name) +{ + struct grub_env_var *var; + int idx = grub_env_hashval (name); + + /* Look for the variable in the current context. */ + for (var = grub_current_context->vars[idx]; var; var = var->next) + if (grub_strcmp (var->name, name) == 0) + return var; + + return 0; +} + +static void +grub_env_insert (struct grub_env_context *context, + struct grub_env_var *var) +{ + int idx = grub_env_hashval (var->name); + + /* Insert the variable into the hashtable. */ + var->prevp = &context->vars[idx]; + var->next = context->vars[idx]; + if (var->next) + var->next->prevp = &(var->next); + context->vars[idx] = var; +} + +static void +grub_env_remove (struct grub_env_var *var) +{ + /* Remove the entry from the variable table. */ + *var->prevp = var->next; + if (var->next) + var->next->prevp = var->prevp; +} + +grub_err_t +grub_env_set (const char *name, const char *val) +{ + struct grub_env_var *var; + + /* If the variable does already exist, just update the variable. */ + var = grub_env_find (name); + if (var) + { + char *old = var->value; + + if (var->write_hook) + var->value = var->write_hook (var, val); + else + var->value = grub_strdup (val); + + if (! var->value) + { + var->value = old; + return grub_errno; + } + + grub_free (old); + return GRUB_ERR_NONE; + } + + /* The variable does not exist, so create a new one. */ + var = grub_zalloc (sizeof (*var)); + if (! var) + return grub_errno; + + var->name = grub_strdup (name); + if (! var->name) + goto fail; + + var->value = grub_strdup (val); + if (! var->value) + goto fail; + + grub_env_insert (grub_current_context, var); + + return GRUB_ERR_NONE; + + fail: + grub_free (var->name); + grub_free (var->value); + grub_free (var); + + return grub_errno; +} + +const char * +grub_env_get (const char *name) +{ + struct grub_env_var *var; + + if (name && vtoy_menu_lang_read_hook && grub_strncmp(name, "VTLANG_", 7) == 0) + return vtoy_menu_lang_read_hook(NULL, name); + + var = grub_env_find (name); + if (! var) + return 0; + + if (var->read_hook) + return var->read_hook (var, var->value); + + return var->value; +} + +void +grub_env_unset (const char *name) +{ + struct grub_env_var *var; + + var = grub_env_find (name); + if (! var) + return; + + if (var->read_hook || var->write_hook) + { + grub_env_set (name, ""); + return; + } + + grub_env_remove (var); + + grub_free (var->name); + grub_free (var->value); + grub_free (var); +} + +struct grub_env_var * +grub_env_update_get_sorted (void) +{ + struct grub_env_var *sorted_list = 0; + int i; + + /* Add variables associated with this context into a sorted list. */ + for (i = 0; i < HASHSZ; i++) + { + struct grub_env_var *var; + + for (var = grub_current_context->vars[i]; var; var = var->next) + { + struct grub_env_var *p, **q; + + for (q = &sorted_list, p = *q; p; q = &((*q)->sorted_next), p = *q) + { + if (grub_strcmp (p->name, var->name) > 0) + break; + } + + var->sorted_next = *q; + *q = var; + } + } + + return sorted_list; +} + +grub_err_t +grub_register_variable_hook (const char *name, + grub_env_read_hook_t read_hook, + grub_env_write_hook_t write_hook) +{ + struct grub_env_var *var = grub_env_find (name); + + if (! var) + { + if (grub_env_set (name, "") != GRUB_ERR_NONE) + return grub_errno; + + var = grub_env_find (name); + /* XXX Insert an assertion? */ + } + + var->read_hook = read_hook; + var->write_hook = write_hook; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_register_vtoy_menu_lang_hook(grub_env_read_hook_t read_hook) +{ + vtoy_menu_lang_read_hook = read_hook; + return GRUB_ERR_NONE; +} + +grub_err_t +grub_env_export (const char *name) +{ + struct grub_env_var *var; + + var = grub_env_find (name); + if (! var) + { + grub_err_t err; + + err = grub_env_set (name, ""); + if (err) + return err; + var = grub_env_find (name); + } + var->global = 1; + + return GRUB_ERR_NONE; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c new file mode 100644 index 0000000..4e09ce1 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/file.c @@ -0,0 +1,399 @@ +/* file.c - file I/O functions */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2006,2007,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +void (*EXPORT_VAR (grub_grubnet_fini)) (void); + +grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX]; + +/* Get the device part of the filename NAME. It is enclosed by parentheses. */ +char * +grub_file_get_device_name (const char *name) +{ + if (name[0] == '(') + { + char *p = grub_strchr (name, ')'); + char *ret; + + if (! p) + { + grub_error (GRUB_ERR_BAD_FILENAME, N_("missing `%c' symbol"), ')'); + return 0; + } + + ret = (char *) grub_malloc (p - name); + if (! ret) + return 0; + + grub_memcpy (ret, name + 1, p - name - 1); + ret[p - name - 1] = '\0'; + return ret; + } + + return 0; +} + +/* Support mem:xxx:size:xxx format in chainloader */ +grub_file_t grub_memfile_open(const char *name); +#define GRUB_MEMFILE_MEM "mem:" +#define GRUB_MEMFILE_SIZE "size:" + +grub_file_t grub_memfile_open(const char *name) +{ + char *size = NULL; + grub_file_t file = 0; + + file = (grub_file_t)grub_zalloc(sizeof(*file)); + if (NULL == file) + { + return 0; + } + + file->name = grub_strdup(name); + file->data = (void *)grub_strtoul(name + grub_strlen(GRUB_MEMFILE_MEM), NULL, 0); + + size = grub_strstr(name, GRUB_MEMFILE_SIZE); + file->size = (grub_off_t)grub_strtoul(size + grub_strlen(GRUB_MEMFILE_SIZE), NULL, 0); + + grub_errno = GRUB_ERR_NONE; + return file; +} + +int ventoy_check_file_exist(const char * fmt, ...) +{ + va_list ap; + grub_file_t file; + char fullpath[256] = {0}; + + va_start (ap, fmt); + grub_vsnprintf(fullpath, 255, fmt, ap); + va_end (ap); + + file = grub_file_open(fullpath, GRUB_FILE_TYPE_NONE); + if (!file) + { + grub_errno = 0; + return 0; + } + else + { + grub_file_close(file); + return 1; + } +} + +typedef struct grub_vlnk +{ + int srclen; + char src[512]; + char dst[512]; + struct grub_vlnk *next; +}grub_vlnk; + +static grub_vlnk g_vtoy_vlnk; +static grub_vlnk *g_vlnk_list; + +int grub_file_is_vlnk_suffix(const char *name, int len) +{ + grub_uint32_t suffix; + + if (len > 9) + { + suffix = *(grub_uint32_t *)(name + len - 4); + if (grub_strncmp(name + len - 9, ".vlnk.", 6) == 0) + { + /* .iso .wim .img .vhd .efi .dat */ + if (suffix == 0x6F73692E || suffix == 0x6D69772E || + suffix == 0x676D692E || suffix == 0x6468762E || + suffix == 0x6966652E || suffix == 0x7461642E) + { + return 1; + } + } + else if (len > 10 && grub_strncmp(name + len - 10, ".vlnk.", 6) == 0) + { + /* vhdx vtoy */ + if (suffix == 0x78646876 || suffix == 0x796F7476) + { + return 1; + } + } + } + + return 0; +} + +int grub_file_vtoy_vlnk(const char *src, const char *dst) +{ + if (src) + { + g_vtoy_vlnk.srclen = (int)grub_strlen(src); + grub_strncpy(g_vtoy_vlnk.src, src, sizeof(g_vtoy_vlnk.src) - 1); + grub_strncpy(g_vtoy_vlnk.dst, dst, sizeof(g_vtoy_vlnk.dst) - 1); + } + else + { + g_vtoy_vlnk.srclen = 0; + g_vtoy_vlnk.src[0] = 0; + g_vtoy_vlnk.dst[0] = 0; + } + return 0; +} + +int grub_file_add_vlnk(const char *src, const char *dst) +{ + grub_vlnk *node = NULL; + + if (src && dst) + { + node = grub_zalloc(sizeof(grub_vlnk)); + if (node) + { + node->srclen = (int)grub_strlen(src); + grub_strncpy(node->src, src, sizeof(node->src) - 1); + grub_strncpy(node->dst, dst, sizeof(node->dst) - 1); + + node->next = g_vlnk_list; + g_vlnk_list = node; + return 0; + } + } + + return 1; +} + +const char *grub_file_get_vlnk(const char *name, int *vlnk) +{ + int len; + grub_vlnk *node = g_vlnk_list; + + len = grub_strlen(name); + + if (!grub_file_is_vlnk_suffix(name, len)) + { + return name; + } + + if (len == g_vtoy_vlnk.srclen && grub_strcmp(name, g_vtoy_vlnk.src) == 0) + { + if (vlnk) + *vlnk = 1; + return g_vtoy_vlnk.dst; + } + + while (node) + { + if (node->srclen == len && grub_strcmp(name, node->src) == 0) + { + if (vlnk) + *vlnk = 1; + return node->dst; + } + node = node->next; + } + + return name; +} + +grub_file_t +grub_file_open (const char *name, enum grub_file_type type) +{ + int vlnk = 0; + grub_device_t device = 0; + grub_file_t file = 0, last_file = 0; + char *device_name; + const char *file_name; + grub_file_filter_id_t filter; + + /* : mem:xxx:size:xxx format in chainloader grub_strlen(GRUB_MEMFILE_MEM) */ + if (grub_strncmp(name, GRUB_MEMFILE_MEM, 4) == 0) { + return grub_memfile_open(name); + } + + if ((g_vlnk_list || g_vtoy_vlnk.srclen) && (type & GRUB_FILE_TYPE_NO_VLNK) == 0) + name = grub_file_get_vlnk(name, &vlnk); + + device_name = grub_file_get_device_name (name); + if (grub_errno) + goto fail; + + /* Get the file part of NAME. */ + file_name = (name[0] == '(') ? grub_strchr (name, ')') : NULL; + if (file_name) + file_name++; + else + file_name = name; + + device = grub_device_open (device_name); + grub_free (device_name); + if (! device) + goto fail; + + file = (grub_file_t) grub_zalloc (sizeof (*file)); + if (! file) + goto fail; + + file->device = device; + file->vlnk = vlnk; + + /* In case of relative pathnames and non-Unix systems (like Windows) + * name of host files may not start with `/'. Blocklists for host files + * are meaningless as well (for a start, host disk does not allow any direct + * access - it is just a marker). So skip host disk in this case. + */ + if (device->disk && file_name[0] != '/' +#if defined(GRUB_UTIL) || defined(GRUB_MACHINE_EMU) + && grub_strcmp (device->disk->name, "host") +#endif + ) + /* This is a block list. */ + file->fs = &grub_fs_blocklist; + else + { + file->fs = grub_fs_probe (device); + if (! file->fs) + goto fail; + } + + if ((file->fs->fs_open) (file, file_name) != GRUB_ERR_NONE) + goto fail; + + file->name = grub_strdup (name); + grub_errno = GRUB_ERR_NONE; + + for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters); + filter++) + if (grub_file_filters[filter]) + { + last_file = file; + file = grub_file_filters[filter] (file, type); + if (file && file != last_file) + { + file->name = grub_strdup (name); + grub_errno = GRUB_ERR_NONE; + } + } + if (!file) + grub_file_close (last_file); + + return file; + + fail: + if (device) + grub_device_close (device); + + /* if (net) grub_net_close (net); */ + + grub_free (file); + + return 0; +} + +grub_disk_read_hook_t grub_file_progress_hook; + +grub_ssize_t +grub_file_read (grub_file_t file, void *buf, grub_size_t len) +{ + grub_ssize_t res; + grub_disk_read_hook_t read_hook; + void *read_hook_data; + + if (file->offset > file->size) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("attempt to read past the end of file")); + return -1; + } + + if (len == 0) + return 0; + + if (len > file->size - file->offset) + len = file->size - file->offset; + + /* Prevent an overflow. */ + if ((grub_ssize_t) len < 0) + len >>= 1; + + if (len == 0) + return 0; + + if (file->name) { + if (grub_strncmp(file->name, GRUB_MEMFILE_MEM, grub_strlen(GRUB_MEMFILE_MEM)) == 0) { + grub_memcpy(buf, (grub_uint8_t *)(file->data) + file->offset, len); + file->offset += len; + return len; + } + } + + read_hook = file->read_hook; + read_hook_data = file->read_hook_data; + if (!file->read_hook) + { + file->read_hook = grub_file_progress_hook; + file->read_hook_data = file; + file->progress_offset = file->offset; + } + res = (file->fs->fs_read) (file, buf, len); + file->read_hook = read_hook; + file->read_hook_data = read_hook_data; + if (res > 0) + file->offset += res; + + return res; +} + +grub_err_t +grub_file_close (grub_file_t file) +{ + if (file->fs && file->fs->fs_close) + (file->fs->fs_close) (file); + + if (file->device) + grub_device_close (file->device); + grub_free (file->name); + grub_free (file); + return grub_errno; +} + +grub_off_t +grub_file_seek (grub_file_t file, grub_off_t offset) +{ + grub_off_t old; + + if (offset > file->size) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("attempt to seek outside of the file")); + return -1; + } + + old = file->offset; + file->offset = offset; + + return old; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/fs.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/fs.c new file mode 100644 index 0000000..3821177 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/fs.c @@ -0,0 +1,342 @@ +/* fs.c - filesystem manager */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2007 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +grub_fs_t grub_fs_list = 0; + +grub_fs_autoload_hook_t grub_fs_autoload_hook = 0; + +/* Helper for grub_fs_probe. */ +static int +probe_dummy_iter (const char *filename __attribute__ ((unused)), + const struct grub_dirhook_info *info __attribute__ ((unused)), + void *data __attribute__ ((unused))) +{ + return 1; +} + +grub_fs_t grub_fs_list_probe(grub_device_t device, const char **list) +{ + int i; + grub_fs_t p; + + if (!device->disk) + return 0; + + for (p = grub_fs_list; p; p = p->next) + { + for (i = 0; list[i]; i++) + { + if (grub_strcmp(p->name, list[i]) == 0) + break; + } + + if (list[i] == NULL) + continue; + + grub_dprintf("fs", "Detecting %s...\n", p->name); + + (p->fs_dir) (device, "/", probe_dummy_iter, NULL); + if (grub_errno == GRUB_ERR_NONE) + return p; + + grub_error_push (); + grub_dprintf ("fs", "%s detection failed.\n", p->name); + grub_error_pop (); + + if (grub_errno != GRUB_ERR_BAD_FS && grub_errno != GRUB_ERR_OUT_OF_RANGE) { + return 0; + } + grub_errno = GRUB_ERR_NONE; + } + + return 0; +} + +grub_fs_t +grub_fs_probe (grub_device_t device) +{ + grub_fs_t p; + const char *first_probe; + grub_size_t len; + + if (device->disk) + { + /* Make it sure not to have an infinite recursive calls. */ + static int count = 0; + + first_probe = grub_env_get("ventoy_fs_probe"); + if (!first_probe) + { + first_probe = "iso9660"; + } + len = grub_strlen(first_probe); + + /* use iso9660 first */ + for (p = grub_fs_list; p; p = p->next) + { + if (grub_strncmp(p->name, first_probe, len) == 0) + { + break; + } + } + + if (p) + { + grub_dprintf ("fs", "Detecting %s...\n", p->name); + + /* This is evil: newly-created just mounted BtrFS after copying all + GRUB files has a very peculiar unrecoverable corruption which + will be fixed at sync but we'd rather not do a global sync and + syncing just files doesn't seem to help. Relax the check for + this time. */ +#ifdef GRUB_UTIL + if (grub_strcmp (p->name, "btrfs") == 0) + { + char *label = 0; + p->fs_uuid (device, &label); + if (label) + grub_free (label); + } + else +#endif + (p->fs_dir) (device, "/", probe_dummy_iter, NULL); + if (grub_errno == GRUB_ERR_NONE) + return p; + + grub_error_push (); + grub_dprintf ("fs", "%s detection failed.\n", p->name); + grub_error_pop (); + + if (grub_errno != GRUB_ERR_BAD_FS + && grub_errno != GRUB_ERR_OUT_OF_RANGE) + return 0; + + grub_errno = GRUB_ERR_NONE; + } + + for (p = grub_fs_list; p; p = p->next) + { + grub_dprintf ("fs", "Detecting %s...\n", p->name); + + /* This is evil: newly-created just mounted BtrFS after copying all + GRUB files has a very peculiar unrecoverable corruption which + will be fixed at sync but we'd rather not do a global sync and + syncing just files doesn't seem to help. Relax the check for + this time. */ +#ifdef GRUB_UTIL + if (grub_strcmp (p->name, "btrfs") == 0) + { + char *label = 0; + p->fs_uuid (device, &label); + if (label) + grub_free (label); + } + else +#endif + (p->fs_dir) (device, "/", probe_dummy_iter, NULL); + if (grub_errno == GRUB_ERR_NONE) + return p; + + grub_error_push (); + grub_dprintf ("fs", "%s detection failed.\n", p->name); + grub_error_pop (); + + if (grub_errno != GRUB_ERR_BAD_FS + && grub_errno != GRUB_ERR_OUT_OF_RANGE) + return 0; + + grub_errno = GRUB_ERR_NONE; + } + + /* Let's load modules automatically. */ + if (grub_fs_autoload_hook && count == 0) + { + count++; + + while (grub_fs_autoload_hook ()) + { + p = grub_fs_list; + + (p->fs_dir) (device, "/", probe_dummy_iter, NULL); + if (grub_errno == GRUB_ERR_NONE) + { + count--; + return p; + } + + if (grub_errno != GRUB_ERR_BAD_FS + && grub_errno != GRUB_ERR_OUT_OF_RANGE) + { + count--; + return 0; + } + + grub_errno = GRUB_ERR_NONE; + } + + count--; + } + } + else if (device->net && device->net->fs) + return device->net->fs; + + grub_error (GRUB_ERR_UNKNOWN_FS, N_("unknown filesystem")); + return 0; +} + + + +/* Block list support routines. */ + +struct grub_fs_block +{ + grub_disk_addr_t offset; + unsigned long length; +}; + +static grub_err_t +grub_fs_blocklist_open (grub_file_t file, const char *name) +{ + char *p = (char *) name; + unsigned num = 0; + unsigned i; + grub_disk_t disk = file->device->disk; + struct grub_fs_block *blocks; + + /* First, count the number of blocks. */ + do + { + num++; + p = grub_strchr (p, ','); + if (p) + p++; + } + while (p); + + /* Allocate a block list. */ + blocks = grub_zalloc (sizeof (struct grub_fs_block) * (num + 1)); + if (! blocks) + return 0; + + file->size = 0; + p = (char *) name; + for (i = 0; i < num; i++) + { + if (*p != '+') + { + blocks[i].offset = grub_strtoull (p, &p, 0); + if (grub_errno != GRUB_ERR_NONE || *p != '+') + { + grub_error (GRUB_ERR_BAD_FILENAME, + N_("invalid file name `%s'"), name); + goto fail; + } + } + + p++; + blocks[i].length = grub_strtoul (p, &p, 0); + if (grub_errno != GRUB_ERR_NONE + || blocks[i].length == 0 + || (*p && *p != ',' && ! grub_isspace (*p))) + { + grub_error (GRUB_ERR_BAD_FILENAME, + N_("invalid file name `%s'"), name); + goto fail; + } + + if (disk->total_sectors < blocks[i].offset + blocks[i].length) + { + grub_error (GRUB_ERR_BAD_FILENAME, "beyond the total sectors"); + goto fail; + } + + file->size += (blocks[i].length << GRUB_DISK_SECTOR_BITS); + p++; + } + + file->data = blocks; + + return GRUB_ERR_NONE; + + fail: + grub_free (blocks); + return grub_errno; +} + +static grub_ssize_t +grub_fs_blocklist_read (grub_file_t file, char *buf, grub_size_t len) +{ + struct grub_fs_block *p; + grub_disk_addr_t sector; + grub_off_t offset; + grub_ssize_t ret = 0; + + if (len > file->size - file->offset) + len = file->size - file->offset; + + sector = (file->offset >> GRUB_DISK_SECTOR_BITS); + offset = (file->offset & (GRUB_DISK_SECTOR_SIZE - 1)); + for (p = file->data; p->length && len > 0; p++) + { + if (sector < p->length) + { + grub_size_t size; + + size = len; + if (((size + offset + GRUB_DISK_SECTOR_SIZE - 1) + >> GRUB_DISK_SECTOR_BITS) > p->length - sector) + size = ((p->length - sector) << GRUB_DISK_SECTOR_BITS) - offset; + + if (grub_disk_read (file->device->disk, p->offset + sector, offset, + size, buf) != GRUB_ERR_NONE) + return -1; + + ret += size; + len -= size; + sector -= ((size + offset) >> GRUB_DISK_SECTOR_BITS); + offset = ((size + offset) & (GRUB_DISK_SECTOR_SIZE - 1)); + } + else + sector -= p->length; + } + + return ret; +} + +struct grub_fs grub_fs_blocklist = + { + .name = "blocklist", + .fs_dir = 0, + .fs_open = grub_fs_blocklist_open, + .fs_read = grub_fs_blocklist_read, + .fs_close = 0, + .next = 0 + }; diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/main.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/main.c new file mode 100644 index 0000000..602c92b --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/main.c @@ -0,0 +1,403 @@ +/* main.c - the kernel main routine */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2006,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef GRUB_MACHINE_PCBIOS +#include +#endif + +grub_addr_t +grub_modules_get_end (void) +{ + struct grub_module_info *modinfo; + + modinfo = (struct grub_module_info *) grub_modbase; + + /* Check if there are any modules. */ + if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC) + return grub_modbase; + + return grub_modbase + modinfo->size; +} + +/* Load all modules in core. */ +static void +grub_load_modules (void) +{ + struct grub_module_header *header; + FOR_MODULES (header) + { + /* Not an ELF module, skip. */ + if (header->type != OBJ_TYPE_ELF) + continue; + + if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header), + (header->size - sizeof (struct grub_module_header)))) + grub_fatal ("%s", grub_errmsg); + + if (grub_errno) + grub_print_error (); + } +} + +static char *load_config; + +static void +grub_load_config (void) +{ + struct grub_module_header *header; + FOR_MODULES (header) + { + /* Not an embedded config, skip. */ + if (header->type != OBJ_TYPE_CONFIG) + continue; + + load_config = grub_malloc (header->size - sizeof (struct grub_module_header) + 1); + if (!load_config) + { + grub_print_error (); + break; + } + grub_memcpy (load_config, (char *) header + + sizeof (struct grub_module_header), + header->size - sizeof (struct grub_module_header)); + load_config[header->size - sizeof (struct grub_module_header)] = 0; + break; + } +} + +/* Write hook for the environment variables of root. Remove surrounding + parentheses, if any. */ +static char * +grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)), + const char *val) +{ + /* XXX Is it better to check the existence of the device? */ + grub_size_t len = grub_strlen (val); + + if (val[0] == '(' && val[len - 1] == ')') + return grub_strndup (val + 1, len - 2); + + return grub_strdup (val); +} + +static int g_ventoy_hook_root = 0; +void ventoy_env_hook_root(int hook) +{ + g_ventoy_hook_root = hook; +} + +static char * +ventoy_env_write_root (struct grub_env_var *var __attribute__ ((unused)), + const char *val) +{ + const char *pos = val; + char buf[256]; + + if (g_ventoy_hook_root == 0) + { + return grub_env_write_root(var, val); + } + + if (pos[0] == '(') + { + pos++; + } + + if (grub_strncmp(pos, "vtimghd", 7) == 0) + { + return grub_env_write_root(var, val); + } + + pos = grub_strchr(val, ','); + if (!pos) + { + return grub_env_write_root(var, val); + } + + if (val[0] == '(') + { + grub_snprintf(buf, sizeof(buf), "(vtimghd%s", pos); + } + else + { + grub_snprintf(buf, sizeof(buf), "vtimghd%s", pos); + } + + return grub_env_write_root(var, buf); +} + +static void +grub_set_prefix_and_root (void) +{ + char *device = NULL; + char *path = NULL; + char *fwdevice = NULL; + char *fwpath = NULL; + char *prefix = NULL; + struct grub_module_header *header; + + FOR_MODULES (header) + if (header->type == OBJ_TYPE_PREFIX) + prefix = (char *) header + sizeof (struct grub_module_header); + + grub_register_variable_hook ("root", 0, ventoy_env_write_root); + + grub_machine_get_bootlocation (&fwdevice, &fwpath); + + if (fwdevice) + { + char *cmdpath; + + cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : ""); + if (cmdpath) + { + grub_env_set ("cmdpath", cmdpath); + grub_env_export ("cmdpath"); + grub_free (cmdpath); + } + } + + if (prefix) + { + char *pptr = NULL; + if (prefix[0] == '(') + { + pptr = grub_strrchr (prefix, ')'); + if (pptr) + { + device = grub_strndup (prefix + 1, pptr - prefix - 1); + pptr++; + } + } + if (!pptr) + pptr = prefix; + if (pptr[0]) + path = grub_strdup (pptr); + } + + if (!device && fwdevice) + device = fwdevice; + else if (fwdevice && (device[0] == ',' || !device[0])) + { + /* We have a partition, but still need to fill in the drive. */ + char *comma, *new_device; + + for (comma = fwdevice; *comma; ) + { + if (comma[0] == '\\' && comma[1] == ',') + { + comma += 2; + continue; + } + if (*comma == ',') + break; + comma++; + } + if (*comma) + { + char *drive = grub_strndup (fwdevice, comma - fwdevice); + new_device = grub_xasprintf ("%s%s", drive, device); + grub_free (drive); + } + else + new_device = grub_xasprintf ("%s%s", fwdevice, device); + + grub_free (fwdevice); + grub_free (device); + device = new_device; + } + else + grub_free (fwdevice); + if (fwpath && !path) + { + grub_size_t len = grub_strlen (fwpath); + while (len > 1 && fwpath[len - 1] == '/') + fwpath[--len] = 0; + if (len >= sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1 + && grub_memcmp (fwpath + len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1), GRUB_TARGET_CPU "-" GRUB_PLATFORM, + sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1) == 0) + fwpath[len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1)] = 0; + path = fwpath; + } + else + grub_free (fwpath); + if (device) + { + char *prefix_set; + + prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); + if (prefix_set) + { + grub_env_set ("prefix", prefix_set); + grub_free (prefix_set); + } + grub_env_set ("root", device); + } + + grub_free (device); + grub_free (path); + grub_print_error (); +} + +/* Load the normal mode module and execute the normal mode if possible. */ +static void +grub_load_normal_mode (void) +{ + /* Load the module. */ + grub_dl_load ("normal"); + + /* Print errors if any. */ + grub_print_error (); + grub_errno = 0; + + grub_command_execute ("normal", 0, 0); +} + +static void +reclaim_module_space (void) +{ + grub_addr_t modstart, modend; + + if (!grub_modbase) + return; + +#ifdef GRUB_MACHINE_PCBIOS + modstart = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR; +#else + modstart = grub_modbase; +#endif + modend = grub_modules_get_end (); + grub_modbase = 0; + +#if GRUB_KERNEL_PRELOAD_SPACE_REUSABLE + grub_mm_init_region ((void *) modstart, modend - modstart); +#else + (void) modstart; + (void) modend; +#endif +} + +#ifndef GRUB_MACHINE_EFI +static int ventoy_legacy_limit_workaround(void) +{ + grub_file_t file; + char *pos, *root; + char buf[128]; + + root = grub_strdup(grub_env_get("root")); + if (!root) + { + return 1; + } + + pos = grub_strchr(root, ','); + if (pos) *pos = 0; + + grub_snprintf(buf, sizeof(buf), "(%s,1)/ventoy/ventoy.disk.img.xz", root); + file = grub_file_open(buf, GRUB_FILE_TYPE_NONE); + if (file) + { + pos = grub_malloc(file->size); + if (pos) + { + grub_file_read(file, pos, file->size); + grub_snprintf(buf, sizeof(buf), "loopback ventoydisk mem:0x%lx:size:%lu", + (unsigned long)pos, (unsigned long)file->size); + + grub_parser_execute(buf); + grub_env_set("prefix", "(ventoydisk)/grub"); + } + + grub_file_close(file); + } + + grub_free(root); + return 0; +} +#endif + +/* The main routine. */ +void __attribute__ ((noreturn)) +grub_main (void) +{ + /* First of all, initialize the machine. */ + grub_machine_init (); + + grub_boot_time ("After machine init."); + + /* Hello. */ + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + //grub_printf ("Welcome to GRUB!\n\n"); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + + grub_load_config (); + + grub_boot_time ("Before loading embedded modules."); + + /* Load pre-loaded modules and free the space. */ + grub_register_exported_symbols (); +#ifdef GRUB_LINKER_HAVE_INIT + grub_arch_dl_init_linker (); +#endif + grub_load_modules (); + + grub_boot_time ("After loading embedded modules."); + + /* It is better to set the root device as soon as possible, + for convenience. */ + grub_set_prefix_and_root (); + grub_env_export ("root"); + grub_env_export ("prefix"); + +#ifndef GRUB_MACHINE_EFI + if (0 == ventoy_check_file_exist("%s/grub.cfg", grub_env_get("prefix"))) { + ventoy_legacy_limit_workaround(); + } +#endif + + /* Reclaim space used for modules. */ + reclaim_module_space (); + + grub_boot_time ("After reclaiming module space."); + + grub_register_core_commands (); + + grub_boot_time ("Before execution of embedded config."); + + if (load_config) + grub_parser_execute (load_config); + + grub_boot_time ("After execution of embedded config. Attempt to go to normal mode"); + + grub_load_normal_mode (); + grub_rescue_run (); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/cache.S b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/cache.S new file mode 100644 index 0000000..c357ecd --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/cache.S @@ -0,0 +1,23 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + +FUNCTION (grub_arch_sync_caches) + jr.hb $ra + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/dl.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/dl.c new file mode 100644 index 0000000..72310df --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/dl.c @@ -0,0 +1,150 @@ +/* dl-mips64.c - arch-dependent part of loadable module support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2007,2009,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Check if EHDR is a valid ELF header. */ +grub_err_t +grub_arch_dl_check_header (void *ehdr) +{ + Elf_Ehdr *e = ehdr; + + /* Check the magic numbers. */ +#ifdef GRUB_CPU_WORDS_BIGENDIAN + if (e->e_ident[EI_CLASS] != ELFCLASS64 + || e->e_ident[EI_DATA] != ELFDATA2MSB + || e->e_machine != EM_MIPS) +#else + if (e->e_ident[EI_CLASS] != ELFCLASS64 + || e->e_ident[EI_DATA] != ELFDATA2LSB + || e->e_machine != EM_MIPS) +#endif + return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); + + return GRUB_ERR_NONE; +} + +#pragma GCC diagnostic ignored "-Wcast-align" + +grub_err_t +grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)), + grub_size_t *tramp, grub_size_t *got) +{ + *tramp = 0; + *got = 0; + return GRUB_ERR_NONE; +} + +/* Relocate symbols. */ +grub_err_t +grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Shdr *s, grub_dl_segment_t seg) +{ + Elf_Ehdr *e = ehdr; + Elf_Rel *rel, *max; + + for (rel = (Elf_Rel *) ((char *) e + s->sh_offset), + max = (Elf_Rel *) ((char *) rel + s->sh_size); + rel < max; + rel = (Elf_Rel *) ((char *) rel + s->sh_entsize)) + { + grub_uint8_t *addr; + Elf_Sym *sym; + Elf_Addr r_info; + grub_uint64_t sym_value; + + if (seg->size < rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, + "reloc offset is out of the segment"); + + r_info = ((grub_uint64_t) rel->r_info << 32) | + (grub_uint32_t) grub_be_to_cpu64 (rel->r_info); + + addr = (grub_uint8_t *) ((char *) seg->addr + rel->r_offset); + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (r_info)); + sym_value = sym->st_value; + if (s->sh_type == SHT_RELA) + { + sym_value += ((Elf_Rela *) rel)->r_addend; + } + switch (ELF_R_TYPE (r_info)) + { + case R_MIPS_64: + *(grub_uint64_t *) addr += sym_value; + break; + case R_MIPS_32: + *(grub_uint32_t *) addr += sym_value; + break; + case R_MIPS_26: + { + grub_uint32_t value; + grub_uint32_t raw; + raw = (*(grub_uint32_t *) addr) & 0x3ffffff; + value = raw << 2; + value += sym_value; + raw = (value >> 2) & 0x3ffffff; + + *(grub_uint32_t *) addr = + raw | ((*(grub_uint32_t *) addr) & 0xfc000000); + } + break; + case R_MIPS_LO16: +#ifdef GRUB_CPU_WORDS_BIGENDIAN + addr += 2; +#endif + *(grub_uint16_t *) addr = (grub_int16_t) sym_value; + break; + case R_MIPS_HI16: +#ifdef GRUB_CPU_WORDS_BIGENDIAN + addr += 2; +#endif + *(grub_uint16_t *) addr = (grub_int16_t) ((sym_value + 0x8000UL) >> 16); + break; + case R_MIPS_HIGHER: +#ifdef GRUB_CPU_WORDS_BIGENDIAN + addr += 2; +#endif + *(grub_uint16_t *) addr = (grub_int16_t) ((sym_value + 0x80008000UL) >> 32); + break; + case R_MIPS_HIGHEST: +#ifdef GRUB_CPU_WORDS_BIGENDIAN + addr += 2; +#endif + *(grub_uint16_t *) addr = (grub_uint16_t) ((sym_value + 0x800080008000UL) >> 48); + break; + default: + { + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("relocation 0x%x is not implemented yet"), + ELF_R_TYPE (r_info)); + } + break; + } + } + + return GRUB_ERR_NONE; +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/efi/init.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/efi/init.c new file mode 100644 index 0000000..307e4d4 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/efi/init.c @@ -0,0 +1,85 @@ +/* init.c - initialize an arm-based EFI system */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_uint64_t tmr; +static grub_efi_event_t tmr_evt; + +static grub_uint64_t +grub_efi_get_time_ms (void) +{ + return tmr; +} + +static void +grub_loongson_increment_timer (grub_efi_event_t event __attribute__ ((unused)), + void *context __attribute__ ((unused))) +{ + tmr += 10; +} + + + +void +grub_machine_init (void) +{ + grub_efi_boot_services_t *b; + + grub_efi_init (); + + b = grub_efi_system_table->boot_services; + efi_call_5 (b->create_event, GRUB_EFI_EVT_TIMER | GRUB_EFI_EVT_NOTIFY_SIGNAL, + GRUB_EFI_TPL_CALLBACK, grub_loongson_increment_timer, NULL, &tmr_evt); + efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_PERIODIC, 100000); + + grub_install_get_time_ms (grub_efi_get_time_ms); + + if (grub_efi_is_loongson ()) + grub_efi_loongson_init (); + else + /* FIXME: Get cpuclock from EFI. */ + grub_timer_init (1000000000U); +} + +void +grub_machine_fini (int flags) +{ + grub_efi_boot_services_t *b; + + if (!(flags & GRUB_LOADER_FLAG_NORETURN)) + return; + + b = grub_efi_system_table->boot_services; + + efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_CANCEL, 0); + efi_call_1 (b->close_event, tmr_evt); + + if (grub_efi_is_loongson ()) + grub_efi_loongson_fini (); + grub_efi_fini (); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/efi/loongson.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/efi/loongson.c new file mode 100644 index 0000000..c817ad8 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/efi/loongson.c @@ -0,0 +1,33 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include + +void +grub_efi_loongson_init (void) +{ +} + +void +grub_efi_loongson_fini (void) +{ +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/efi/startup.S b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/efi/startup.S new file mode 100644 index 0000000..0491e15 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/efi/startup.S @@ -0,0 +1,47 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + + .file "startup.S" + .text + + .set push + .align 4 + +FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0. + */ + daddiu $sp, -16 + sd $ra, ($sp) + + dla $a2, grub_efi_image_handle + sd $a0, ($a2) + dla $a2, grub_efi_system_table + sd $a1, ($a2) + + jal grub_main + +1: + ld $ra, ($sp) + daddiu $sp, 16 + jr $ra + + .set pop + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/init.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/init.c new file mode 100644 index 0000000..74580d3 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/mips64/init.c @@ -0,0 +1,47 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include + +grub_uint32_t grub_arch_cpuclock; + +/* FIXME: use interrupt to count high. */ +grub_uint64_t +grub_get_rtc (void) +{ + static grub_uint32_t high = 0; + static grub_uint32_t last = 0; + grub_uint32_t low; + + asm volatile ("mfc0 %0, " GRUB_CPU_MIPS_COP0_TIMER_COUNT : "=r" (low)); + if (low < last) + high++; + last = low; + + return (((grub_uint64_t) high) << 32) | low; +} + +void +grub_timer_init (grub_uint32_t cpuclock) +{ + grub_arch_cpuclock = cpuclock; + grub_install_get_time_ms (grub_rtc_get_time_ms); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/term.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/term.c new file mode 100644 index 0000000..3201e8b --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/term.c @@ -0,0 +1,133 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_term_output *grub_term_outputs_disabled; +struct grub_term_input *grub_term_inputs_disabled; +struct grub_term_output *grub_term_outputs; +struct grub_term_input *grub_term_inputs; + +/* Current color state. */ +grub_uint8_t grub_term_normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR; +grub_uint8_t grub_term_highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR; + +void (*grub_term_poll_usb) (int wait_for_completion) = NULL; +void (*grub_net_poll_cards_idle) (void) = NULL; + +/* Put a Unicode character. */ +static void +grub_putcode_dumb (grub_uint32_t code, + struct grub_term_output *term) +{ + struct grub_unicode_glyph c = + { + .base = code, + .variant = 0, + .attributes = 0, + .ncomb = 0, + .estimated_width = 1 + }; + + if (code == '\t' && term->getxy) + { + int n; + + n = GRUB_TERM_TAB_WIDTH - ((term->getxy (term).x) + % GRUB_TERM_TAB_WIDTH); + while (n--) + grub_putcode_dumb (' ', term); + + return; + } + + (term->putchar) (term, &c); + if (code == '\n') + grub_putcode_dumb ('\r', term); +} + +static void +grub_xputs_dumb (const char *str) +{ + for (; *str; str++) + { + grub_term_output_t term; + grub_uint32_t code = *str; + if (code > 0x7f) + code = '?'; + + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_putcode_dumb (code, term); + } +} + +void (*grub_xputs) (const char *str) = grub_xputs_dumb; + +int (*grub_key_remap)(int key) = NULL; +int +grub_getkey_noblock (void) +{ + grub_term_input_t term; + + if (grub_term_poll_usb) + grub_term_poll_usb (0); + + if (grub_net_poll_cards_idle) + grub_net_poll_cards_idle (); + + FOR_ACTIVE_TERM_INPUTS(term) + { + int key = term->getkey (term); + if (grub_key_remap) + key = grub_key_remap(key); + if (key != GRUB_TERM_NO_KEY) + return key; + } + + return GRUB_TERM_NO_KEY; +} + +int +grub_getkey (void) +{ + int ret; + + grub_refresh (); + + while (1) + { + ret = grub_getkey_noblock (); + if (ret != GRUB_TERM_NO_KEY) + return ret; + grub_cpu_idle (); + } +} + +void +grub_refresh (void) +{ + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_term_refresh (term); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/cmdline.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/cmdline.c new file mode 100644 index 0000000..2c727d7 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/cmdline.c @@ -0,0 +1,118 @@ +/* cmdline.c - linux command line handling */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +static unsigned int check_arg (char *c, int *has_space) +{ + int space = 0; + unsigned int size = 0; + + while (*c) + { + if (*c == '\\' || *c == '\'' || *c == '"') + size++; + else if (*c == ' ') + space = 1; + + size++; + c++; + } + + if (space) + size += 2; + + if (has_space) + *has_space = space; + + return size; +} + +unsigned int grub_loader_cmdline_size (int argc, char *argv[]) +{ + int i; + unsigned int size = 0; + + for (i = 0; i < argc; i++) + { + size += check_arg (argv[i], 0); + size++; /* Separator space or NULL. */ + } + + if (size == 0) + size = 1; + + return size; +} + +grub_err_t +grub_create_loader_cmdline (int argc, char *argv[], char *buf, + grub_size_t size, enum grub_verify_string_type type) +{ + int i, space; + unsigned int arg_size; + char *c, *orig_buf = buf; + + for (i = 0; i < argc; i++) + { + c = argv[i]; + arg_size = check_arg(argv[i], &space); + arg_size++; /* Separator space or NULL. */ + + if (size < arg_size) + break; + + size -= arg_size; + + if (space) + *buf++ = '"'; + + while (*c) + { + if (*c == '\\' && *(c+1) == 'x' && + grub_isxdigit(*(c+2)) && grub_isxdigit(*(c+3))) + { + *buf++ = *c++; + *buf++ = *c++; + *buf++ = *c++; + *buf++ = *c++; + continue; + } + else if (*c == '\\' || *c == '\'' || *c == '"') + *buf++ = '\\'; + + *buf++ = *c; + c++; + } + + if (space) + *buf++ = '"'; + + *buf++ = ' '; + } + + /* Replace last space with null. */ + if (i) + buf--; + + *buf = 0; + + return grub_verify_string (orig_buf, type); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/efi/halt.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/efi/halt.c new file mode 100644 index 0000000..bcd1fc6 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/efi/halt.c @@ -0,0 +1,40 @@ +/* efi.c - generic EFI support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +void +grub_halt (void) +{ + grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); +#if !defined(__ia64__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__mips__) &&\ + !defined(__riscv) + grub_acpi_halt (); +#endif + efi_call_4 (grub_efi_system_table->runtime_services->reset_system, + GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL); + + while (1); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/efi/loongson.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/efi/loongson.c new file mode 100644 index 0000000..2bbf5cd --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/efi/loongson.c @@ -0,0 +1,495 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic ignored "-Wunused-function" + +#define loongson_params (&loongson_boot_params->boot_params.efi.smbios.lp) +#define loongson_boot_params_size ALIGN_UP (sizeof (*loongson_boot_params), 8) +#define loongson_reset_code_size (&grub_efi_loongson_reset_end - &grub_efi_loongson_reset_start) + +extern grub_uint8_t grub_efi_loongson_reset_start; +extern grub_uint8_t grub_efi_loongson_reset_end; + +static struct +{ + grub_efi_loongson_boot_params boot_params; + grub_efi_loongson_memory_map memory_map; + grub_efi_loongson_cpu_info cpu_info; + grub_efi_loongson_system_info system_info; + grub_efi_loongson_irq_src_routing_table irq_src_routing_table; + grub_efi_loongson_interface_info interface_info; + grub_efi_loongson_special_attribute special_attribute; + grub_efi_loongson_board_devices board_devices; +} GRUB_PACKED +* loongson_boot_params; + +static void +grub_efi_loongson_init_reset_system (void) +{ + grub_efi_loongson_boot_params *boot_params; + grub_uint8_t *reset_code_addr = (grub_uint8_t *) loongson_boot_params + + loongson_boot_params_size; + + boot_params = &loongson_boot_params->boot_params; + grub_efi_loongson_reset_system_addr = + (grub_uint64_t) grub_efi_system_table->runtime_services->reset_system; + grub_memcpy (reset_code_addr, &grub_efi_loongson_reset_start, loongson_reset_code_size); + grub_arch_sync_caches (reset_code_addr, loongson_reset_code_size); + + boot_params->reset_system.reset_cold = (grub_uint64_t) reset_code_addr + + ((grub_uint64_t) &grub_efi_loongson_reset_cold - + (grub_uint64_t) &grub_efi_loongson_reset_start); + boot_params->reset_system.reset_warm = (grub_uint64_t) reset_code_addr + + ((grub_uint64_t) &grub_efi_loongson_reset_warm - + (grub_uint64_t) &grub_efi_loongson_reset_start); + boot_params->reset_system.shutdown = (grub_uint64_t) reset_code_addr + + ((grub_uint64_t) &grub_efi_loongson_reset_shutdown - + (grub_uint64_t) &grub_efi_loongson_reset_start); + boot_params->reset_system.do_suspend = (grub_uint64_t) reset_code_addr + + ((grub_uint64_t) &grub_efi_loongson_reset_suspend - + (grub_uint64_t) &grub_efi_loongson_reset_start); +} + +static void +grub_efi_loongson_init_smbios (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_smbios_table *dst = &loongson_boot_params->boot_params.efi.smbios; + + dst->vers = smbios_table->vers; + dst->vga_bios = smbios_table->vga_bios; +} + +static void +grub_efi_loongson_init_cpu_info (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_cpu_info *src = (void *) smbios_table->lp.cpu_offset; + grub_efi_loongson_cpu_info *dst = &loongson_boot_params->cpu_info; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_cpu_info)); + loongson_params->cpu_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_system_info (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_system_info *src = (void *) smbios_table->lp.system_offset; + grub_efi_loongson_system_info *dst = &loongson_boot_params->system_info; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_system_info)); + loongson_params->system_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_irq_src_routing_table (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_irq_src_routing_table *src = (void *) smbios_table->lp.irq_offset; + grub_efi_loongson_irq_src_routing_table *dst = &loongson_boot_params->irq_src_routing_table; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_irq_src_routing_table)); + loongson_params->irq_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_interface_info (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_interface_info *src = (void *) smbios_table->lp.interface_offset; + grub_efi_loongson_interface_info *dst = &loongson_boot_params->interface_info; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_interface_info)); + loongson_params->interface_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_special_attribute (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_special_attribute *src = (void *) smbios_table->lp.special_offset; + grub_efi_loongson_special_attribute *dst = &loongson_boot_params->special_attribute; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_special_attribute)); + loongson_params->special_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +static void +grub_efi_loongson_init_board_devices (grub_efi_loongson_smbios_table *smbios_table) +{ + grub_efi_loongson_board_devices *src = (void *) smbios_table->lp.boarddev_table_offset; + grub_efi_loongson_board_devices *dst = &loongson_boot_params->board_devices; + + if (!src) + return; + + grub_memcpy (dst, src, sizeof (grub_efi_loongson_board_devices)); + loongson_params->boarddev_table_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; +} + +#define ADD_MEMORY_DESCRIPTOR(desc, size) \ + ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) + +static void +grub_efi_loongson_init_memory_map (grub_efi_loongson_smbios_table *smbios_table, + grub_efi_memory_descriptor_t *mmap_buf, + grub_efi_uintn_t mmap_size, + grub_efi_uintn_t desc_size) +{ + grub_efi_loongson_memory_map *src = (void *) smbios_table->lp.memory_offset; + grub_efi_loongson_memory_map *dst = &loongson_boot_params->memory_map; + grub_efi_memory_descriptor_t *mmap_end; + grub_efi_memory_descriptor_t *desc; + grub_efi_memory_descriptor_t *desc_next; + grub_efi_uint32_t mem_types_reserved[] = + { + 1, // GRUB_EFI_RESERVED_MEMORY_TYPE + 0, // GRUB_EFI_LOADER_CODE + 0, // GRUB_EFI_LOADER_DATA + 0, // GRUB_EFI_BOOT_SERVICES_CODE + 0, // GRUB_EFI_BOOT_SERVICES_DATA + 1, // GRUB_EFI_RUNTIME_SERVICES_CODE + 1, // GRUB_EFI_RUNTIME_SERVICES_DATA + 0, // GRUB_EFI_CONVENTIONAL_MEMORY + 1, // GRUB_EFI_UNUSABLE_MEMORY + 0, // GRUB_EFI_ACPI_RECLAIM_MEMORY + 0, // GRUB_EFI_ACPI_MEMORY_NVS + 1, // GRUB_EFI_MEMORY_MAPPED_IO + 1, // GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE + 1, // GRUB_EFI_PAL_CODE + 1, // GRUB_EFI_PERSISTENT_MEMORY + }; + grub_uint32_t need_sort = 1; + + if (!src) + return; + + dst->vers = src->vers; + dst->nr_map = 0; + dst->mem_freq = src->mem_freq; + loongson_params->memory_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; + + if (!mmap_buf || !mmap_size || !desc_size) + return; + + mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); + + /* drop reserved */ + for (desc = mmap_buf, + desc_next = desc; + desc < mmap_end; + desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) + { + desc->type = mem_types_reserved[desc->type]; + if (desc->type) + continue; + + if (desc != desc_next) + *desc_next = *desc; + desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size); + } + mmap_end = desc_next; + + /* sort: low->high */ + while (need_sort) + { + need_sort = 0; + + for (desc = mmap_buf, + desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); + (desc < mmap_end) && (desc_next < mmap_end); + desc = desc_next, + desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) + { + grub_efi_memory_descriptor_t tmp; + + if (desc->physical_start <= desc_next->physical_start) + continue; + + tmp = *desc; + *desc = *desc_next; + *desc_next = tmp; + need_sort = 1; + } + } + + /* combine continuous memory map */ + for (desc = mmap_buf, + desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); + desc_next < mmap_end; + desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size)) + { + grub_efi_physical_address_t prev_end = desc->physical_start + (desc->num_pages << 12); + + if (prev_end == desc_next->physical_start) + { + desc->num_pages += desc_next->num_pages; + continue; + } + + desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size); + grub_memcpy (desc, desc_next, desc_size); + } + mmap_end = ADD_MEMORY_DESCRIPTOR (desc, desc_size); + + /* write to loongson memory map */ + for (desc = mmap_buf; + desc < mmap_end; + desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) + { + grub_efi_physical_address_t physical_start = grub_vtop ((void *) desc->physical_start); + grub_efi_physical_address_t physical_end = physical_start + (desc->num_pages << 12); + + physical_start = ALIGN_UP (physical_start, 0x100000); + physical_end = ALIGN_DOWN (physical_end, 0x100000); + + if (physical_start >= physical_end || (physical_end - physical_start) < 0x100000) + continue; + + dst->map[dst->nr_map].node_id = (desc->physical_start >> 44) & 0xf; + dst->map[dst->nr_map].mem_type = (physical_end <= 0x10000000) ? + GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW : + GRUB_EFI_LOONGSON_SYSTEM_RAM_HIGH; + dst->map[dst->nr_map].mem_start = physical_start; + dst->map[dst->nr_map].mem_size = (physical_end - physical_start) >> 20; + + grub_dprintf ("loongson", "memory map %03u: 0x%016lx 0x%016lx @ %u\n", + dst->nr_map, physical_start, physical_end - physical_start, + dst->map[dst->nr_map].node_id); + + dst->nr_map ++; + } +} + +#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) +#define SUB_MEMORY_DESCRIPTOR(desc, size) \ + ((grub_efi_memory_descriptor_t *) ((char *) (desc) - (size))) + +void +grub_efi_loongson_alloc_boot_params (void) +{ + grub_efi_memory_descriptor_t *mmap_buf; + grub_efi_memory_descriptor_t *mmap_end; + grub_efi_memory_descriptor_t *desc; + grub_efi_uintn_t mmap_size; + grub_efi_uintn_t desc_size; + grub_efi_physical_address_t address; + grub_efi_allocate_type_t type; + grub_efi_uintn_t pages; + grub_efi_status_t status; + grub_efi_boot_services_t *b; + int mm_status; + + type = GRUB_EFI_ALLOCATE_ADDRESS; + pages = BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size); + + mmap_size = (1 << 12); + mmap_buf = grub_malloc (mmap_size); + if (!mmap_buf) + grub_fatal ("out of memory!"); + + mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); + if (mm_status == 0) + { + grub_free (mmap_buf); + mmap_size += desc_size * 32; + + mmap_buf = grub_malloc (mmap_size); + if (!mmap_buf) + grub_fatal ("out of memory!"); + + mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); + } + + if (mm_status < 0) + grub_fatal ("cannot get memory map!"); + + mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); + + for (desc = SUB_MEMORY_DESCRIPTOR (mmap_end, desc_size); + desc >= mmap_buf; + desc = SUB_MEMORY_DESCRIPTOR (desc, desc_size)) + { + if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) + continue; + if (desc->physical_start >= GRUB_EFI_MAX_USABLE_ADDRESS) + continue; + if (desc->num_pages < pages) + continue; + + address = desc->physical_start; + break; + } + + grub_free (mmap_buf); + + b = grub_efi_system_table->boot_services; + status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_RUNTIME_SERVICES_DATA, pages, &address); + if (status != GRUB_EFI_SUCCESS) + grub_fatal ("cannot allocate Loongson boot parameters!"); + + loongson_boot_params = (void *) ((grub_addr_t) address); +} + +void +grub_efi_loongson_free_boot_params (void) +{ + grub_efi_free_pages ((grub_addr_t) loongson_boot_params, + BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size)); +} + +void * +grub_efi_loongson_get_smbios_table (void) +{ + static grub_efi_loongson_smbios_table *smbios_table; + grub_efi_loongson_boot_params *old_boot_params; + struct bootparamsinterface* boot_params; + void * tmp_boot_params = NULL; + char * p = NULL; + if(smbios_table) + return smbios_table; + + tmp_boot_params = grub_efi_loongson_get_boot_params(); + if(tmp_boot_params == NULL) + { + grub_dprintf("loongson", "tmp_boot_params is NULL\n"); + return tmp_boot_params; + } + + boot_params = (struct bootparamsinterface *)tmp_boot_params; + p = (char *)&(boot_params->signature); + if(grub_strncmp(p, "BPI", 3) == 0) + { + grub_dprintf("loongson", "find new bpi\n"); + return boot_params ? boot_params : 0; + } + else + { + old_boot_params = (grub_efi_loongson_boot_params *)tmp_boot_params; + return old_boot_params ? &old_boot_params->efi.smbios : 0; + } + +} + +int +grub_efi_is_loongson (void) +{ + return grub_efi_loongson_get_smbios_table () ? 1 : 0; +} + +void * +grub_efi_loongson_get_boot_params (void) +{ + static void * boot_params = NULL; + grub_efi_configuration_table_t *tables; + grub_efi_guid_t smbios_guid = GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID; + unsigned int i; + + if (boot_params) + return boot_params; + + /* Look for Loongson SMBIOS in UEFI config tables. */ + tables = grub_efi_system_table->configuration_table; + + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) + if (grub_memcmp (&tables[i].vendor_guid, &smbios_guid, sizeof (smbios_guid)) == 0) + { + boot_params= tables[i].vendor_table; + grub_dprintf ("loongson", "found registered SMBIOS @ %p\n", boot_params); + break; + } + return boot_params; +} + +grub_uint8_t +grub_efi_loongson_calculatesum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) +{ + grub_uint8_t sum; + grub_efi_uintn_t count; + + for (sum = 0, count = 0; count < length; count++) + { + sum = (grub_uint8_t) (sum + *(buffer + count)); + } + return sum; +} + +grub_uint8_t +grub_efi_loongson_grub_calculatechecksum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) +{ + grub_uint8_t checksum; + + checksum = grub_efi_loongson_calculatesum8(buffer, length); + + return (grub_uint8_t) (0x100 - checksum); +} + + +grub_uint32_t +grub_efi_loongson_memmap_sort(struct memmap array[], grub_uint32_t length, mem_map * bpmem, grub_uint32_t index, grub_uint32_t memtype) +{ + grub_uint64_t tempmemsize = 0; + grub_uint32_t j = 0; + grub_uint32_t t = 0; + + for(j = 0; j < length;) + { + tempmemsize = array[j].memsize; + for(t = j + 1; t < length; t++) + { + if(array[j].memstart + tempmemsize == array[t].memstart) + { + tempmemsize += array[t].memsize; + } + else + { + break; + } + } + bpmem->map[index].memtype = memtype; + bpmem->map[index].memstart = array[j].memstart; + bpmem->map[index].memsize = tempmemsize; + grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", + index, + bpmem->map[index].memtype, + (unsigned long long)bpmem->map[index].memstart, + (unsigned long long)bpmem->map[index].memstart+ bpmem->map[index].memsize + ); + j = t; + index++; + } + return index; +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/efi/loongson_asm.S b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/efi/loongson_asm.S new file mode 100644 index 0000000..62d1ea9 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/efi/loongson_asm.S @@ -0,0 +1,61 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + + .file "loongson.S" + .text + + .set push + .set noreorder + .align 4 + +VARIABLE (grub_efi_loongson_reset_start) + +VARIABLE (grub_efi_loongson_reset_system_addr) + .dword 0 + +reset_system: + bal 1f + move $a1, $zero +1: + ld $t9, -16($ra) + move $a2, $zero + jalr $t9 + move $a3, $zero + +FUNCTION(grub_efi_loongson_reset_cold) + b reset_system + li $a0, 0 + +FUNCTION(grub_efi_loongson_reset_warm) + b reset_system + li $a0, 1 + +FUNCTION(grub_efi_loongson_reset_shutdown) + b reset_system + li $a0, 2 + +FUNCTION(grub_efi_loongson_reset_suspend) + b reset_system + li $a0, 3 + +VARIABLE (grub_efi_loongson_reset_end) + + .set pop + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/relocator.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/relocator.c new file mode 100644 index 0000000..2844504 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/relocator.c @@ -0,0 +1,169 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern grub_uint8_t grub_relocator_forward_start; +extern grub_uint8_t grub_relocator_forward_end; +extern grub_uint8_t grub_relocator_backward_start; +extern grub_uint8_t grub_relocator_backward_end; + +#define REGW_SIZEOF (6 * sizeof (grub_uint32_t)) +#define JUMP_SIZEOF (2 * sizeof (grub_uint32_t)) + +#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \ + - &grub_relocator_##x##_start) +#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ + + REGW_SIZEOF * 3) +grub_size_t grub_relocator_align = sizeof (grub_uint64_t); +grub_size_t grub_relocator_forward_size; +grub_size_t grub_relocator_backward_size; +grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; + +void +grub_cpu_relocator_init (void) +{ + grub_relocator_forward_size = RELOCATOR_SIZEOF(forward); + grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); +} + +static void +write_reg (int regn, grub_uint64_t val, void **target) +{ + grub_uint32_t lui; + grub_uint32_t ori; + grub_uint32_t dsll; + + /* lui $r, 0 */ + lui = (0x3c00 | regn) << 16; + /* ori $r, $r, 0 */ + ori = (0x3400 | (regn << 5) | regn) << 16; + /* dsll $r, $r, 16 */ + dsll = (regn << 16) | (regn << 11) | (16 << 6) | 56; + + /* lui $r, val[63:48]. */ + *(grub_uint32_t *) *target = lui | (grub_uint16_t) (val >> 48); + *target = ((grub_uint32_t *) *target) + 1; + /* ori $r, val[47:32]. */ + *(grub_uint32_t *) *target = ori | (grub_uint16_t) (val >> 32); + *target = ((grub_uint32_t *) *target) + 1; + /* dsll $r, $r, 16 */ + *(grub_uint32_t *) *target = dsll; + *target = ((grub_uint32_t *) *target) + 1; + /* ori $r, val[31:16]. */ + *(grub_uint32_t *) *target = ori | (grub_uint16_t) (val >> 16); + *target = ((grub_uint32_t *) *target) + 1; + /* dsll $r, $r, 16 */ + *(grub_uint32_t *) *target = dsll; + *target = ((grub_uint32_t *) *target) + 1; + /* ori $r, val[15:0]. */ + *(grub_uint32_t *) *target = ori | (grub_uint16_t) val; + *target = ((grub_uint32_t *) *target) + 1; +} + +static void +write_jump (int regn, void **target) +{ + /* j $r. */ + *(grub_uint32_t *) *target = (regn << 21) | 0x8; + *target = ((grub_uint32_t *) *target) + 1; + /* nop. */ + *(grub_uint32_t *) *target = 0; + *target = ((grub_uint32_t *) *target) + 1; +} + +void +grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) +{ + write_reg (1, addr, &rels); + write_jump (1, &rels); +} + +void +grub_cpu_relocator_backward (void *ptr0, void *src, void *dest, + grub_size_t size) +{ + void *ptr = ptr0; + write_reg (8, (grub_uint64_t) src, &ptr); + write_reg (9, (grub_uint64_t) dest, &ptr); + write_reg (10, (grub_uint64_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_backward_start, + RELOCATOR_SRC_SIZEOF (backward)); +} + +void +grub_cpu_relocator_forward (void *ptr0, void *src, void *dest, + grub_size_t size) +{ + void *ptr = ptr0; + write_reg (8, (grub_uint64_t) src, &ptr); + write_reg (9, (grub_uint64_t) dest, &ptr); + write_reg (10, (grub_uint64_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_forward_start, + RELOCATOR_SRC_SIZEOF (forward)); +} + +grub_err_t +grub_relocator64_boot (struct grub_relocator *rel, + struct grub_relocator64_state state) +{ + grub_relocator_chunk_t ch; + void *ptr; + grub_err_t err; + void *relst; + grub_size_t relsize; + grub_size_t stateset_size = 31 * REGW_SIZEOF + JUMP_SIZEOF; + unsigned i; + grub_addr_t vtarget; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + (0xffffffff - stateset_size) + + 1, stateset_size, + grub_relocator_align, + GRUB_RELOCATOR_PREFERENCE_NONE, 0); + if (err) + return err; + + ptr = get_virtual_current_address (ch); + for (i = 1; i < 32; i++) + write_reg (i, state.gpr[i], &ptr); + write_jump (state.jumpreg, &ptr); + + vtarget = (grub_addr_t) grub_map_memory (get_physical_target_address (ch), + stateset_size); + + err = grub_relocator_prepare_relocs (rel, vtarget, &relst, &relsize); + if (err) + return err; + + grub_arch_sync_caches ((void *) relst, relsize); + + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/relocator_asm.S b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/relocator_asm.S new file mode 100644 index 0000000..9ff3c8e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/relocator_asm.S @@ -0,0 +1,56 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + + .p2align 4 /* force 16-byte alignment */ + + .set push + .set noreorder + .set nomacro + +VARIABLE (grub_relocator_forward_start) + +copycont1: + ld $11,0($8) + sd $11,0($9) + daddiu $8, $8, 8 + daddiu $10, $10, -8 + bne $10, $0, copycont1 + daddiu $9, $9, 8 + +VARIABLE (grub_relocator_forward_end) + +VARIABLE (grub_relocator_backward_start) + + daddu $9, $9, $10 + daddu $8, $8, $10 + /* Backward movsl is implicitly off-by-one. compensate that. */ + daddiu $9, $9, -8 + daddiu $8, $8, -8 +copycont2: + ld $11,0($8) + sd $11,0($9) + daddiu $8, $8, -8 + daddiu $10, $10, -8 + bne $10, $0, copycont2 + daddiu $9, $9, -8 + +VARIABLE (grub_relocator_backward_end) + + .set pop diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/setjmp.S b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/setjmp.S new file mode 100644 index 0000000..8766ab5 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/mips64/setjmp.S @@ -0,0 +1,69 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2007,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include + + .file "setjmp.S" + +GRUB_MOD_LICENSE "GPLv3+" + + .text + +/* + * int grub_setjmp (grub_jmp_buf env) + */ +FUNCTION(grub_setjmp) + GRUB_ASM_REG_S $s0, 0($a0) + GRUB_ASM_REG_S $s1, 8($a0) + GRUB_ASM_REG_S $s2, 16($a0) + GRUB_ASM_REG_S $s3, 24($a0) + GRUB_ASM_REG_S $s4, 32($a0) + GRUB_ASM_REG_S $s5, 40($a0) + GRUB_ASM_REG_S $s6, 48($a0) + GRUB_ASM_REG_S $s7, 56($a0) + GRUB_ASM_REG_S $s8, 64($a0) + GRUB_ASM_REG_S $gp, 72($a0) + GRUB_ASM_REG_S $sp, 80($a0) + GRUB_ASM_REG_S $ra, 88($a0) + move $v0, $zero + move $v1, $zero + jr $ra + nop +/* + * int grub_longjmp (grub_jmp_buf env, int val) + */ +FUNCTION(grub_longjmp) + GRUB_ASM_REG_L $s0, 0($a0) + GRUB_ASM_REG_L $s1, 8($a0) + GRUB_ASM_REG_L $s2, 16($a0) + GRUB_ASM_REG_L $s3, 24($a0) + GRUB_ASM_REG_L $s4, 32($a0) + GRUB_ASM_REG_L $s5, 40($a0) + GRUB_ASM_REG_L $s6, 48($a0) + GRUB_ASM_REG_L $s7, 56($a0) + GRUB_ASM_REG_L $s8, 64($a0) + GRUB_ASM_REG_L $gp, 72($a0) + GRUB_ASM_REG_L $sp, 80($a0) + GRUB_ASM_REG_L $ra, 88($a0) + addiu $v0, $zero, 1 + movn $v0, $a1, $a1 + move $v1, $zero + jr $ra + nop diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/relocator.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/relocator.c new file mode 100644 index 0000000..22454e3 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/relocator.c @@ -0,0 +1,1660 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009, 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +struct grub_relocator +{ + struct grub_relocator_chunk *chunks; + grub_phys_addr_t postchunks; + grub_phys_addr_t highestaddr; + grub_phys_addr_t highestnonpostaddr; + grub_size_t relocators_size; +}; + +struct grub_relocator_subchunk +{ + enum {CHUNK_TYPE_IN_REGION, CHUNK_TYPE_REGION_START, +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + CHUNK_TYPE_FIRMWARE, CHUNK_TYPE_LEFTOVER +#endif + } type; + grub_mm_region_t reg; + grub_phys_addr_t start; + grub_size_t size; + grub_size_t pre_size; + struct grub_relocator_extra_block *extra; +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + struct grub_relocator_fw_leftover *pre, *post; +#endif +}; + +struct grub_relocator_chunk +{ + struct grub_relocator_chunk *next; + grub_phys_addr_t src; + void *srcv; + grub_phys_addr_t target; + grub_size_t size; + struct grub_relocator_subchunk *subchunks; + unsigned nsubchunks; +}; + +struct grub_relocator_extra_block +{ + struct grub_relocator_extra_block *next; + struct grub_relocator_extra_block **prev; + grub_phys_addr_t start; + grub_phys_addr_t end; +}; + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS +struct grub_relocator_fw_leftover +{ + struct grub_relocator_fw_leftover *next; + struct grub_relocator_fw_leftover **prev; + grub_phys_addr_t quantstart; + grub_uint8_t freebytes[GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT / 8]; +}; + +static struct grub_relocator_fw_leftover *leftovers; +#endif + +static struct grub_relocator_extra_block *extra_blocks; + +void * +get_virtual_current_address (grub_relocator_chunk_t in) +{ + return in->srcv; +} + +grub_phys_addr_t +get_physical_target_address (grub_relocator_chunk_t in) +{ + return in->target; +} + +struct grub_relocator * +grub_relocator_new (void) +{ + struct grub_relocator *ret; + + grub_cpu_relocator_init (); + + ret = grub_zalloc (sizeof (struct grub_relocator)); + if (!ret) + return NULL; + + ret->postchunks = ~(grub_phys_addr_t) 0; + ret->relocators_size = grub_relocator_jumper_size; + grub_dprintf ("relocator", "relocators_size=%lu\n", + (unsigned long) ret->relocators_size); + return ret; +} + +#define DIGITSORT_BITS 8 +#define DIGITSORT_MASK ((1 << DIGITSORT_BITS) - 1) +#define BITS_IN_BYTE 8 + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) + +static inline int +is_start (int type) +{ + return !(type & 1) && (type != COLLISION_START); +} + +static void +allocate_regstart (grub_phys_addr_t addr, grub_size_t size, grub_mm_region_t rb, + grub_mm_region_t *regancestor, grub_mm_header_t hancestor) +{ + grub_addr_t newreg_start, newreg_raw_start + = (grub_addr_t) rb + (addr - grub_vtop (rb)) + size; + grub_addr_t newreg_size, newreg_presize; + grub_mm_header_t new_header; + grub_mm_header_t hb = (grub_mm_header_t) (rb + 1); + +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF + grub_dprintf ("relocator", "ra = %p, rb = %p\n", regancestor, rb); +#endif + newreg_start = ALIGN_UP (newreg_raw_start, GRUB_MM_ALIGN); + newreg_presize = newreg_start - newreg_raw_start; + newreg_size = rb->size - (newreg_start - (grub_addr_t) rb); + if ((hb->size << GRUB_MM_ALIGN_LOG2) >= newreg_start + - (grub_addr_t) rb) + { + grub_mm_header_t newhnext = hb->next; + grub_size_t newhsize = ((hb->size << GRUB_MM_ALIGN_LOG2) + - (newreg_start + - (grub_addr_t) rb)) >> GRUB_MM_ALIGN_LOG2; + new_header = (void *) (newreg_start + sizeof (*rb)); + if (newhnext == hb) + newhnext = new_header; + new_header->next = newhnext; + new_header->size = newhsize; + new_header->magic = GRUB_MM_FREE_MAGIC; + } + else + { + new_header = hb->next; + if (new_header == hb) + new_header = (void *) (newreg_start + sizeof (*rb)); + } + { + struct grub_mm_header *newregfirst = rb->first; + struct grub_mm_region *newregnext = rb->next; + struct grub_mm_region *newreg = (void *) newreg_start; + hancestor->next = new_header; + if (newregfirst == hb) + newregfirst = new_header; + newreg->first = newregfirst; + newreg->next = newregnext; + newreg->pre_size = newreg_presize; + newreg->size = newreg_size; + *regancestor = newreg; + { + grub_mm_header_t h = newreg->first, hp = NULL; + do + { + if ((void *) h < (void *) (newreg + 1)) + grub_fatal ("Failed to adjust memory region: %p, %p, %p, %p, %p", + newreg, newreg->first, h, hp, hb); +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF + if ((void *) h == (void *) (newreg + 1)) + grub_dprintf ("relocator", + "Free start memory region: %p, %p, %p, %p, %p", + newreg, newreg->first, h, hp, hb); +#endif + hp = h; + h = h->next; + } + while (h != newreg->first); + } + } +} + +static void +allocate_inreg (grub_phys_addr_t paddr, grub_size_t size, + grub_mm_header_t hb, grub_mm_header_t hbp, + grub_mm_region_t rb) +{ + struct grub_mm_header *foll = NULL; + grub_addr_t vaddr = (grub_addr_t) hb + (paddr - grub_vtop (hb)); + +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF + grub_dprintf ("relocator", "inreg paddr = 0x%lx, size = %lu," + " hb = %p, hbp = %p, rb = %p, vaddr = 0x%lx\n", + (unsigned long) paddr, (unsigned long) size, hb, hbp, + rb, (unsigned long) vaddr); +#endif + + if (ALIGN_UP (vaddr + size, GRUB_MM_ALIGN) + GRUB_MM_ALIGN + <= (grub_addr_t) (hb + hb->size)) + { + foll = (void *) ALIGN_UP (vaddr + size, GRUB_MM_ALIGN); + foll->magic = GRUB_MM_FREE_MAGIC; + foll->size = hb + hb->size - foll; +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF + grub_dprintf ("relocator", "foll = %p, foll->size = %lu\n", foll, + (unsigned long) foll->size); +#endif + } + + if (vaddr - (grub_addr_t) hb >= sizeof (*hb)) + { + hb->size = ((vaddr - (grub_addr_t) hb) >> GRUB_MM_ALIGN_LOG2); + if (foll) + { + foll->next = hb; + hbp->next = foll; + if (rb->first == hb) + { + rb->first = foll; + } + } + } + else + { + if (foll) + { + foll->next = hb->next; + } + else + foll = hb->next; + + hbp->next = foll; + if (rb->first == hb) + { + rb->first = foll; + } + if (rb->first == hb) + { + rb->first = (void *) (rb + 1); + } + } +} + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS +static void +check_leftover (struct grub_relocator_fw_leftover *lo) +{ + unsigned i; + for (i = 0; i < sizeof (lo->freebytes); i++) + if (lo->freebytes[i] != 0xff) + return; + grub_relocator_firmware_free_region (lo->quantstart, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + *lo->prev = lo->next; + if (lo->next) + lo->next->prev = lo->prev; +} +#endif + +static void +free_subchunk (const struct grub_relocator_subchunk *subchu) +{ + switch (subchu->type) + { + case CHUNK_TYPE_REGION_START: + { + grub_mm_region_t r1, r2, *rp; + grub_mm_header_t h; + grub_size_t pre_size; + r1 = subchu->reg; + r2 = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) subchu->reg + + (grub_vtop (subchu->reg) + - subchu->start) + subchu->size, + GRUB_MM_ALIGN); + for (rp = &grub_mm_base; *rp && *rp != r2; rp = &((*rp)->next)); + pre_size = subchu->pre_size; + + if (*rp) + { + grub_mm_header_t h2, *hp; + r1->first = r2->first; + r1->next = r2->next; + r1->pre_size = pre_size; + r1->size = r2->size + (r2 - r1) * sizeof (*r2); + *rp = r1; + h = (grub_mm_header_t) (r1 + 1); + h->next = r2->first; + h->magic = GRUB_MM_FREE_MAGIC; + h->size = (r2 - r1 - 1); + for (hp = &r2->first, h2 = *hp; h2->next != r2->first; + hp = &(h2->next), h2 = *hp) + if (h2 == (grub_mm_header_t) (r2 + 1)) + break; + if (h2 == (grub_mm_header_t) (r2 + 1)) + { + h->size = h2->size + (h2 - h); + h->next = h2->next; + *hp = h; + if (hp == &r2->first) + { + for (h2 = r2->first; h2->next != r2->first; h2 = h2->next); + h2->next = h; + } + } + else + { + h2->next = h; + } + } + else + { + r1->pre_size = pre_size; + r1->size = (r2 - r1) * sizeof (*r2); + /* Find where to insert this region. + Put a smaller one before bigger ones, + to prevent fragmentation. */ + for (rp = &grub_mm_base; *rp; rp = &((*rp)->next)) + if ((*rp)->size > r1->size) + break; + r1->next = *rp; + *rp = r1->next; + h = (grub_mm_header_t) (r1 + 1); + r1->first = h; + h->next = h; + h->magic = GRUB_MM_FREE_MAGIC; + h->size = (r2 - r1 - 1); + } + for (r2 = grub_mm_base; r2; r2 = r2->next) + if ((grub_addr_t) r2 + r2->size == (grub_addr_t) r1) + break; + if (r2) + { + grub_mm_header_t hl2, hl, g; + g = (grub_mm_header_t) ((grub_addr_t) r2 + r2->size); + g->size = (grub_mm_header_t) r1 - g; + r2->size += r1->size; + for (hl = r2->first; hl->next != r2->first; hl = hl->next); + for (hl2 = r1->first; hl2->next != r1->first; hl2 = hl2->next); + hl2->next = r2->first; + r2->first = r1->first; + hl->next = r2->first; + *rp = (*rp)->next; + grub_free (g + 1); + } + break; + } + case CHUNK_TYPE_IN_REGION: + { + grub_mm_header_t h = (grub_mm_header_t) ALIGN_DOWN ((grub_addr_t) subchu->start, + GRUB_MM_ALIGN); + h->size + = ((subchu->start + subchu->size + GRUB_MM_ALIGN - 1) / GRUB_MM_ALIGN) + - (subchu->start / GRUB_MM_ALIGN) - 1; + h->next = h; + h->magic = GRUB_MM_ALLOC_MAGIC; + grub_free (h + 1); + break; + } +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case CHUNK_TYPE_FIRMWARE: + case CHUNK_TYPE_LEFTOVER: + { + grub_addr_t fstart, fend; + fstart = ALIGN_UP (subchu->start, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + fend = ALIGN_DOWN (subchu->start + subchu->size, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + if (fstart < fend) + grub_relocator_firmware_free_region (fstart, fend - fstart); +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + if (subchu->pre) + { + int off = subchu->start - fstart + - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + grub_memset (subchu->pre->freebytes + off / 8 + 1, + 0xff, sizeof (subchu->pre->freebytes) - off / 8 - 1); + subchu->pre->freebytes[off / 8] |= ~((1 << (off % 8)) - 1); + check_leftover (subchu->pre); + } + if (subchu->post) + { + int off = subchu->start + subchu->size - fend; + grub_memset (subchu->pre->freebytes, + 0xff, sizeof (subchu->pre->freebytes) - off / 8); + subchu->pre->freebytes[off / 8] |= ((1 << (8 - (off % 8))) - 1); + check_leftover (subchu->post); + } +#endif + *subchu->extra->prev = subchu->extra->next; + grub_free (subchu->extra); + } + break; +#endif + } +} + +static int +malloc_in_range (struct grub_relocator *rel, + grub_addr_t start, grub_addr_t end, grub_addr_t align, + grub_size_t size, struct grub_relocator_chunk *res, + int from_low_priv, int collisioncheck) +{ + grub_mm_region_t r, *ra, base_saved; + struct grub_relocator_mmap_event *events = NULL, *eventt = NULL, *t; + /* 128 is just in case of additional malloc (shouldn't happen). */ + unsigned maxevents = 2 + 128; + grub_mm_header_t p, pa; + unsigned *counter; + int nallocs = 0; + unsigned j, N = 0; + grub_addr_t target = 0; + + grub_dprintf ("relocator", + "trying to allocate in 0x%lx-0x%lx aligned 0x%lx size 0x%lx\n", + (unsigned long) start, (unsigned long) end, + (unsigned long) align, (unsigned long) size); + + start = ALIGN_UP (start, align); + end = ALIGN_DOWN (end - size, align) + size; + + if (end < start + size) + return 0; + + /* We have to avoid any allocations when filling scanline events. + Hence 2-stages. + */ + for (r = grub_mm_base; r; r = r->next) + { + p = r->first; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal ("%d: out of range pointer: %p\n", __LINE__, p); + maxevents += 2; + p = p->next; + } + while (p != r->first); + maxevents += 4; + } + + if (collisioncheck && rel) + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + maxevents += 2; + } + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + { + struct grub_relocator_extra_block *cur; + for (cur = extra_blocks; cur; cur = cur->next) + maxevents += 2; + } + for (r = grub_mm_base; r; r = r->next) + maxevents += 2; + + maxevents += grub_relocator_firmware_get_max_events (); +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + { + struct grub_relocator_fw_leftover *cur; + for (cur = leftovers; cur; cur = cur->next) + { + int l = 0; + unsigned i; + for (i = 0; i < GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; i++) + { + if (l != ((cur->freebytes[i / 8] >> (i % 8)) & 1)) + maxevents++; + l = ((cur->freebytes[i / 8] >> (i % 8)) & 1); + } + if (l) + maxevents++; + } + } +#endif + + eventt = grub_malloc (maxevents * sizeof (events[0])); + counter = grub_malloc ((DIGITSORT_MASK + 2) * sizeof (counter[0])); + events = grub_malloc (maxevents * sizeof (events[0])); + if (!events || !eventt || !counter) + { + grub_dprintf ("relocator", "events or counter allocation failed %d\n", + maxevents); + grub_free (events); + grub_free (eventt); + grub_free (counter); + return 0; + } + + if (collisioncheck && rel) + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + { + events[N].type = COLLISION_START; + events[N].pos = chunk->target; + N++; + events[N].type = COLLISION_END; + events[N].pos = chunk->target + chunk->size; + N++; + } + } + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + for (r = grub_mm_base; r; r = r->next) + { +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF + grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n", + (unsigned long) r - r->pre_size, + (unsigned long) (r + 1) + r->size); +#endif + events[N].type = FIRMWARE_BLOCK_START; + events[N].pos = (grub_addr_t) r - r->pre_size; + N++; + events[N].type = FIRMWARE_BLOCK_END; + events[N].pos = (grub_addr_t) (r + 1) + r->size; + N++; + } + { + struct grub_relocator_extra_block *cur; + for (cur = extra_blocks; cur; cur = cur->next) + { +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF + grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n", + (unsigned long) cur->start, (unsigned long) cur->end); +#endif + events[N].type = FIRMWARE_BLOCK_START; + events[N].pos = cur->start; + N++; + events[N].type = FIRMWARE_BLOCK_END; + events[N].pos = cur->end; + N++; + } + } + + N += grub_relocator_firmware_fill_events (events + N); + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + { + struct grub_relocator_fw_leftover *cur; + for (cur = leftovers; cur; cur = cur->next) + { + unsigned i; + int l = 0; + for (i = 0; i < GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; i++) + { + if (l != ((cur->freebytes[i / 8] >> (i % 8)) & 1)) + { + events[N].type = l ? REG_LEFTOVER_END : REG_LEFTOVER_START; + events[N].pos = cur->quantstart + i; + events[N].leftover = cur; + N++; + } + l = ((cur->freebytes[i / 8] >> (i % 8)) & 1); + } + if (l) + { + events[N].type = REG_LEFTOVER_END; + events[N].pos = cur->quantstart + i; + events[N].leftover = cur; + N++; + } + } + } +#endif +#endif + + /* No malloc from this point. */ + base_saved = grub_mm_base; + grub_mm_base = NULL; + + for (ra = &base_saved, r = *ra; r; ra = &(r->next), r = *ra) + { + pa = r->first; + p = pa->next; + if (p->magic == GRUB_MM_ALLOC_MAGIC) + continue; + do + { + if (p->magic != GRUB_MM_FREE_MAGIC) + grub_fatal ("%s:%d free magic broken at %p (0x%x)\n", + __FILE__, + __LINE__, p, p->magic); + if (p == (grub_mm_header_t) (r + 1)) + { + events[N].type = REG_BEG_START; + events[N].pos = grub_vtop (r) - r->pre_size; + events[N].reg = r; + events[N].regancestor = ra; + events[N].head = p; + events[N].hancestor = pa; + N++; + events[N].type = REG_BEG_END; + events[N].pos = grub_vtop (p + p->size) - sizeof (*r) + - sizeof (struct grub_mm_header); + N++; + } + else + { + events[N].type = IN_REG_START; + events[N].pos = grub_vtop (p); + events[N].head = p; + events[N].hancestor = pa; + events[N].reg = r; + N++; + events[N].type = IN_REG_END; + events[N].pos = grub_vtop (p + p->size); + N++; + } + pa = p; + p = pa->next; + } + while (pa != r->first); + } + + /* Put ending events after starting events. */ + { + int st = 0, e = N / 2; + for (j = 0; j < N; j++) + if (is_start (events[j].type) || events[j].type == COLLISION_START) + eventt[st++] = events[j]; + else + eventt[e++] = events[j]; + t = eventt; + eventt = events; + events = t; + } + + { + unsigned i; + for (i = 0; i < (BITS_IN_BYTE * sizeof (grub_addr_t) / DIGITSORT_BITS); + i++) + { + grub_memset (counter, 0, (1 + (1 << DIGITSORT_BITS)) * sizeof (counter[0])); + for (j = 0; j < N; j++) + counter[((events[j].pos >> (DIGITSORT_BITS * i)) + & DIGITSORT_MASK) + 1]++; + for (j = 0; j <= DIGITSORT_MASK; j++) + counter[j+1] += counter[j]; + for (j = 0; j < N; j++) + eventt[counter[((events[j].pos >> (DIGITSORT_BITS * i)) + & DIGITSORT_MASK)]++] = events[j]; + t = eventt; + eventt = events; + events = t; + } + } + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + retry: +#endif + + /* Now events are nicely sorted. */ + { + int nstarted = 0, ncollisions = 0, nstartedfw = 0, nblockfw = 0; +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + int nlefto = 0; +#else + const int nlefto = 0; +#endif + grub_addr_t starta = 0; + for (j = from_low_priv ? 0 : N - 1; from_low_priv ? j < N : (j + 1); + from_low_priv ? j++ : j--) + { + int isinsidebefore, isinsideafter; + isinsidebefore = (!ncollisions && (nstarted || (((nlefto || nstartedfw) + && !nblockfw)))); + switch (events[j].type) + { +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case REG_FIRMWARE_START: + nstartedfw++; + break; + + case REG_FIRMWARE_END: + nstartedfw--; + break; + + case FIRMWARE_BLOCK_START: + nblockfw++; + break; + + case FIRMWARE_BLOCK_END: + nblockfw--; + break; +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case REG_LEFTOVER_START: + nlefto++; + break; + + case REG_LEFTOVER_END: + nlefto--; + break; +#endif + + case COLLISION_START: + ncollisions++; + break; + + case COLLISION_END: + ncollisions--; + break; + + case IN_REG_START: + case REG_BEG_START: + nstarted++; + break; + + case IN_REG_END: + case REG_BEG_END: + nstarted--; + break; + } + isinsideafter = (!ncollisions && (nstarted || ((nlefto || nstartedfw) + && !nblockfw))); + if (from_low_priv) { + if (!isinsidebefore && isinsideafter) + starta = ALIGN_UP (events[j].pos, align); + + if (isinsidebefore && !isinsideafter) + { + target = starta; + if (target < start) + target = start; + if (target + size <= end && target + size <= events[j].pos) + /* Found an usable address. */ + goto found; + } + } else { + if (!isinsidebefore && isinsideafter) + { + if (events[j].pos >= size) + starta = ALIGN_DOWN (events[j].pos - size, align) + size; + else + starta = 0; + } + if (isinsidebefore && !isinsideafter && starta >= size) + { + target = starta - size; + if (target > end - size) + target = end - size; + if (target >= start && target >= events[j].pos) + goto found; + } + } + } + } + + grub_mm_base = base_saved; + grub_free (events); + grub_free (eventt); + grub_free (counter); + return 0; + + found: + { + int inreg = 0, regbeg = 0, ncol = 0; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + int fwin = 0, fwb = 0, fwlefto = 0; +#endif +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + int last_lo = 0; +#endif + int last_start = 0; + for (j = 0; j < N; j++) + { + int typepre; + if (ncol) + typepre = -1; + else if (regbeg) + typepre = CHUNK_TYPE_REGION_START; + else if (inreg) + typepre = CHUNK_TYPE_IN_REGION; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + else if (fwin && !fwb) + typepre = CHUNK_TYPE_FIRMWARE; + else if (fwlefto && !fwb) + typepre = CHUNK_TYPE_LEFTOVER; +#endif + else + typepre = -1; + + if (j != 0 && events[j - 1].pos != events[j].pos) + { + grub_addr_t alloc_start, alloc_end; + alloc_start = max (events[j - 1].pos, target); + alloc_end = min (events[j].pos, target + size); + if (alloc_end > alloc_start) + { + switch (typepre) + { + case CHUNK_TYPE_REGION_START: + allocate_regstart (alloc_start, alloc_end - alloc_start, + events[last_start].reg, + events[last_start].regancestor, + events[last_start].hancestor); + /* TODO: maintain a reverse lookup tree for hancestor. */ + { + unsigned k; + for (k = 0; k < N; k++) + if (events[k].hancestor == events[last_start].head) + events[k].hancestor = events[last_start].hancestor; + } + break; + case CHUNK_TYPE_IN_REGION: + allocate_inreg (alloc_start, alloc_end - alloc_start, + events[last_start].head, + events[last_start].hancestor, + events[last_start].reg); + { + unsigned k; + for (k = 0; k < N; k++) + if (events[k].hancestor == events[last_start].head) + events[k].hancestor = events[last_start].hancestor; + } + break; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case CHUNK_TYPE_FIRMWARE: + { + grub_addr_t fstart, fend; + fstart + = ALIGN_DOWN (alloc_start, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + fend + = ALIGN_UP (alloc_end, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF + grub_dprintf ("relocator", "requesting %lx-%lx\n", + (unsigned long) fstart, + (unsigned long) fend); +#endif + /* The failure here can be very expensive. */ + if (!grub_relocator_firmware_alloc_region (fstart, + fend - fstart)) + { + if (from_low_priv) + start = fend; + else + end = fstart; + goto retry; + } + break; + } +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case CHUNK_TYPE_LEFTOVER: + { + unsigned offstart = alloc_start + % GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + unsigned offend = alloc_end + % GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + struct grub_relocator_fw_leftover *lo + = events[last_lo].leftover; + if (offend == 0 && alloc_end != alloc_start) + offend = GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + lo->freebytes[offstart / 8] + &= ((1 << (8 - (start % 8))) - 1); + grub_memset (lo->freebytes + (offstart + 7) / 8, 0, + offend / 8 - (offstart + 7) / 8); + lo->freebytes[offend / 8] &= ~((1 << (offend % 8)) - 1); + } + break; +#endif + } + nallocs++; + } + } + + switch (events[j].type) + { + case REG_BEG_START: + case IN_REG_START: + if (events[j].type == REG_BEG_START && + (grub_addr_t) (events[j].reg + 1) > target) + regbeg++; + else + inreg++; + last_start = j; + break; + + case REG_BEG_END: + case IN_REG_END: + if (regbeg) + regbeg--; + else + inreg--; + break; + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case REG_FIRMWARE_START: + fwin++; + break; + + case REG_FIRMWARE_END: + fwin--; + break; + + case FIRMWARE_BLOCK_START: + fwb++; + break; + + case FIRMWARE_BLOCK_END: + fwb--; + break; +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case REG_LEFTOVER_START: + fwlefto++; + last_lo = j; + break; + + case REG_LEFTOVER_END: + fwlefto--; + break; +#endif + case COLLISION_START: + ncol++; + break; + case COLLISION_END: + ncol--; + break; + } + + } + } + + /* Malloc is available again. */ + grub_mm_base = base_saved; + + grub_free (eventt); + grub_free (counter); + + { + int last_start = 0; + int inreg = 0, regbeg = 0, ncol = 0; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + int fwin = 0, fwlefto = 0, fwb = 0; +#endif + unsigned cural = 0; + int oom = 0; + res->subchunks = grub_malloc (sizeof (res->subchunks[0]) * nallocs); + if (!res->subchunks) + oom = 1; + res->nsubchunks = nallocs; + + for (j = 0; j < N; j++) + { + int typepre; + if (ncol) + typepre = -1; + else if (regbeg) + typepre = CHUNK_TYPE_REGION_START; + else if (inreg) + typepre = CHUNK_TYPE_IN_REGION; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + else if (fwin && !fwb) + typepre = CHUNK_TYPE_FIRMWARE; + else if (fwlefto && !fwb) + typepre = CHUNK_TYPE_LEFTOVER; +#endif + else + typepre = -1; + + if (j != 0 && events[j - 1].pos != events[j].pos) + { + grub_addr_t alloc_start, alloc_end; + struct grub_relocator_subchunk tofree; + struct grub_relocator_subchunk *curschu = &tofree; + if (!oom) + curschu = &res->subchunks[cural]; + alloc_start = max (events[j - 1].pos, target); + alloc_end = min (events[j].pos, target + size); + if (alloc_end > alloc_start) + { +#ifdef DEBUG_RELOCATOR_NOMEM_DPRINTF + grub_dprintf ("relocator", "subchunk 0x%lx-0x%lx, %d\n", + (unsigned long) alloc_start, + (unsigned long) alloc_end, typepre); +#endif + curschu->type = typepre; + curschu->start = alloc_start; + curschu->size = alloc_end - alloc_start; + if (typepre == CHUNK_TYPE_REGION_START + || typepre == CHUNK_TYPE_IN_REGION) + { + curschu->reg = events[last_start].reg; + curschu->pre_size = alloc_start - events[j - 1].pos; + } + if (!oom && (typepre == CHUNK_TYPE_REGION_START +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + || typepre == CHUNK_TYPE_FIRMWARE +#endif + )) + { + struct grub_relocator_extra_block *ne; + ne = grub_malloc (sizeof (*ne)); + if (!ne) + { + oom = 1; + grub_memcpy (&tofree, curschu, sizeof (tofree)); + } + else + { + ne->start = alloc_start; + ne->end = alloc_end; + ne->next = extra_blocks; + ne->prev = &extra_blocks; + if (extra_blocks) + extra_blocks->prev = &(ne->next); + extra_blocks = ne; + curschu->extra = ne; + } + } + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + if (!oom && typepre == CHUNK_TYPE_FIRMWARE) + { + grub_addr_t fstart, fend; + + fstart + = ALIGN_DOWN (alloc_start, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + fend + = ALIGN_UP (alloc_end, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + + { + struct grub_relocator_fw_leftover *lo1 = NULL; + struct grub_relocator_fw_leftover *lo2 = NULL; + if (fstart != alloc_start) + lo1 = grub_malloc (sizeof (*lo1)); + if (fend != alloc_end) + lo2 = grub_malloc (sizeof (*lo2)); + if ((!lo1 && fstart != alloc_start) + || (!lo2 && fend != alloc_end)) + { + struct grub_relocator_extra_block *ne; + grub_free (lo1); + grub_free (lo2); + lo1 = NULL; + lo2 = NULL; + oom = 1; + grub_memcpy (&tofree, curschu, sizeof (tofree)); + ne = extra_blocks; + extra_blocks = extra_blocks->next; + grub_free (ne); + } + if (lo1) + { + lo1->quantstart = fstart; + grub_memset (lo1->freebytes, 0xff, + (alloc_start - fstart) / 8); + lo1->freebytes[(alloc_start - fstart) / 8] + = (1 << ((alloc_start - fstart) % 8)) - 1; + grub_memset (lo1->freebytes + + ((alloc_start - fstart) / 8) + 1, 0, + sizeof (lo1->freebytes) + - (alloc_start - fstart) / 8 - 1); + lo1->next = leftovers; + lo1->prev = &leftovers; + if (leftovers) + leftovers->prev = &lo1->next; + leftovers = lo1; + } + if (lo2) + { + lo2->quantstart + = fend - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + grub_memset (lo2->freebytes, 0, + (alloc_end - lo2->quantstart) / 8); + lo2->freebytes[(alloc_end - lo2->quantstart) / 8] + = ~((1 << ((alloc_end - lo2->quantstart) % 8)) - 1); + grub_memset (lo2->freebytes + + ((alloc_end - lo2->quantstart) / 8) + + 1, 0, sizeof (lo2->freebytes) + - (alloc_end - lo2->quantstart) / 8 - 1); + lo2->prev = &leftovers; + if (leftovers) + leftovers->prev = &lo2->next; + lo2->next = leftovers; + leftovers = lo2; + } + curschu->pre = lo1; + curschu->post = lo2; + } + } + + if (typepre == CHUNK_TYPE_LEFTOVER) + { + curschu->pre = events[last_start].leftover; + curschu->post = events[last_start].leftover; + } +#endif + + if (!oom) + cural++; + else + free_subchunk (&tofree); + } + } + + switch (events[j].type) + { + case REG_BEG_START: + case IN_REG_START: + if (events[j].type == REG_BEG_START && + (grub_addr_t) (events[j].reg + 1) > target) + regbeg++; + else + inreg++; + last_start = j; + break; + + case REG_BEG_END: + case IN_REG_END: + inreg = regbeg = 0; + break; + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case REG_FIRMWARE_START: + fwin++; + break; + + case REG_FIRMWARE_END: + fwin--; + break; + + case FIRMWARE_BLOCK_START: + fwb++; + break; + + case FIRMWARE_BLOCK_END: + fwb--; + break; +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case REG_LEFTOVER_START: + fwlefto++; + break; + + case REG_LEFTOVER_END: + fwlefto--; + break; +#endif + case COLLISION_START: + ncol++; + break; + case COLLISION_END: + ncol--; + break; + } + } + if (oom) + { + unsigned i; + for (i = 0; i < cural; i++) + free_subchunk (&res->subchunks[i]); + grub_free (res->subchunks); + grub_dprintf ("relocator", "allocation failed with out-of-memory\n"); + grub_free (events); + + return 0; + } + } + + res->src = target; + res->size = size; + + grub_free (events); + + grub_dprintf ("relocator", "allocated: 0x%lx+0x%lx\n", (unsigned long) target, + (unsigned long) size); + + return 1; +} + +static void +adjust_limits (struct grub_relocator *rel, + grub_phys_addr_t *min_addr, grub_phys_addr_t *max_addr, + grub_phys_addr_t in_min, grub_phys_addr_t in_max) +{ + struct grub_relocator_chunk *chunk; + + *min_addr = 0; + *max_addr = rel->postchunks; + + /* Keep chunks in memory in the same order as they'll be after relocation. */ + for (chunk = rel->chunks; chunk; chunk = chunk->next) + { + if (chunk->target > in_max && chunk->src < *max_addr + && chunk->src < rel->postchunks) + *max_addr = chunk->src; + if (chunk->target + chunk->size <= in_min + && chunk->src + chunk->size > *min_addr + && chunk->src < rel->postchunks) + *min_addr = chunk->src + chunk->size; + } +} + +grub_err_t +grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t target, grub_size_t size) +{ + struct grub_relocator_chunk *chunk; + grub_phys_addr_t min_addr = 0, max_addr; + + if (target > ~size) + return grub_error (GRUB_ERR_BUG, "address is out of range"); + + adjust_limits (rel, &min_addr, &max_addr, target, target); + + for (chunk = rel->chunks; chunk; chunk = chunk->next) + if ((chunk->target <= target && target < chunk->target + chunk->size) + || (target <= chunk->target && chunk->target < target + size)) + return grub_error (GRUB_ERR_BUG, "overlap detected"); + + chunk = grub_malloc (sizeof (struct grub_relocator_chunk)); + if (!chunk) + return grub_errno; + + grub_dprintf ("relocator", + "min_addr = 0x%llx, max_addr = 0x%llx, target = 0x%llx\n", + (unsigned long long) min_addr, (unsigned long long) max_addr, + (unsigned long long) target); + + do + { + /* A trick to improve Linux allocation. */ +#if defined (__i386__) || defined (__x86_64__) + if (target < 0x100000) + if (malloc_in_range (rel, rel->highestnonpostaddr, ~(grub_addr_t)0, 1, + size, chunk, 0, 1)) + { + if (rel->postchunks > chunk->src) + rel->postchunks = chunk->src; + break; + } +#elif defined(__mips__) && (_MIPS_SIM == _ABI64) + if (malloc_in_range (rel, target, max_addr, 8, size, chunk, 1, 0)) + break; +#endif + if (malloc_in_range (rel, target, max_addr, 1, size, chunk, 1, 0)) + break; + + if (malloc_in_range (rel, min_addr, target, 1, size, chunk, 0, 0)) + break; + + if (malloc_in_range (rel, rel->highestnonpostaddr, ~(grub_addr_t)0, 1, + size, chunk, 0, 1)) + { + if (rel->postchunks > chunk->src) + rel->postchunks = chunk->src; + break; + } + + grub_dprintf ("relocator", "not allocated\n"); + grub_free (chunk); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + } + while (0); + + grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n", + (unsigned long long) chunk->src, (unsigned long long) target); + + if (rel->highestaddr < target + size) + rel->highestaddr = target + size; + + if (rel->highestaddr < chunk->src + size) + rel->highestaddr = chunk->src + size; + + if (chunk->src < rel->postchunks) + { + if (rel->highestnonpostaddr < target + size) + rel->highestnonpostaddr = target + size; + + if (rel->highestnonpostaddr < chunk->src + size) + rel->highestnonpostaddr = chunk->src + size; + } + + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + + if (chunk->src < target) + rel->relocators_size += grub_relocator_backward_size; + if (chunk->src > target) + rel->relocators_size += grub_relocator_forward_size; + + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + + chunk->target = target; + chunk->size = size; + chunk->next = rel->chunks; + rel->chunks = chunk; + grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks, + rel->chunks->next); + + chunk->srcv = grub_map_memory (chunk->src, chunk->size); + *out = chunk; +#ifdef DEBUG_RELOCATOR + grub_memset (chunk->srcv, 0xfa, chunk->size); + grub_mm_check (); +#endif + return GRUB_ERR_NONE; +} + +/* Context for grub_relocator_alloc_chunk_align. */ +struct grub_relocator_alloc_chunk_align_ctx +{ + grub_phys_addr_t min_addr, max_addr; + grub_size_t size, align; + int preference; + struct grub_relocator_chunk *chunk; + int found; +}; + +/* Helper for grub_relocator_alloc_chunk_align. */ +static int +grub_relocator_alloc_chunk_align_iter (grub_uint64_t addr, grub_uint64_t sz, + grub_memory_type_t type, void *data) +{ + struct grub_relocator_alloc_chunk_align_ctx *ctx = data; + grub_uint64_t candidate; + + if (type != GRUB_MEMORY_AVAILABLE) + return 0; + candidate = ALIGN_UP (addr, ctx->align); + if (candidate < ctx->min_addr) + candidate = ALIGN_UP (ctx->min_addr, ctx->align); + if (candidate + ctx->size > addr + sz + || candidate > ALIGN_DOWN (ctx->max_addr, ctx->align)) + return 0; + if (ctx->preference == GRUB_RELOCATOR_PREFERENCE_HIGH) + candidate = ALIGN_DOWN (min (addr + sz - ctx->size, ctx->max_addr), + ctx->align); + if (!ctx->found || (ctx->preference == GRUB_RELOCATOR_PREFERENCE_HIGH + && candidate > ctx->chunk->target)) + ctx->chunk->target = candidate; + if (!ctx->found || (ctx->preference == GRUB_RELOCATOR_PREFERENCE_LOW + && candidate < ctx->chunk->target)) + ctx->chunk->target = candidate; + ctx->found = 1; + return 0; +} + +grub_err_t +grub_relocator_alloc_chunk_align (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t min_addr, + grub_phys_addr_t max_addr, + grub_size_t size, grub_size_t align, + int preference, + int avoid_efi_boot_services) +{ + struct grub_relocator_alloc_chunk_align_ctx ctx = { + .min_addr = min_addr, + .max_addr = max_addr, + .size = size, + .align = align, + .preference = preference, + .found = 0 + }; + grub_addr_t min_addr2 = 0, max_addr2; + + if (max_addr > ~size) + max_addr = ~size; + +#ifdef GRUB_MACHINE_PCBIOS + if (min_addr < 0x1000) + min_addr = 0x1000; +#endif + + grub_dprintf ("relocator", "chunks = %p\n", rel->chunks); + + ctx.chunk = grub_malloc (sizeof (struct grub_relocator_chunk)); + if (!ctx.chunk) + return grub_errno; + + if (malloc_in_range (rel, min_addr, max_addr, align, + size, ctx.chunk, + preference != GRUB_RELOCATOR_PREFERENCE_HIGH, 1)) + { + grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n", + (unsigned long long) ctx.chunk->src, + (unsigned long long) ctx.chunk->src); + grub_dprintf ("relocator", "chunks = %p\n", rel->chunks); + ctx.chunk->target = ctx.chunk->src; + ctx.chunk->size = size; + ctx.chunk->next = rel->chunks; + rel->chunks = ctx.chunk; + ctx.chunk->srcv = grub_map_memory (ctx.chunk->src, ctx.chunk->size); + *out = ctx.chunk; + return GRUB_ERR_NONE; + } + + adjust_limits (rel, &min_addr2, &max_addr2, min_addr, max_addr); + grub_dprintf ("relocator", "Adjusted limits from %lx-%lx to %lx-%lx\n", + (unsigned long) min_addr, (unsigned long) max_addr, + (unsigned long) min_addr2, (unsigned long) max_addr2); + + do + { + if (malloc_in_range (rel, min_addr2, max_addr2, align, + size, ctx.chunk, 1, 1)) + break; + + if (malloc_in_range (rel, rel->highestnonpostaddr, ~(grub_addr_t)0, 1, + size, ctx.chunk, 0, 1)) + { + if (rel->postchunks > ctx.chunk->src) + rel->postchunks = ctx.chunk->src; + break; + } + + return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + } + while (0); + + { +#ifdef GRUB_MACHINE_EFI + grub_efi_mmap_iterate (grub_relocator_alloc_chunk_align_iter, &ctx, + avoid_efi_boot_services); +#elif defined (__powerpc__) || defined (GRUB_MACHINE_XEN) + (void) avoid_efi_boot_services; + grub_machine_mmap_iterate (grub_relocator_alloc_chunk_align_iter, &ctx); +#else + (void) avoid_efi_boot_services; + grub_mmap_iterate (grub_relocator_alloc_chunk_align_iter, &ctx); +#endif + if (!ctx.found) + return grub_error (GRUB_ERR_BAD_OS, "couldn't find suitable memory target"); + } + while (1) + { + struct grub_relocator_chunk *chunk2; + for (chunk2 = rel->chunks; chunk2; chunk2 = chunk2->next) + if ((chunk2->target <= ctx.chunk->target + && ctx.chunk->target < chunk2->target + chunk2->size) + || (ctx.chunk->target <= chunk2->target && chunk2->target + < ctx.chunk->target + size)) + { + if (preference == GRUB_RELOCATOR_PREFERENCE_HIGH) + ctx.chunk->target = ALIGN_DOWN (chunk2->target, align); + else + ctx.chunk->target = ALIGN_UP (chunk2->target + chunk2->size, + align); + break; + } + if (!chunk2) + break; + } + + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + + if (ctx.chunk->src < ctx.chunk->target) + rel->relocators_size += grub_relocator_backward_size; + if (ctx.chunk->src > ctx.chunk->target) + rel->relocators_size += grub_relocator_forward_size; + + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + + ctx.chunk->size = size; + ctx.chunk->next = rel->chunks; + rel->chunks = ctx.chunk; + grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks, + rel->chunks->next); + ctx.chunk->srcv = grub_map_memory (ctx.chunk->src, ctx.chunk->size); + *out = ctx.chunk; +#ifdef DEBUG_RELOCATOR + grub_memset (ctx.chunk->srcv, 0xfa, ctx.chunk->size); + grub_mm_check (); +#endif + return GRUB_ERR_NONE; +} + +void +grub_relocator_unload (struct grub_relocator *rel) +{ + struct grub_relocator_chunk *chunk, *next; + if (!rel) + return; + for (chunk = rel->chunks; chunk; chunk = next) + { + unsigned i; + for (i = 0; i < chunk->nsubchunks; i++) + free_subchunk (&chunk->subchunks[i]); + grub_unmap_memory (chunk->srcv, chunk->size); + next = chunk->next; + grub_free (chunk->subchunks); + grub_free (chunk); + } + grub_free (rel); +} + +grub_err_t +grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr, + void **relstart, grub_size_t *relsize) +{ + grub_uint8_t *rels; + grub_uint8_t *rels0; + struct grub_relocator_chunk *sorted; + grub_size_t nchunks = 0; + unsigned j; + struct grub_relocator_chunk movers_chunk; + + grub_dprintf ("relocator", "Preparing relocs (size=%ld)\n", + (unsigned long) rel->relocators_size); + + if (!malloc_in_range (rel, 0, ~(grub_addr_t)0 - rel->relocators_size + 1, + grub_relocator_align, + rel->relocators_size, &movers_chunk, 1, 1)) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + movers_chunk.srcv = rels = rels0 + = grub_map_memory (movers_chunk.src, movers_chunk.size); + + if (relsize) + *relsize = rel->relocators_size; + + grub_dprintf ("relocator", "Relocs allocated at %p\n", movers_chunk.srcv); + + { + unsigned i; + grub_size_t count[257]; + struct grub_relocator_chunk *from, *to, *tmp; + + grub_memset (count, 0, sizeof (count)); + + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + { + grub_dprintf ("relocator", "chunk %p->%p, 0x%lx\n", + (void *) chunk->src, (void *) chunk->target, + (unsigned long) chunk->size); + nchunks++; + count[(chunk->src & 0xff) + 1]++; + } + } + from = grub_malloc (nchunks * sizeof (sorted[0])); + to = grub_malloc (nchunks * sizeof (sorted[0])); + if (!from || !to) + { + grub_free (from); + grub_free (to); + return grub_errno; + } + + for (j = 0; j < 256; j++) + count[j+1] += count[j]; + + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + from[count[chunk->src & 0xff]++] = *chunk; + } + + for (i = 1; i < GRUB_CPU_SIZEOF_VOID_P; i++) + { + grub_memset (count, 0, sizeof (count)); + for (j = 0; j < nchunks; j++) + count[((from[j].src >> (8 * i)) & 0xff) + 1]++; + for (j = 0; j < 256; j++) + count[j+1] += count[j]; + for (j = 0; j < nchunks; j++) + to[count[(from[j].src >> (8 * i)) & 0xff]++] = from[j]; + tmp = to; + to = from; + from = tmp; + } + sorted = from; + grub_free (to); + } + + for (j = 0; j < nchunks; j++) + { + grub_dprintf ("relocator", "sorted chunk %p->%p, 0x%lx\n", + (void *) sorted[j].src, (void *) sorted[j].target, + (unsigned long) sorted[j].size); + if (sorted[j].src < sorted[j].target) + { + grub_cpu_relocator_backward ((void *) rels, + sorted[j].srcv, + grub_map_memory (sorted[j].target, + sorted[j].size), + sorted[j].size); + rels += grub_relocator_backward_size; + } + if (sorted[j].src > sorted[j].target) + { + grub_cpu_relocator_forward ((void *) rels, + sorted[j].srcv, + grub_map_memory (sorted[j].target, + sorted[j].size), + sorted[j].size); + rels += grub_relocator_forward_size; + } + if (sorted[j].src == sorted[j].target) + grub_arch_sync_caches (sorted[j].srcv, sorted[j].size); + } + grub_cpu_relocator_jumper ((void *) rels, (grub_addr_t) addr); + *relstart = rels0; + grub_free (sorted); + return GRUB_ERR_NONE; +} + +void +grub_mm_check_real (const char *file, int line) +{ + grub_mm_region_t r; + grub_mm_header_t p, pa; + + for (r = grub_mm_base; r; r = r->next) + { + pa = r->first; + p = pa->next; + if (p->magic == GRUB_MM_ALLOC_MAGIC) + continue; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal ("%s:%d: out of range pointer: %p\n", file, line, p); + if (p->magic != GRUB_MM_FREE_MAGIC) + grub_fatal ("%s:%d free magic broken at %p (0x%x)\n", file, + line, p, p->magic); + pa = p; + p = pa->next; + } + while (pa != r->first); + } +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/setjmp.S b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/setjmp.S new file mode 100644 index 0000000..5059d92 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/setjmp.S @@ -0,0 +1,26 @@ +#if defined(__i386__) +#include "./i386/setjmp.S" +#elif defined(__x86_64__) +#include "./x86_64/setjmp.S" +#elif defined(__sparc__) +#include "./sparc64/setjmp.S" +#elif defined(__mips__) +#if _MIPS_SIM == _ABI64 +#include "./mips64/setjmp.S" +#else +#include "./mips/setjmp.S" +#endif +#elif defined(__powerpc__) || defined(__PPC__) +#include "./powerpc/setjmp.S" +#elif defined(__ia64__) +#include "./ia64/setjmp.S" +#include "./ia64/longjmp.S" +#elif defined(__arm__) +#include "./arm/setjmp.S" +#elif defined(__aarch64__) +#include "./arm64/setjmp.S" +#elif defined(__riscv) +#include "./riscv/setjmp.S" +#else +#error "Unknown target cpu type" +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/syslinux_parse.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/syslinux_parse.c new file mode 100644 index 0000000..1109614 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/syslinux_parse.c @@ -0,0 +1,1570 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include + +struct syslinux_say +{ + struct syslinux_say *next; + struct syslinux_say *prev; + char msg[0]; +}; + +struct initrd_list +{ + struct initrd_list *next; + char *file; +}; + +struct syslinux_menuentry +{ + struct syslinux_menuentry *next; + struct syslinux_menuentry *prev; + char *label; + char *extlabel; + char *kernel_file; + struct initrd_list *initrds; + struct initrd_list *initrds_last; + char *append; + char *argument; + char *help; + char *comments; + grub_size_t commentslen; + char hotkey; + int make_default; + struct syslinux_say *say; + + enum { KERNEL_NO_KERNEL, KERNEL_LINUX, KERNEL_CHAINLOADER, + KERNEL_BIN, KERNEL_PXE, KERNEL_CHAINLOADER_BPB, + KERNEL_COM32, KERNEL_COM, KERNEL_IMG, KERNEL_CONFIG, LOCALBOOT } + entry_type; +}; + +struct syslinux_menu +{ + struct syslinux_menu *parent; + struct syslinux_menuentry *entries; + char *def; + char *comments; + char *background; + const char *root_read_directory; + const char *root_target_directory; + const char *current_read_directory; + const char *current_target_directory; + const char *filename; + grub_size_t commentslen; + unsigned long timeout; + struct syslinux_say *say; + grub_syslinux_flavour_t flavour; +}; + +struct output_buffer +{ + grub_size_t alloc; + grub_size_t ptr; + char *buf; +}; + +static grub_err_t +syslinux_parse_real (struct syslinux_menu *menu); +static grub_err_t +config_file (struct output_buffer *outbuf, + const char *root, const char *target_root, + const char *cwd, const char *target_cwd, + const char *fname, struct syslinux_menu *parent, + grub_syslinux_flavour_t flav); +static grub_err_t +print_entry (struct output_buffer *outbuf, + struct syslinux_menu *menu, + const char *str); + +static grub_err_t +ensure_space (struct output_buffer *outbuf, grub_size_t len) +{ + grub_size_t newlen; + char *newbuf; + if (len < outbuf->alloc - outbuf->ptr) + return GRUB_ERR_NONE; + newlen = (outbuf->ptr + len + 10) * 2; + newbuf = grub_realloc (outbuf->buf, newlen); + if (!newbuf) + return grub_errno; + outbuf->alloc = newlen; + outbuf->buf = newbuf; + return GRUB_ERR_NONE; +} + +static grub_err_t +print (struct output_buffer *outbuf, const char *str, grub_size_t len) +{ + grub_err_t err; + err = ensure_space (outbuf, len); + if (err) + return err; + grub_memcpy (&outbuf->buf[outbuf->ptr], str, len); + outbuf->ptr += len; + return GRUB_ERR_NONE; +} + +static grub_err_t +add_comment (struct syslinux_menu *menu, const char *comment, int nl) +{ + if (menu->entries) + { + if (menu->entries->commentslen == 0 && *comment == 0) + return GRUB_ERR_NONE; + menu->entries->comments = grub_realloc (menu->entries->comments, + menu->entries->commentslen + + 2 + grub_strlen (comment)); + if (!menu->entries->comments) + return grub_errno; + menu->entries->commentslen + += grub_stpcpy (menu->entries->comments + menu->entries->commentslen, + comment) + - (menu->entries->comments + menu->entries->commentslen); + if (nl) + menu->entries->comments[menu->entries->commentslen++] = '\n'; + menu->entries->comments[menu->entries->commentslen] = '\0'; + } + else + { + if (menu->commentslen == 0 && *comment == 0) + return GRUB_ERR_NONE; + menu->comments = grub_realloc (menu->comments, menu->commentslen + + 2 + grub_strlen (comment)); + if (!menu->comments) + return grub_errno; + menu->commentslen += grub_stpcpy (menu->comments + menu->commentslen, + comment) + - (menu->comments + menu->commentslen); + if (nl) + menu->comments[menu->commentslen++] = '\n'; + menu->comments[menu->commentslen] = '\0'; + } + return GRUB_ERR_NONE; +} + + +#define print_string(x) do { err = print (outbuf, x, sizeof (x) - 1); if (err) return err; } while (0) + +static grub_err_t +print_num (struct output_buffer *outbuf, int n) +{ + char buf[20]; + grub_snprintf (buf, sizeof (buf), "%d", n); + return print (outbuf, buf, grub_strlen (buf)); +} + +static grub_err_t +label (const char *line, struct syslinux_menu *menu) +{ + struct syslinux_menuentry *entry; + + entry = grub_malloc (sizeof (*entry)); + if (!entry) + return grub_errno; + grub_memset (entry, 0, sizeof (*entry)); + entry->label = grub_strdup (line); + if (!entry->label) + { + grub_free (entry); + return grub_errno; + } + entry->next = menu->entries; + entry->prev = NULL; + if (menu->entries) + menu->entries->prev = entry; + menu->entries = entry; + return GRUB_ERR_NONE; +} + +static grub_err_t +kernel (const char *line, struct syslinux_menu *menu) +{ + const char *end = line + grub_strlen (line); + + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->kernel_file = grub_strdup (line); + if (!menu->entries->kernel_file) + return grub_errno; + + menu->entries->entry_type = KERNEL_LINUX; + + if (end - line >= 2 && grub_strcmp (end - 2, ".0") == 0) + menu->entries->entry_type = KERNEL_PXE; + + if (end - line >= 4 && grub_strcasecmp (end - 4, ".bin") == 0) + menu->entries->entry_type = KERNEL_BIN; + + if (end - line >= 3 && grub_strcasecmp (end - 3, ".bs") == 0) + menu->entries->entry_type = KERNEL_CHAINLOADER; + + if (end - line >= 4 && grub_strcasecmp (end - 4, ".bss") == 0) + menu->entries->entry_type = KERNEL_CHAINLOADER_BPB; + + if (end - line >= 4 && grub_strcasecmp (end - 4, ".c32") == 0) + menu->entries->entry_type = KERNEL_COM32; + + if (end - line >= 4 && grub_strcasecmp (end - 4, ".cbt") == 0) + menu->entries->entry_type = KERNEL_COM; + + if (end - line >= 4 && grub_strcasecmp (end - 4, ".com") == 0) + menu->entries->entry_type = KERNEL_COM; + + if (end - line >= 4 && grub_strcasecmp (end - 4, ".img") == 0) + menu->entries->entry_type = KERNEL_IMG; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_linux (const char *line, struct syslinux_menu *menu) +{ + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->kernel_file = grub_strdup (line); + if (!menu->entries->kernel_file) + return grub_errno; + menu->entries->entry_type = KERNEL_LINUX; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_boot (const char *line, struct syslinux_menu *menu) +{ + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->kernel_file = grub_strdup (line); + if (!menu->entries->kernel_file) + return grub_errno; + menu->entries->entry_type = KERNEL_CHAINLOADER; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_bss (const char *line, struct syslinux_menu *menu) +{ + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->kernel_file = grub_strdup (line); + if (!menu->entries->kernel_file) + return grub_errno; + menu->entries->entry_type = KERNEL_CHAINLOADER_BPB; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_pxe (const char *line, struct syslinux_menu *menu) +{ + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->kernel_file = grub_strdup (line); + if (!menu->entries->kernel_file) + return grub_errno; + menu->entries->entry_type = KERNEL_PXE; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_fdimage (const char *line, struct syslinux_menu *menu) +{ + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->kernel_file = grub_strdup (line); + if (!menu->entries->kernel_file) + return grub_errno; + menu->entries->entry_type = KERNEL_IMG; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_comboot (const char *line, struct syslinux_menu *menu) +{ + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->kernel_file = grub_strdup (line); + if (!menu->entries->kernel_file) + return grub_errno; + menu->entries->entry_type = KERNEL_COM; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_com32 (const char *line, struct syslinux_menu *menu) +{ + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->kernel_file = grub_strdup (line); + if (!menu->entries->kernel_file) + return grub_errno; + menu->entries->entry_type = KERNEL_COM32; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_config (const char *line, struct syslinux_menu *menu) +{ + const char *space; + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + for (space = line; *space && !grub_isspace (*space); space++); + menu->entries->kernel_file = grub_strndup (line, space - line); + if (!menu->entries->kernel_file) + return grub_errno; + for (; *space && grub_isspace (*space); space++); + if (*space) + { + menu->entries->argument = grub_strdup (space); + if (!menu->entries->argument) + return grub_errno; + } + menu->entries->entry_type = KERNEL_CONFIG; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_append (const char *line, struct syslinux_menu *menu) +{ + if (!menu->entries) + return GRUB_ERR_NONE; + //return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->append = grub_strdup (line); + if (!menu->entries->append) + return grub_errno; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_initrd (const char *line, struct syslinux_menu *menu) +{ + struct initrd_list *ninitrd; + const char *comma; + char *pcPos; + + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + while (*line) + { + for (comma = line; *comma && *comma != ','; comma++); + + ninitrd = grub_malloc (sizeof (*ninitrd)); + if (!ninitrd) + return grub_errno; + ninitrd->file = grub_strndup (line, comma - line); + if (!ninitrd->file) + { + grub_free (ninitrd); + return grub_errno; + } + + pcPos = grub_strstr(ninitrd->file, " quiet"); + if (pcPos) + { + *pcPos = 0; + } + + + ninitrd->next = NULL; + if (menu->entries->initrds_last) + menu->entries->initrds_last->next = ninitrd; + else + { + menu->entries->initrds_last = ninitrd; + menu->entries->initrds = ninitrd; + } + + line = comma; + while (*line == ',') + line++; + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_default (const char *line, struct syslinux_menu *menu) +{ + menu->def = grub_strdup (line); + if (!menu->def) + return grub_errno; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_timeout (const char *line, struct syslinux_menu *menu) +{ + menu->timeout = grub_strtoul (line, NULL, 0); + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_menudefault (const char *line __attribute__ ((unused)), + struct syslinux_menu *menu) +{ + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->make_default = 1; + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_menubackground (const char *line, + struct syslinux_menu *menu) +{ + menu->background = grub_strdup (line); + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_localboot (const char *line, + struct syslinux_menu *menu) +{ + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->kernel_file = grub_strdup (line); + if (!menu->entries->kernel_file) + return grub_errno; + menu->entries->entry_type = LOCALBOOT; + + return GRUB_ERR_NONE; +} + +static grub_err_t +cmd_extlabel (const char *line, struct syslinux_menu *menu) +{ + const char *in; + char *out; + + if (!menu->entries) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "kernel without label"); + + menu->entries->extlabel = grub_malloc (grub_strlen (line) + 1); + if (!menu->entries->extlabel) + return grub_errno; + in = line; + out = menu->entries->extlabel; + while (*in) + { + if (in[0] == '^' && in[1]) + { + menu->entries->hotkey = grub_tolower (in[1]); + in++; + } + *out++ = *in++; + } + *out = 0; + + return GRUB_ERR_NONE; +} + + +static grub_err_t +cmd_say (const char *line, struct syslinux_menu *menu) +{ + struct syslinux_say *nsay; + nsay = grub_malloc (sizeof (*nsay) + grub_strlen (line) + 1); + if (!nsay) + return grub_errno; + nsay->prev = NULL; + if (menu->entries) + { + nsay->next = menu->entries->say; + menu->entries->say = nsay; + } + else + { + nsay->next = menu->say; + menu->say = nsay; + } + + if (nsay->next) + nsay->next->prev = nsay; + + grub_memcpy (nsay->msg, line, grub_strlen (line) + 1); + return GRUB_ERR_NONE; +} + +static char * +get_read_filename (struct syslinux_menu *menu, + const char *filename) +{ + return grub_xasprintf ("%s/%s", + filename[0] == '/' ? menu->root_read_directory + : menu->current_read_directory, filename); +} + +static char * +get_target_filename (struct syslinux_menu *menu, + const char *filename) +{ + return grub_xasprintf ("%s/%s", + filename[0] == '/' ? menu->root_target_directory + : menu->current_target_directory, filename); +} + +static grub_err_t +syslinux_parse (const char *filename, + struct syslinux_menu *menu) +{ + const char *old_filename = menu->filename; + grub_err_t ret; + char *nf; + nf = get_read_filename (menu, filename); + if (!nf) + return grub_errno; + menu->filename = nf; + ret = syslinux_parse_real (menu); + if (ret == GRUB_ERR_FILE_NOT_FOUND + || ret == GRUB_ERR_BAD_FILENAME) + { + grub_errno = ret = GRUB_ERR_NONE; + add_comment (menu, "# File ", 0); + add_comment (menu, nf, 0); + add_comment (menu, " not found", 1); + } + grub_free (nf); + menu->filename = old_filename; + return ret; +} + +struct +{ + const char *name1; + const char *name2; + grub_err_t (*parse) (const char *line, struct syslinux_menu *menu); +} commands[] = { + /* FIXME: support tagname. */ + {"include", NULL, syslinux_parse}, + {"menu", "include", syslinux_parse}, + {"label", NULL, label}, + {"kernel", NULL, kernel}, + {"linux", NULL, cmd_linux}, + {"boot", NULL, cmd_boot}, + {"bss", NULL, cmd_bss}, + {"pxe", NULL, cmd_pxe}, + {"fdimage", NULL, cmd_fdimage}, + {"comboot", NULL, cmd_comboot}, + {"com32", NULL, cmd_com32}, + {"config", NULL, cmd_config}, + {"append", NULL, cmd_append}, + /* FIXME: ipappend not supported. */ + {"localboot", NULL, cmd_localboot}, + {"initrd", NULL, cmd_initrd}, + {"default", NULL, cmd_default}, + {"menu", "label", cmd_extlabel}, + /* FIXME: MENU LABEL not supported. */ + /* FIXME: MENU HIDDEN not supported. */ + /* FIXME: MENU SEPARATOR not supported. */ + /* FIXME: MENU INDENT not supported. */ + /* FIXME: MENU DISABLE not supported. */ + /* FIXME: MENU HIDE not supported. */ + {"menu", "default", cmd_menudefault}, + /* FIXME: MENU PASSWD not supported. */ + /* FIXME: MENU MASTER PASSWD not supported. */ + {"menu", "background", cmd_menubackground}, + /* FIXME: MENU BEGIN not supported. */ + /* FIXME: MENU GOTO not supported. */ + /* FIXME: MENU EXIT not supported. */ + /* FIXME: MENU QUIT not supported. */ + /* FIXME: MENU START not supported. */ + /* FIXME: MENU AUTOBOOT not supported. */ + /* FIXME: MENU TABMSG not supported. */ + /* FIXME: MENU NOTABMSG not supported. */ + /* FIXME: MENU PASSPROMPT not supported. */ + /* FIXME: MENU COLOR not supported. */ + /* FIXME: MENU MSGCOLOR not supported. */ + /* FIXME: MENU WIDTH not supported. */ + /* FIXME: MENU MARGIN not supported. */ + /* FIXME: MENU PASSWORDMARGIN not supported. */ + /* FIXME: MENU ROWS not supported. */ + /* FIXME: MENU TABMSGROW not supported. */ + /* FIXME: MENU CMDLINEROW not supported. */ + /* FIXME: MENU ENDROW not supported. */ + /* FIXME: MENU PASSWORDROW not supported. */ + /* FIXME: MENU TIMEOUTROW not supported. */ + /* FIXME: MENU HELPMSGROW not supported. */ + /* FIXME: MENU HELPMSGENDROW not supported. */ + /* FIXME: MENU HIDDENROW not supported. */ + /* FIXME: MENU HSHIFT not supported. */ + /* FIXME: MENU VSHIFT not supported. */ + {"timeout", NULL, cmd_timeout}, + /* FIXME: TOTALTIMEOUT not supported. */ + /* FIXME: ONTIMEOUT not supported. */ + /* FIXME: ONERROR not supported. */ + /* FIXME: SERIAL not supported. */ + /* FIXME: CONSOLE not supported. */ + /* FIXME: FONT not supported. */ + /* FIXME: KBDMAP not supported. */ + {"say", NULL, cmd_say}, + /* FIXME: DISPLAY not supported. */ + /* FIXME: F* not supported. */ + + /* Commands to control interface behaviour which aren't needed with GRUB. + If they are important in your environment please contact GRUB team. + */ + {"prompt", NULL, NULL}, + {"nocomplete", NULL, NULL}, + {"noescape", NULL, NULL}, + {"implicit", NULL, NULL}, + {"allowoptions", NULL, NULL} +}; + +static grub_err_t +helptext (const char *line, grub_file_t file, struct syslinux_menu *menu) +{ + char *help; + char *buf = NULL; + grub_size_t helplen, alloclen = 0; + + help = grub_strdup (line); + if (!help) + return grub_errno; + helplen = grub_strlen (line); + while ((grub_free (buf), buf = grub_file_getline (file))) + { + char *ptr; + grub_size_t needlen; + for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++); + if (grub_strncasecmp (ptr, "endtext", sizeof ("endtext") - 1) == 0) + { + ptr += sizeof ("endtext") - 1; + for (; *ptr && (grub_isspace (*ptr) || *ptr == '\n' || *ptr == '\r'); + ptr++); + if (!*ptr) + { + menu->entries->help = help; + grub_free (buf); + return GRUB_ERR_NONE; + } + } + needlen = helplen + 1 + grub_strlen (buf); + if (alloclen < needlen) + { + alloclen = 2 * needlen; + help = grub_realloc (help, alloclen); + if (!help) + { + grub_free (buf); + return grub_errno; + } + } + helplen += grub_stpcpy (help + helplen, buf) - (help + helplen); + } + + grub_free (buf); + grub_free (help); + return grub_errno; +} + + +static grub_err_t +syslinux_parse_real (struct syslinux_menu *menu) +{ + grub_file_t file; + char *buf = NULL; + grub_err_t err = GRUB_ERR_NONE; + + file = grub_file_open (menu->filename, GRUB_FILE_TYPE_CONFIG); + if (!file) + return grub_errno; + while ((grub_free (buf), buf = grub_file_getline (file))) + { + const char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5; + char *end; + unsigned i; + end = buf + grub_strlen (buf); + while (end > buf && (end[-1] == '\n' || end[-1] == '\r')) + end--; + *end = 0; + for (ptr1 = buf; *ptr1 && grub_isspace (*ptr1); ptr1++); + if (*ptr1 == '#' || *ptr1 == 0) + { + err = add_comment (menu, ptr1, 1); + if (err) + goto fail; + continue; + } + for (ptr2 = ptr1; !grub_isspace (*ptr2) && *ptr2; ptr2++); + for (ptr3 = ptr2; grub_isspace (*ptr3) && *ptr3; ptr3++); + for (ptr4 = ptr3; !grub_isspace (*ptr4) && *ptr4; ptr4++); + for (ptr5 = ptr4; grub_isspace (*ptr5) && *ptr5; ptr5++); + for (i = 0; i < ARRAY_SIZE(commands); i++) + if (grub_strlen (commands[i].name1) == (grub_size_t) (ptr2 - ptr1) + && grub_strncasecmp (commands[i].name1, ptr1, ptr2 - ptr1) == 0 + && (commands[i].name2 == NULL + || (grub_strlen (commands[i].name2) + == (grub_size_t) (ptr4 - ptr3) + && grub_strncasecmp (commands[i].name2, ptr3, ptr4 - ptr3) + == 0))) + break; + if (i == ARRAY_SIZE(commands)) + { + if (sizeof ("text") - 1 == ptr2 - ptr1 + && grub_strncasecmp ("text", ptr1, ptr2 - ptr1) == 0 + && (sizeof ("help") - 1 == ptr4 - ptr3 + && grub_strncasecmp ("help", ptr3, ptr4 - ptr3) == 0)) + { + if (helptext (ptr5, file, menu)) + return 1; + continue; + } + + add_comment (menu, " # UNSUPPORTED command '", 0); + add_comment (menu, ptr1, 0); + add_comment (menu, "'", 1); + + continue; + } + if (commands[i].parse) + { + err = commands[i].parse (commands[i].name2 + ? ptr5 : ptr3, menu); + if (err) + goto fail; + } + } + fail: + grub_file_close (file); + return err; +} + +static grub_err_t +print_escaped (struct output_buffer *outbuf, + const char *from, const char *to) +{ + const char *ptr; + grub_err_t err; + if (!to) + to = from + grub_strlen (from); + err = ensure_space (outbuf, (to - from) * 4 + 2); + if (err) + return err; + outbuf->buf[outbuf->ptr++] = '\''; + for (ptr = from; *ptr && ptr < to; ptr++) + { + if (*ptr == '\'') + { + outbuf->buf[outbuf->ptr++] = '\''; + outbuf->buf[outbuf->ptr++] = '\\'; + outbuf->buf[outbuf->ptr++] = '\''; + outbuf->buf[outbuf->ptr++] = '\''; + } + else + outbuf->buf[outbuf->ptr++] = *ptr; + } + outbuf->buf[outbuf->ptr++] = '\''; + return GRUB_ERR_NONE; +} + +static grub_err_t +print_file (struct output_buffer *outbuf, + struct syslinux_menu *menu, const char *from, const char *to) +{ + grub_err_t err; + if (!to) + to = from + grub_strlen (from); + err = print_escaped (outbuf, from[0] == '/' + ? menu->root_target_directory + : menu->current_target_directory, NULL); + if (err) + return err; + + err = print (outbuf, "/", 1); + if (err) + return err; + return print_escaped (outbuf, from, to); +} + +/* + * Makefile.am mimics this when generating tests/syslinux/ubuntu10.04_grub.cfg, + * so changes here may need to be reflected there too. + */ +static void +simplify_filename (char *str) +{ + char *iptr, *optr = str; + for (iptr = str; *iptr; iptr++) + { + if (*iptr == '/' && optr != str && optr[-1] == '/') + continue; + if (iptr[0] == '/' && iptr[1] == '.' && iptr[2] == '/') + { + iptr += 2; + continue; + } + if (iptr[0] == '/' && iptr[1] == '.' && iptr[2] == '.' + && iptr[3] == '/') + { + iptr += 3; + while (optr >= str && *optr != '/') + optr--; + if (optr < str) + { + str[0] = '/'; + optr = str; + } + optr++; + continue; + } + *optr++ = *iptr; + } + *optr = '\0'; +} + +static grub_err_t +print_config (struct output_buffer *outbuf, + struct syslinux_menu *menu, + const char *filename, const char *basedir) +{ + struct syslinux_menu *menuptr; + grub_err_t err = GRUB_ERR_NONE; + char *new_cwd = NULL; + char *new_target_cwd = NULL; + char *newname = NULL; + int depth = 0; + + new_cwd = get_read_filename (menu, basedir); + if (!new_cwd) + { + err = grub_errno; + goto out; + } + new_target_cwd = get_target_filename (menu, basedir); + if (!new_target_cwd) + { + err = grub_errno; + goto out; + } + newname = get_read_filename (menu, filename); + if (!newname) + { + err = grub_errno; + goto out; + } + simplify_filename (newname); + + print_string ("#"); + print_file (outbuf, menu, filename, NULL); + print_string (" "); + err = print (outbuf, newname, grub_strlen (newname)); + if (err) + return err; + print_string (":\n"); + + for (menuptr = menu; menuptr; menuptr = menuptr->parent, depth++) + if (grub_strcmp (menuptr->filename, newname) == 0 + || depth > 20) + break; + if (menuptr) + { + print_string (" syslinux_configfile -r "); + print_file (outbuf, menu, "/", NULL); + print_string (" -c "); + print_file (outbuf, menu, basedir, NULL); + print_string (" "); + print_file (outbuf, menu, filename, NULL); + print_string ("\n"); + } + else + { + err = config_file (outbuf, menu->root_read_directory, + menu->root_target_directory, new_cwd, new_target_cwd, + newname, menu, menu->flavour); + if (err == GRUB_ERR_FILE_NOT_FOUND + || err == GRUB_ERR_BAD_FILENAME) + { + grub_errno = err = GRUB_ERR_NONE; + print_string ("# File "); + err = print (outbuf, newname, grub_strlen (newname)); + if (err) + goto out; + print_string (" not found\n"); + } + } + + out: + grub_free (newname); + grub_free (new_cwd); + grub_free (new_target_cwd); + return err; +} + +static grub_err_t +write_entry (struct output_buffer *outbuf, + struct syslinux_menu *menu, + struct syslinux_menuentry *curentry) +{ + grub_err_t err; + if (curentry->comments) + { + err = print (outbuf, curentry->comments, + grub_strlen (curentry->comments)); + if (err) + return err; + } + { + struct syslinux_say *say; + for (say = curentry->say; say && say->next; say = say->next); + for (; say && say->prev; say = say->prev) + { + print_string ("echo "); + if (print_escaped (outbuf, say->msg, NULL)) return grub_errno; + print_string ("\n"); + } + } + + /* FIXME: support help text. */ + switch (curentry->entry_type) + { + case KERNEL_LINUX: + { + const char *ptr; + const char *initrd = NULL, *initrde= NULL; + for (ptr = curentry->append; ptr && *ptr; ptr++) + if ((ptr == curentry->append || grub_isspace (ptr[-1])) + && grub_strncasecmp (ptr, "initrd=", sizeof ("initrd=") - 1) + == 0) + break; + if (ptr && *ptr) + { + initrd = ptr + sizeof ("initrd=") - 1; + for (initrde = initrd; *initrde && !grub_isspace (*initrde); initrde++); + } + print_string (" if test x$ventoy_linux_16 = x1; then " + "linux_suffix=16; else linux_suffix= ; fi\n"); + print_string (" linux$linux_suffix "); + print_file (outbuf, menu, curentry->kernel_file, NULL); + print_string (" "); + if (curentry->append) + { + err = print (outbuf, curentry->append, grub_strlen (curentry->append)); + if (err) + return err; + } + print_string ("\n"); + if (initrd || curentry->initrds) + { + struct initrd_list *lst; + print_string (" initrd$linux_suffix "); + if (initrd) + { + print_file (outbuf, menu, initrd, initrde); + print_string (" "); + } + for (lst = curentry->initrds; lst; lst = lst->next) + { + print_file (outbuf, menu, lst->file, NULL); + print_string (" "); + } + + print_string ("\n"); + } + print_string ("boot\n"); + } + break; + case KERNEL_CHAINLOADER: + print_string (" chainloader "); + print_file (outbuf, menu, curentry->kernel_file, NULL); + print_string ("\n"); + break; + case KERNEL_CHAINLOADER_BPB: + print_string (" chainloader --bpb "); + print_file (outbuf, menu, curentry->kernel_file, NULL); + print_string ("\n"); + break; + case LOCALBOOT: + /* FIXME: support -1. */ + /* FIXME: PXELINUX. */ + { + int n = grub_strtol (curentry->kernel_file, NULL, 0); + if (n >= 0 && n <= 0x02) + { + print_string (" root=fd"); + if (print_num (outbuf, n)) + return grub_errno; + print_string (";\n chainloader +1;\n"); + + break; + } + if (n >= 0x80 && n < 0x8a) + { + print_string (" root=hd"); + if (print_num (outbuf, n - 0x80)) + return grub_errno; + print_string (";\n chainloader +1;\n"); + break; + } + print_string (" # UNSUPPORTED localboot type "); + print_string ("\ntrue;\n"); + if (print_num (outbuf, n)) + return grub_errno; + print_string ("\n"); + break; + } + case KERNEL_COM32: + case KERNEL_COM: + { + char *basename = NULL; + + { + char *ptr; + for (ptr = curentry->kernel_file; *ptr; ptr++) + if (*ptr == '/' || *ptr == '\\') + basename = ptr; + } + if (!basename) + basename = curentry->kernel_file; + else + basename++; + if (grub_strcasecmp (basename, "chain.c32") == 0) + { + char *file = NULL; + int is_fd = -1, devn = 0; + int part = -1; + int swap = 0; + char *ptr; + for (ptr = curentry->append; *ptr; ) + { + while (grub_isspace (*ptr)) + ptr++; + /* FIXME: support mbr: and boot. */ + if (ptr[0] == 'h' && ptr[1] == 'd') + { + is_fd = 0; + devn = grub_strtoul (ptr + 2, &ptr, 0); + continue; + } + if (grub_strncasecmp (ptr, "file=", 5) == 0) + { + file = ptr + 5; + for (ptr = file; *ptr && !grub_isspace (*ptr); ptr++); + if (*ptr) + { + *ptr = 0; + ptr++; + } + continue; + } + if (grub_strncasecmp (ptr, "swap", sizeof ("swap") - 1) == 0) + { + swap = 1; + ptr += sizeof ("swap") - 1; + continue; + } + + if (ptr[0] == 'f' && ptr[1] == 'd') + { + is_fd = 1; + devn = grub_strtoul (ptr + 2, &ptr, 0); + continue; + } + if (grub_isdigit (ptr[0])) + { + part = grub_strtoul (ptr, &ptr, 0); + continue; + } + /* FIXME: isolinux, ntldr, cmldr, *dos, seg, hide + FIXME: sethidden. */ + print_string (" # UNSUPPORTED option "); + if (print (outbuf, ptr, grub_strlen (ptr))) + return 0; + print_string ("\n"); + break; + } + if (is_fd == -1) + { + print_string (" # no drive specified\n"); + break; + } + if (!*ptr) + { + print_string (is_fd ? " root=fd": " root=hd"); + if (print_num (outbuf, devn)) + return grub_errno; + if (part != -1) + { + print_string (","); + if (print_num (outbuf, part + 1)) + return grub_errno; + } + print_string (";\n"); + if (file) + { + print_string (" chainloader "); + print_file (outbuf, menu, file, NULL); + print_string (";\n"); + } + else + print_string (" chainloader +1;\n"); + if (swap) + print_string (" drivemap -s hd0 \"root\";\n"); + } + break; + } + + if (grub_strcasecmp (basename, "mboot.c32") == 0) + { + char *ptr; + int first = 1; + int is_kernel = 1; + for (ptr = curentry->append; *ptr; ) + { + char *ptrr = ptr; + while (*ptr && !grub_isspace (*ptr)) + ptr++; + if (ptrr + 2 == ptr && ptrr[0] == '-' && ptrr[1] == '-') + { + print_string ("\n"); + first = 1; + continue; + } + if (first) + { + if (is_kernel) + print_string (" multiboot "); + else + print_string (" module "); + first = 0; + is_kernel = 0; + if (print_file (outbuf, menu, ptrr, ptr)) + return grub_errno; + continue; + } + if (print_escaped (outbuf, ptrr, ptr)) + return grub_errno; + } + break; + } + + if (grub_strcasecmp (basename, "ifcpu64.c32") == 0) + { + char *lm, *lme, *pae = 0, *paee = 0, *i386s = 0, *i386e = 0; + char *ptr; + ptr = curentry->append; + while (grub_isspace (*ptr)) + ptr++; + lm = ptr; + while (*ptr && !grub_isspace (*ptr)) + ptr++; + lme = ptr; + while (grub_isspace (*ptr)) + ptr++; + if (ptr[0] == '-' && ptr[1] == '-') + { + ptr += 2; + while (grub_isspace (*ptr)) + ptr++; + pae = ptr; + while (*ptr && !grub_isspace (*ptr)) + ptr++; + paee = ptr; + } + while (grub_isspace (*ptr)) + ptr++; + if (ptr[0] == '-' && ptr[1] == '-') + { + ptr += 2; + while (grub_isspace (*ptr)) + ptr++; + i386s = ptr; + while (*ptr && !grub_isspace (*ptr)) + ptr++; + i386e = ptr; + } + *lme = '\0'; + if (paee) + *paee = '\0'; + if (i386e) + *i386e = '\0'; + if (!i386s) + { + i386s = pae; + pae = 0; + } + print_string ("if cpuid --long-mode; then true;\n"); + if (print_entry (outbuf, menu, lm)) + return grub_errno; + if (pae) + { + print_string ("elif cpuid --pae; then true;\n"); + if (print_entry (outbuf, menu, pae)) + return grub_errno; + } + print_string ("else\n"); + if (print_entry (outbuf, menu, i386s)) + return grub_errno; + print_string ("fi\n"); + break; + } + + if (grub_strcasecmp (basename, "reboot.c32") == 0) + { + print_string (" reboot\n"); + break; + } + + if (grub_strcasecmp (basename, "poweroff.com") == 0) + { + print_string (" halt\n"); + break; + } + + if (grub_strcasecmp (basename, "whichsys.c32") == 0) + { + grub_syslinux_flavour_t flavour = GRUB_SYSLINUX_ISOLINUX; + const char *flav[] = + { + [GRUB_SYSLINUX_ISOLINUX] = "iso", + [GRUB_SYSLINUX_PXELINUX] = "pxe", + [GRUB_SYSLINUX_SYSLINUX] = "sys" + }; + char *ptr; + for (ptr = curentry->append; *ptr; ) + { + char *bptr, c; + while (grub_isspace (*ptr)) + ptr++; + if (grub_strncasecmp (ptr, "-iso-", 5) == 0) + { + ptr += sizeof ("-iso-") - 1; + flavour = GRUB_SYSLINUX_ISOLINUX; + continue; + } + if (grub_strncasecmp (ptr, "-pxe-", 5) == 0) + { + ptr += sizeof ("-pxe-") - 1; + flavour = GRUB_SYSLINUX_PXELINUX; + continue; + } + if (grub_strncasecmp (ptr, "-sys-", 5) == 0) + { + ptr += sizeof ("-sys-") - 1; + flavour = GRUB_SYSLINUX_SYSLINUX; + continue; + } + bptr = ptr; + while (*ptr && !grub_isspace (*ptr)) + ptr++; + c = *ptr; + *ptr = '\0'; + if (menu->flavour == GRUB_SYSLINUX_UNKNOWN + && flavour == GRUB_SYSLINUX_ISOLINUX) + { + print_string ("if [ x$syslinux_flavour = xiso -o x$syslinux_flavour = x ]; then true;\n"); + menu->flavour = GRUB_SYSLINUX_ISOLINUX; + print_entry (outbuf, menu, bptr); + menu->flavour = GRUB_SYSLINUX_UNKNOWN; + print_string ("fi\n"); + } + else if (menu->flavour == GRUB_SYSLINUX_UNKNOWN) + { + print_string ("if [ x$syslinux_flavour = x"); + err = print (outbuf, flav[flavour], grub_strlen (flav[flavour])); + if (err) + return err; + print_string (" ]; then true;\n"); + menu->flavour = flavour; + print_entry (outbuf, menu, bptr); + menu->flavour = GRUB_SYSLINUX_UNKNOWN; + print_string ("fi\n"); + } + if (menu->flavour != GRUB_SYSLINUX_UNKNOWN + && menu->flavour == flavour) + print_entry (outbuf, menu, bptr); + *ptr = c; + } + break; + } + + if (grub_strcasecmp (basename, "menu.c32") == 0 || + grub_strcasecmp (basename, "vesamenu.c32") == 0) + { + char *ptr; + char *end; + + ptr = curentry->append; + if (!ptr) + return grub_errno; + + while (*ptr) + { + end = ptr; + for (end = ptr; *end && !grub_isspace (*end); end++); + if (*end) + *end++ = '\0'; + + /* "~" is supposed to be current file, so let's skip it */ + if (grub_strcmp (ptr, "~") != 0) + { + err = print_config (outbuf, menu, ptr, ""); + if (err != GRUB_ERR_NONE) + break; + } + for (ptr = end; *ptr && grub_isspace (*ptr); ptr++); + } + err = GRUB_ERR_NONE; + break; + } + + /* FIXME: gdb, GFXBoot, Hdt, Ifcpu, Ifplop, Kbdmap, + FIXME: Linux, Lua, Meminfo, rosh, Sanbboot */ + + print_string (" # UNSUPPORTED com(32) "); + err = print (outbuf, basename, grub_strlen (basename)); + if (err) + return err; + print_string ("\ntrue;\n"); + break; + } + case KERNEL_CONFIG: + { + const char *ap; + ap = curentry->append; + if (!ap) + ap = curentry->argument; + if (!ap) + ap = ""; + print_config (outbuf, menu, curentry->kernel_file, ap); + } + break; + case KERNEL_NO_KERNEL: + /* FIXME: support this. */ + case KERNEL_BIN: + case KERNEL_PXE: + case KERNEL_IMG: + print_string (" # UNSUPPORTED entry type "); + if (print_num (outbuf, curentry->entry_type)) + return grub_errno; + print_string ("\ntrue;\n"); + break; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +print_entry (struct output_buffer *outbuf, + struct syslinux_menu *menu, + const char *str) +{ + struct syslinux_menuentry *curentry; + for (curentry = menu->entries; curentry; curentry = curentry->next) + if (grub_strcasecmp (curentry->label, str) == 0) + { + grub_err_t err; + err = write_entry (outbuf, menu, curentry); + if (err) + return err; + } + return GRUB_ERR_NONE; +} + +static void +free_menu (struct syslinux_menu *menu) +{ + struct syslinux_say *say, *nsay; + struct syslinux_menuentry *entry, *nentry; + + grub_free (menu->def); + grub_free (menu->comments); + grub_free (menu->background); + for (say = menu->say; say ; say = nsay) + { + nsay = say->next; + grub_free (say); + } + + for (entry = menu->entries; entry ; entry = nentry) + { + nentry = entry->next; + struct initrd_list *initrd, *ninitrd; + + for (initrd = entry->initrds; initrd ; initrd = ninitrd) + { + ninitrd = initrd->next; + grub_free (initrd->file); + grub_free (initrd); + } + + grub_free (entry->comments); + grub_free (entry->kernel_file); + grub_free (entry->label); + grub_free (entry->extlabel); + grub_free (entry->append); + grub_free (entry->help); + grub_free (entry); + } +} + +static grub_err_t +config_file (struct output_buffer *outbuf, + const char *root, const char *target_root, + const char *cwd, const char *target_cwd, + const char *fname, struct syslinux_menu *parent, + grub_syslinux_flavour_t flav) +{ + const char *data; + grub_err_t err; + struct syslinux_menu menu; + struct syslinux_menuentry *curentry, *lentry; + struct syslinux_say *say; + + grub_memset (&menu, 0, sizeof (menu)); + menu.flavour = flav; + menu.root_read_directory = root; + menu.root_target_directory = target_root; + menu.current_read_directory = cwd; + menu.current_target_directory = target_cwd; + + menu.filename = fname; + menu.parent = parent; + + data = grub_env_get("vtdebug_flag"); + if (data && data[0]) + { + menu.timeout = 100; + } + + err = syslinux_parse_real (&menu); + if (err) + return err; + + for (say = menu.say; say && say->next; say = say->next); + for (; say && say->prev; say = say->prev) + { + print_string ("echo "); + err = print_escaped (outbuf, say->msg, NULL); + if (err) + return err; + print_string ("\n"); + } + + if (menu.background) + { + print_string (" background_image "); + err = print_file (outbuf, &menu, menu.background, NULL); + if (err) + return err; + print_string ("\n"); + } + + if (menu.comments) + { + err = print (outbuf, menu.comments, grub_strlen (menu.comments)); + if (err) + return err; + } + + if (menu.timeout == 0 && menu.entries && menu.def) + { + err = print_entry (outbuf, &menu, menu.def); + if (err) + return err; + } + else if (menu.entries) + { + for (curentry = menu.entries; curentry->next; curentry = curentry->next); + lentry = curentry; + + print_string ("set timeout="); + err = print_num (outbuf, (menu.timeout + 9) / 10); + if (err) + return err; + print_string ("\n"); + + if (menu.def) + { + print_string (" default="); + err = print_escaped (outbuf, menu.def, NULL); + if (err) + return err; + print_string ("\n"); + } + for (curentry = lentry; curentry; curentry = curentry->prev) + { + print_string ("menuentry "); + err = print_escaped (outbuf, + curentry->extlabel ? : curentry->label, NULL); + if (err) + return err; + if (curentry->hotkey) + { + char hk[] = { curentry->hotkey, '\0' }; + print_string (" --hotkey '"); + print_string (hk); + print_string ("'"); + } + print_string (" --id "); + err = print_escaped (outbuf, curentry->label, NULL); + if (err) + return err; + print_string (" {\n"); + + err = write_entry (outbuf, &menu, curentry); + if (err) + return err; + + print_string ("}\n"); + } + } + free_menu (&menu); + return GRUB_ERR_NONE; +} + +char * +grub_syslinux_config_file (const char *base, const char *target_base, + const char *cwd, const char *target_cwd, + const char *fname, grub_syslinux_flavour_t flav) +{ + struct output_buffer outbuf = { 0, 0, 0 }; + grub_err_t err; + err = config_file (&outbuf, base, target_base, cwd, target_cwd, + fname, NULL, flav); + if (err) + return NULL; + err = print (&outbuf, "\0", 1); + if (err) + return NULL; + return outbuf.buf; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/arm64/linux.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/arm64/linux.c new file mode 100644 index 0000000..9ec3413 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/arm64/linux.c @@ -0,0 +1,888 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_dl_t my_mod; +static int loaded; + +static void *kernel_addr; +static grub_uint64_t kernel_size; + +static char *linux_args; +static grub_uint32_t cmdline_size; + +static grub_addr_t initrd_start; +static grub_addr_t initrd_end; + +#define LINUX_MAX_ARGC 1024 +static int ventoy_debug = 0; +static int ventoy_initrd_called = 0; +static int ventoy_linux_argc = 0; +static char **ventoy_linux_args = NULL; +static int ventoy_extra_initrd_num = 0; +static char *ventoy_extra_initrd_list[256]; +static grub_err_t +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]); + +grub_err_t +grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) +{ + if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) + return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); + + if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); + + grub_dprintf ("linux", "UEFI stub kernel:\n"); + grub_dprintf ("linux", "PE/COFF header @ %08x\n", lh->hdr_offset); + + return GRUB_ERR_NONE; +} + +static grub_err_t +finalize_params_linux (void) +{ + int node, retval; + + void *fdt; + + fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); + + if (!fdt) + goto failure; + + node = grub_fdt_find_subnode (fdt, 0, "chosen"); + if (node < 0) + node = grub_fdt_add_subnode (fdt, 0, "chosen"); + + if (node < 1) + goto failure; + + /* Set initrd info */ + if (initrd_start && initrd_end > initrd_start) + { + grub_dprintf ("linux", "Initrd @ %p-%p\n", + (void *) initrd_start, (void *) initrd_end); + + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", + initrd_start); + if (retval) + goto failure; + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", + initrd_end); + if (retval) + goto failure; + } + + if (grub_fdt_install() != GRUB_ERR_NONE) + goto failure; + + return GRUB_ERR_NONE; + +failure: + grub_fdt_unload(); + return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); +} + +grub_err_t +grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) +{ + grub_efi_memory_mapped_device_path_t *mempath; + grub_efi_handle_t image_handle; + grub_efi_boot_services_t *b; + grub_efi_status_t status; + grub_efi_loaded_image_t *loaded_image; + int len; + + mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t)); + if (!mempath) + return grub_errno; + + mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE; + mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE; + mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath)); + mempath[0].memory_type = GRUB_EFI_LOADER_DATA; + mempath[0].start_address = addr; + mempath[0].end_address = addr + size; + + mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE; + mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; + mempath[1].header.length = sizeof (grub_efi_device_path_t); + + b = grub_efi_system_table->boot_services; + status = b->load_image (0, grub_efi_image_handle, + (grub_efi_device_path_t *) mempath, + (void *) addr, size, &image_handle); + if (status != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_BAD_OS, "cannot load image"); + + grub_dprintf ("linux", "linux command line: '%s'\n", args); + + /* Convert command line to UCS-2 */ + loaded_image = grub_efi_get_loaded_image (image_handle); + loaded_image->load_options_size = len = + (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t); + loaded_image->load_options = + grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); + if (!loaded_image->load_options) + return grub_errno; + + loaded_image->load_options_size = + 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, + (grub_uint8_t *) args, len, NULL); + + grub_dprintf ("linux", "starting image %p\n", image_handle); + status = b->start_image (image_handle, 0, NULL); + + /* When successful, not reached */ + b->unload_image (image_handle); + grub_efi_free_pages ((grub_addr_t) loaded_image->load_options, + GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); + + return grub_errno; +} + + +static void ventoy_debug_pause(void) +{ + char key; + + if (0 == ventoy_debug) + { + return; + } + + grub_printf("press Enter to continue ......\n"); + while (1) + { + key = grub_getkey(); + if (key == '\n' || key == '\r') + { + break; + } + } +} + +static int ventoy_preboot(void) +{ + int i; + const char *file; + char buf[128]; + + if (ventoy_debug) + { + grub_printf("ventoy_preboot %d %d\n", ventoy_linux_argc, ventoy_initrd_called); + ventoy_debug_pause(); + } + + if (ventoy_linux_argc == 0) + { + return 0; + } + + if (ventoy_initrd_called) + { + ventoy_initrd_called = 0; + return 0; + } + + grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size")); + + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf); + + file = grub_env_get("vtoy_img_part_file"); + if (file) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file); + } + + if (ventoy_debug) + { + grub_printf("========== initrd list ==========\n"); + for (i = 0; i < ventoy_extra_initrd_num; i++) + { + grub_printf("%s\n", ventoy_extra_initrd_list[i]); + } + grub_printf("=================================\n"); + + ventoy_debug_pause(); + } + + grub_cmd_initrd(NULL, ventoy_extra_initrd_num, ventoy_extra_initrd_list); + + return 0; +} + +static int ventoy_boot_opt_filter(char *opt) +{ + if (grub_strcmp(opt, "noinitrd") == 0) + { + return 1; + } + + if (grub_strcmp(opt, "vga=current") == 0) + { + return 1; + } + + if (grub_strncmp(opt, "rdinit=", 7) == 0) + { + if (grub_strcmp(opt, "rdinit=/vtoy/vtoy") != 0) + { + opt[0] = 'v'; + opt[1] = 't'; + } + return 0; + } + + if (grub_strncmp(opt, "init=", 5) == 0) + { + opt[0] = 'v'; + opt[1] = 't'; + return 0; + } + + if (grub_strncmp(opt, "dm=", 3) == 0) + { + opt[0] = 'D'; + opt[1] = 'M'; + return 0; + } + + if (ventoy_debug) + { + if (grub_strcmp(opt, "quiet") == 0) + { + return 1; + } + + if (grub_strncmp(opt, "loglevel=", 9) == 0) + { + return 1; + } + + if (grub_strcmp(opt, "splash") == 0) + { + return 1; + } + } + + return 0; +} + +static int ventoy_bootopt_hook(int argc, char *argv[]) +{ + int i; + int TmpIdx; + int count = 0; + const char *env; + char c; + char *newenv; + char *last, *pos; + + //grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc); + + if (ventoy_linux_argc == 0) + { + return 0; + } + + /* To avoid --- parameter, we split two parts */ + for (TmpIdx = 0; TmpIdx < argc; TmpIdx++) + { + if (ventoy_boot_opt_filter(argv[TmpIdx])) + { + continue; + } + + if (grub_strncmp(argv[TmpIdx], "--", 2) == 0) + { + break; + } + + ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]); + } + + for (i = 0; i < ventoy_linux_argc; i++) + { + ventoy_linux_args[count] = ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)]; + ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)] = NULL; + + if (ventoy_linux_args[count][0] == '@') + { + env = grub_env_get(ventoy_linux_args[count] + 1); + if (env) + { + grub_free(ventoy_linux_args[count]); + + newenv = grub_strdup(env); + last = newenv; + + while (*last) + { + while (*last) + { + if (*last != ' ' && *last != '\t') + { + break; + } + last++; + } + + if (*last == 0) + { + break; + } + + for (pos = last; *pos; pos++) + { + if (*pos == ' ' || *pos == '\t') + { + c = *pos; + *pos = 0; + if (0 == ventoy_boot_opt_filter(last)) + { + ventoy_linux_args[count++] = grub_strdup(last); + } + *pos = c; + break; + } + } + + if (*pos == 0) + { + if (0 == ventoy_boot_opt_filter(last)) + { + ventoy_linux_args[count++] = grub_strdup(last); + } + break; + } + + last = pos + 1; + } + } + else + { + count++; + } + } + else + { + count++; + } + } + + while (TmpIdx < argc) + { + if (ventoy_boot_opt_filter(argv[TmpIdx])) + { + continue; + } + + ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]); + TmpIdx++; + } + + if (ventoy_debug) + { + ventoy_linux_args[count++] = grub_strdup("loglevel=7"); + } + + ventoy_linux_argc = count; + + if (ventoy_debug) + { + grub_printf("========== bootoption ==========\n"); + for (i = 0; i < count; i++) + { + grub_printf("%s ", ventoy_linux_args[i]); + } + grub_printf("\n================================\n"); + } + + return 0; +} + +static grub_err_t +grub_cmd_set_boot_opt (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + const char *vtdebug; + + for (i = 0; i < argc; i++) + { + ventoy_linux_args[ventoy_linux_argc + (LINUX_MAX_ARGC / 2) ] = grub_strdup(argv[i]); + ventoy_linux_argc++; + } + + vtdebug = grub_env_get("vtdebug_flag"); + if (vtdebug && vtdebug[0]) + { + ventoy_debug = 1; + } + + if (ventoy_debug) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc); + + return 0; +} + +static grub_err_t +grub_cmd_unset_boot_opt (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + + (void)argc; + (void)argv; + + for (i = 0; i < LINUX_MAX_ARGC; i++) + { + if (ventoy_linux_args[i]) + { + grub_free(ventoy_linux_args[i]); + } + } + + ventoy_debug = 0; + ventoy_linux_argc = 0; + ventoy_initrd_called = 0; + grub_memset(ventoy_linux_args, 0, sizeof(char *) * LINUX_MAX_ARGC); + return 0; +} + +static grub_err_t +grub_cmd_extra_initrd_append (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_uint32_t i; + int newclen = 0; + char *pos = NULL; + char *end = NULL; + char buf[256] = {0}; + const char *suffix = NULL; + const char *check_suffix[] = { ".ko", ".ko.zst", ".ko.xz", ".ko.gz" }; + + if (argc != 1) + { + return 1; + } + + if (grub_strstr(argv[0], ".ko")) + { + if (ventoy_check_file_exist("%s", argv[0])) + { + suffix = ""; + } + } + else + { + for (i = 0; i < sizeof(check_suffix) / sizeof(check_suffix[0]); i++) + { + if (ventoy_check_file_exist("%s%s", argv[0], check_suffix[i])) + { + suffix = check_suffix[i]; + break; + } + } + } + + if (!suffix) + { + grub_printf("ko file <%s> not exist\n", argv[0]); + return 0; + } + + for (pos = argv[0]; *pos; pos++) + { + if (*pos == '/') + { + end = pos; + } + } + + if (end) + { + /* grub2 newc bug workaround */ + newclen = (int)grub_strlen(end + 1); + if ((110 + newclen) % 4 == 0) + { + grub_snprintf(buf, sizeof(buf), "newc:.%s%s:%s%s", end + 1, suffix, argv[0], suffix); + } + else + { + grub_snprintf(buf, sizeof(buf), "newc:%s%s:%s%s", end + 1, suffix, argv[0], suffix); + } + + if (ventoy_extra_initrd_num < 256) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf); + } + } + + return 0; +} + + +static grub_err_t +grub_cmd_extra_initrd_reset (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + + (void)argc; + (void)argv; + + for (i = 0; i < ventoy_extra_initrd_num; i++) + { + if (ventoy_extra_initrd_list[i]) + { + grub_free(ventoy_extra_initrd_list[i]); + } + } + + grub_memset(ventoy_extra_initrd_list, 0, sizeof(ventoy_extra_initrd_list)); + + return 0; +} + + +static grub_err_t +grub_linux_boot (void) +{ + ventoy_preboot(); + + if (finalize_params_linux () != GRUB_ERR_NONE) + return grub_errno; + + return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, + kernel_size, linux_args)); +} + +static grub_err_t +grub_linux_unload (void) +{ + grub_dl_unref (my_mod); + loaded = 0; + if (initrd_start) + grub_efi_free_pages ((grub_efi_physical_address_t) initrd_start, + GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start)); + initrd_start = initrd_end = 0; + grub_free (linux_args); + if (kernel_addr) + grub_efi_free_pages ((grub_addr_t) kernel_addr, + GRUB_EFI_BYTES_TO_PAGES (kernel_size)); + grub_fdt_unload (); + return GRUB_ERR_NONE; +} + +/* + * As per linux/Documentation/arm/Booting + * ARM initrd needs to be covered by kernel linear mapping, + * so place it in the first 512MB of DRAM. + * + * As per linux/Documentation/arm64/booting.txt + * ARM64 initrd needs to be contained entirely within a 1GB aligned window + * of up to 32GB of size that covers the kernel image as well. + * Since the EFI stub loader will attempt to load the kernel near start of + * RAM, place the buffer in the first 32GB of RAM. + */ +#ifdef __arm__ +#define INITRD_MAX_ADDRESS_OFFSET (512U * 1024 * 1024) +#else /* __aarch64__ */ +#define INITRD_MAX_ADDRESS_OFFSET (32ULL * 1024 * 1024 * 1024) +#endif + +/* + * This function returns a pointer to a legally allocated initrd buffer, + * or NULL if unsuccessful + */ +static void * +allocate_initrd_mem (int initrd_pages) +{ + grub_addr_t max_addr; + + if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) + return NULL; + + max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; + + return grub_efi_allocate_pages_real (max_addr, initrd_pages, + GRUB_EFI_ALLOCATE_MAX_ADDRESS, + GRUB_EFI_LOADER_DATA); +} + +static grub_err_t +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; + int initrd_size, initrd_pages; + void *initrd_mem = NULL; + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + goto fail; + } + + if (!loaded) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("you need to load the kernel first")); + goto fail; + } + + if (grub_initrd_init (argc, argv, &initrd_ctx)) + goto fail; + + initrd_size = grub_get_initrd_size (&initrd_ctx); + grub_dprintf ("linux", "Loading initrd\n"); + + initrd_pages = (GRUB_EFI_BYTES_TO_PAGES (initrd_size)); + initrd_mem = allocate_initrd_mem (initrd_pages); + + if (!initrd_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto fail; + } + + if (grub_initrd_load (&initrd_ctx, argv, initrd_mem)) + goto fail; + + initrd_start = (grub_addr_t) initrd_mem; + initrd_end = initrd_start + initrd_size; + grub_dprintf ("linux", "[addr=%p, size=0x%x]\n", + (void *) initrd_start, initrd_size); + + fail: + grub_initrd_close (&initrd_ctx); + if (initrd_mem && !initrd_start) + grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages); + + return grub_errno; +} + +static grub_err_t +grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + struct linux_arch_kernel_header lh; + grub_err_t err; + + grub_dl_ref (my_mod); + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + goto fail; + } + + file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (!file) + goto fail; + + kernel_size = grub_file_size (file); + + if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh)) + return grub_errno; + + if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE) + goto fail; + + grub_loader_unset(); + + grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size); + kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size)); + grub_dprintf ("linux", "kernel numpages: %lld\n", + (long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size)); + if (!kernel_addr) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto fail; + } + + grub_file_seek (file, 0); + if (grub_file_read (file, kernel_addr, kernel_size) + < (grub_int64_t) kernel_size) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); + goto fail; + } + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); + + cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); + linux_args = grub_malloc (cmdline_size); + if (!linux_args) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto fail; + } + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + + if (ventoy_linux_argc) + { + ventoy_bootopt_hook(argc, argv); + err = grub_create_loader_cmdline (ventoy_linux_argc, ventoy_linux_args, + linux_args + sizeof (LINUX_IMAGE) - 1, + cmdline_size, + GRUB_VERIFY_KERNEL_CMDLINE); } + else + { + err = grub_create_loader_cmdline (argc, argv, + linux_args + sizeof (LINUX_IMAGE) - 1, + cmdline_size, + GRUB_VERIFY_KERNEL_CMDLINE); + } + + if (err) + goto fail; + + if (grub_errno == GRUB_ERR_NONE) + { + grub_loader_set (grub_linux_boot, grub_linux_unload, 0); + loaded = 1; + } + +fail: + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_dl_unref (my_mod); + loaded = 0; + } + + if (linux_args && !loaded) + grub_free (linux_args); + + if (kernel_addr && !loaded) + grub_efi_free_pages ((grub_addr_t) kernel_addr, + GRUB_EFI_BYTES_TO_PAGES (kernel_size)); + + return grub_errno; +} + +static grub_err_t +ventoy_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + const char *file; + char buf[64]; + + if (ventoy_debug) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc); + + if (ventoy_linux_argc == 0) + { + return grub_cmd_initrd(cmd, argc, argv); + } + + grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size")); + + if (ventoy_debug) grub_printf("membuf=%s\n", buf); + + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf); + + file = grub_env_get("vtoy_img_part_file"); + if (file) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file); + } + + for (i = 0; i < argc; i++) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(argv[i]); + } + + ventoy_initrd_called = 1; + + if (ventoy_debug) + { + grub_printf("========== initrd list ==========\n"); + for (i = 0; i < ventoy_extra_initrd_num; i++) + { + grub_printf("%s\n", ventoy_extra_initrd_list[i]); + } + grub_printf("=================================\n"); + } + + return grub_cmd_initrd(cmd, ventoy_extra_initrd_num, ventoy_extra_initrd_list); +} + + +static grub_command_t cmd_linux, cmd_initrd, cmd_linuxefi, cmd_initrdefi; +static grub_command_t cmd_set_bootopt, cmd_unset_bootopt, cmd_extra_initrd_append, cmd_extra_initrd_reset; + + +GRUB_MOD_INIT (linux) +{ + cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0, + N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", ventoy_cmd_initrd, 0, + N_("Load initrd.")); + + cmd_linuxefi = grub_register_command ("linuxefi", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrdefi = grub_register_command ("initrdefi", ventoy_cmd_initrd, + 0, N_("Load initrd.")); + + cmd_set_bootopt = grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt, 0, N_("set ext boot opt")); + cmd_unset_bootopt = grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt, 0, N_("unset ext boot opt")); + + cmd_extra_initrd_append = grub_register_command ("vt_img_extra_initrd_append", grub_cmd_extra_initrd_append, 0, N_("")); + cmd_extra_initrd_reset = grub_register_command ("vt_img_extra_initrd_reset", grub_cmd_extra_initrd_reset, 0, N_("")); + + ventoy_linux_args = grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC); + + my_mod = mod; +} + +GRUB_MOD_FINI (linux) +{ + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/efi/chainloader.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/efi/chainloader.c new file mode 100644 index 0000000..173b4b5 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/efi/chainloader.c @@ -0,0 +1,418 @@ +/* chainloader.c - boot another boot loader */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2006,2007,2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +/* TODO: support load options. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined (__i386__) || defined (__x86_64__) +#include +#include +#endif + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_dl_t my_mod; + +static grub_efi_physical_address_t address; +static grub_efi_uintn_t pages; +static grub_efi_device_path_t *file_path; +static grub_efi_handle_t image_handle; +static grub_efi_char16_t *cmdline; + +static grub_err_t +grub_chainloader_unload (void) +{ + grub_efi_boot_services_t *b; + + b = grub_efi_system_table->boot_services; + efi_call_1 (b->unload_image, image_handle); + efi_call_2 (b->free_pages, address, pages); + + grub_free (file_path); + grub_free (cmdline); + cmdline = 0; + file_path = 0; + + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_chainloader_boot (void) +{ + grub_efi_boot_services_t *b; + grub_efi_status_t status; + grub_efi_uintn_t exit_data_size; + grub_efi_char16_t *exit_data = NULL; + + b = grub_efi_system_table->boot_services; + status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data); + if (status != GRUB_EFI_SUCCESS) + { + if (exit_data) + { + char *buf; + + buf = grub_malloc (exit_data_size * 4 + 1); + if (buf) + { + *grub_utf16_to_utf8 ((grub_uint8_t *) buf, + exit_data, exit_data_size) = 0; + + grub_error (GRUB_ERR_BAD_OS, buf); + grub_free (buf); + } + } + else + grub_error (GRUB_ERR_BAD_OS, "unknown error"); + } + + if (exit_data) + efi_call_1 (b->free_pool, exit_data); + + grub_loader_unset (); + + return grub_errno; +} + +static void +copy_file_path (grub_efi_file_path_device_path_t *fp, + const char *str, grub_efi_uint16_t len) +{ + grub_efi_char16_t *p, *path_name; + grub_efi_uint16_t size; + + fp->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE; + fp->header.subtype = GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE; + + path_name = grub_malloc (len * GRUB_MAX_UTF16_PER_UTF8 * sizeof (*path_name)); + if (!path_name) + return; + + size = grub_utf8_to_utf16 (path_name, len * GRUB_MAX_UTF16_PER_UTF8, + (const grub_uint8_t *) str, len, 0); + for (p = path_name; p < path_name + size; p++) + if (*p == '/') + *p = '\\'; + + grub_memcpy (fp->path_name, path_name, size * sizeof (*fp->path_name)); + /* File Path is NULL terminated */ + fp->path_name[size++] = '\0'; + fp->header.length = size * sizeof (grub_efi_char16_t) + sizeof (*fp); + grub_free (path_name); +} + +static grub_efi_device_path_t * +make_file_path (grub_efi_device_path_t *dp, const char *filename) +{ + char *dir_start; + char *dir_end; + grub_size_t size; + grub_efi_device_path_t *d; + + dir_start = grub_strchr (filename, ')'); + if (! dir_start) + dir_start = (char *) filename; + else + dir_start++; + + dir_end = grub_strrchr (dir_start, '/'); + if (! dir_end) + { + grub_error (GRUB_ERR_BAD_FILENAME, "invalid EFI file path"); + return 0; + } + + size = 0; + d = dp; + while (1) + { + size += GRUB_EFI_DEVICE_PATH_LENGTH (d); + if ((GRUB_EFI_END_ENTIRE_DEVICE_PATH (d))) + break; + d = GRUB_EFI_NEXT_DEVICE_PATH (d); + } + + /* File Path is NULL terminated. Allocate space for 2 extra characters */ + /* FIXME why we split path in two components? */ + file_path = grub_malloc (size + + ((grub_strlen (dir_start) + 2) + * GRUB_MAX_UTF16_PER_UTF8 + * sizeof (grub_efi_char16_t)) + + sizeof (grub_efi_file_path_device_path_t) * 2); + if (! file_path) + return 0; + + grub_memcpy (file_path, dp, size); + + /* Fill the file path for the directory. */ + d = (grub_efi_device_path_t *) ((char *) file_path + + ((char *) d - (char *) dp)); + //grub_efi_print_device_path (d); + copy_file_path ((grub_efi_file_path_device_path_t *) d, + dir_start, dir_end - dir_start); + + /* Fill the file path for the file. */ + d = GRUB_EFI_NEXT_DEVICE_PATH (d); + copy_file_path ((grub_efi_file_path_device_path_t *) d, + dir_end + 1, grub_strlen (dir_end + 1)); + + /* Fill the end of device path nodes. */ + d = GRUB_EFI_NEXT_DEVICE_PATH (d); + d->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + d->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; + d->length = sizeof (*d); + + return file_path; +} + +static grub_err_t +grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_ssize_t size; + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; + grub_efi_device_path_t *dp = 0; + grub_efi_loaded_image_t *loaded_image; + char *filename; + void *boot_image = 0; + grub_efi_handle_t dev_handle = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + filename = argv[0]; + + grub_dl_ref (my_mod); + + /* Initialize some global variables. */ + address = 0; + image_handle = 0; + file_path = 0; + + b = grub_efi_system_table->boot_services; + + file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); + if (! file) + goto fail; + + dev = file->device; + + if (dev->disk) + dev_handle = grub_efidisk_get_device_handle (dev->disk); + else if (dev->net && dev->net->server) + { + grub_net_network_level_address_t addr; + struct grub_net_network_level_interface *inf; + grub_net_network_level_address_t gateway; + grub_err_t err; + + err = grub_net_resolve_address (dev->net->server, &addr); + if (err) + goto fail; + + err = grub_net_route_address (addr, &gateway, &inf); + if (err) + goto fail; + + dev_handle = grub_efinet_get_device_handle (inf->card); + } + + if (dev_handle) + dp = grub_efi_get_device_path (dev_handle); + + if (dp != NULL) + { + file_path = make_file_path (dp, filename); + if (! file_path) + goto fail; + } + + //grub_printf ("file path: "); + //grub_efi_print_device_path (file_path); + + size = grub_file_size (file); + if (!size) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } + pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12); + + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, + GRUB_EFI_LOADER_CODE, + pages, &address); + if (status != GRUB_EFI_SUCCESS) + { + grub_dprintf ("chain", "Failed to allocate %u pages\n", + (unsigned int) pages); + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto fail; + } + + boot_image = (void *) ((grub_addr_t) address); + if (grub_file_read (file, boot_image, size) != size) + { + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + + goto fail; + } + +#if defined (__i386__) || defined (__x86_64__) + if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) + { + struct grub_macho_fat_header *head = boot_image; + if (head->magic + == grub_cpu_to_le32_compile_time (GRUB_MACHO_FAT_EFI_MAGIC)) + { + grub_uint32_t i; + struct grub_macho_fat_arch *archs + = (struct grub_macho_fat_arch *) (head + 1); + for (i = 0; i < grub_cpu_to_le32 (head->nfat_arch); i++) + { + if (GRUB_MACHO_CPUTYPE_IS_HOST_CURRENT (archs[i].cputype)) + break; + } + if (i == grub_cpu_to_le32 (head->nfat_arch)) + { + grub_error (GRUB_ERR_BAD_OS, "no compatible arch found"); + goto fail; + } + if (grub_cpu_to_le32 (archs[i].offset) + > ~grub_cpu_to_le32 (archs[i].size) + || grub_cpu_to_le32 (archs[i].offset) + + grub_cpu_to_le32 (archs[i].size) + > (grub_size_t) size) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } + boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset); + size = grub_cpu_to_le32 (archs[i].size); + } + } +#endif + + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, + boot_image, size, + &image_handle); + if (status != GRUB_EFI_SUCCESS) + { + if (status == GRUB_EFI_OUT_OF_RESOURCES) + grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources"); + else + grub_error (GRUB_ERR_BAD_OS, "cannot load image"); + + goto fail; + } + + /* LoadImage does not set a device handler when the image is + loaded from memory, so it is necessary to set it explicitly here. + This is a mess. */ + loaded_image = grub_efi_get_loaded_image (image_handle); + if (! loaded_image) + { + grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); + goto fail; + } + loaded_image->device_handle = dev_handle; + + if (argc > 1) + { + int i, len; + grub_efi_char16_t *p16; + + for (i = 1, len = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + + len *= sizeof (grub_efi_char16_t); + cmdline = p16 = grub_malloc (len); + if (! cmdline) + goto fail; + + for (i = 1; i < argc; i++) + { + char *p8; + + p8 = argv[i]; + while (*p8) + *(p16++) = *(p8++); + + *(p16++) = ' '; + } + *(--p16) = 0; + + loaded_image->load_options = cmdline; + loaded_image->load_options_size = len; + } + + grub_file_close (file); + + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); + return 0; + + fail: + + if (file) + grub_file_close (file); + + grub_free (file_path); + + if (address) + efi_call_2 (b->free_pages, address, pages); + + grub_dl_unref (my_mod); + + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(chainloader) +{ + cmd = grub_register_command ("chainloader", grub_cmd_chainloader, + 0, N_("Load another boot loader.")); + my_mod = mod; +} + +GRUB_MOD_FINI(chainloader) +{ + grub_unregister_command (cmd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/i386/linux.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/i386/linux.c new file mode 100644 index 0000000..1cf9ecc --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/i386/linux.c @@ -0,0 +1,1690 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#ifdef GRUB_MACHINE_PCBIOS +#include +#endif + +#ifdef GRUB_MACHINE_EFI +#include +#define HAS_VGA_TEXT 0 +#define DEFAULT_VIDEO_MODE "auto" +#define ACCEPTS_PURE_TEXT 0 +#elif defined (GRUB_MACHINE_IEEE1275) +#include +#define HAS_VGA_TEXT 0 +#define DEFAULT_VIDEO_MODE "text" +#define ACCEPTS_PURE_TEXT 1 +#else +#include +#include +#define HAS_VGA_TEXT 1 +#define DEFAULT_VIDEO_MODE "text" +#define ACCEPTS_PURE_TEXT 1 +#endif + +static grub_dl_t my_mod; + +static grub_size_t linux_mem_size; +static int loaded; +static void *prot_mode_mem; +static grub_addr_t prot_mode_target; +static void *initrd_mem; +static grub_addr_t initrd_mem_target; +static grub_size_t prot_init_space; +static struct grub_relocator *relocator = NULL; +static void *efi_mmap_buf; +static grub_size_t maximal_cmdline_size; +static struct linux_kernel_params linux_params; +static char *linux_cmdline; +#ifdef GRUB_MACHINE_EFI +static grub_efi_uintn_t efi_mmap_size; +#else +static const grub_size_t efi_mmap_size = 0; +#endif + +#define LINUX_MAX_ARGC 1024 +static int ventoy_debug = 0; +static int ventoy_initrd_called = 0; +static int ventoy_linux_argc = 0; +static char **ventoy_linux_args = NULL; +static int ventoy_extra_initrd_num = 0; +static char *ventoy_extra_initrd_list[256]; +static grub_command_func_t ventoy_linux16_func = NULL; +static grub_command_func_t ventoy_initrd16_func = NULL; +static grub_err_t +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]); + +/* FIXME */ +#if 0 +struct idt_descriptor +{ + grub_uint16_t limit; + void *base; +} GRUB_PACKED; + +static struct idt_descriptor idt_desc = + { + 0, + 0 + }; +#endif + +static inline grub_size_t +page_align (grub_size_t size) +{ + return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); +} + +/* Helper for find_mmap_size. */ +static int +count_hook (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + grub_memory_type_t type __attribute__ ((unused)), void *data) +{ + grub_size_t *count = data; + + (*count)++; + return 0; +} + +/* Find the optimal number of pages for the memory map. */ +static grub_size_t +find_mmap_size (void) +{ + grub_size_t count = 0, mmap_size; + + grub_mmap_iterate (count_hook, &count); + + mmap_size = count * sizeof (struct grub_e820_mmap); + + /* Increase the size a bit for safety, because GRUB allocates more on + later. */ + mmap_size += (1 << 12); + + return page_align (mmap_size); +} + +static void +free_pages (void) +{ + grub_relocator_unload (relocator); + relocator = NULL; + prot_mode_mem = initrd_mem = 0; + prot_mode_target = initrd_mem_target = 0; +} + +/* Allocate pages for the real mode code and the protected mode code + for linux as well as a memory map buffer. */ +static grub_err_t +allocate_pages (grub_size_t prot_size, grub_size_t *align, + grub_size_t min_align, int relocatable, + grub_uint64_t preferred_address) +{ + grub_err_t err; + + if (prot_size == 0) + prot_size = 1; + + prot_size = page_align (prot_size); + + /* Initialize the memory pointers with NULL for convenience. */ + free_pages (); + + relocator = grub_relocator_new (); + if (!relocator) + { + err = grub_errno; + goto fail; + } + + /* FIXME: Should request low memory from the heap when this feature is + implemented. */ + + { + grub_relocator_chunk_t ch; + if (relocatable) + { + err = grub_relocator_alloc_chunk_align (relocator, &ch, + preferred_address, + preferred_address, + prot_size, 1, + GRUB_RELOCATOR_PREFERENCE_LOW, + 1); + for (; err && *align + 1 > min_align; (*align)--) + { + grub_errno = GRUB_ERR_NONE; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + 0x1000000, + 0xffffffff & ~prot_size, + prot_size, 1 << *align, + GRUB_RELOCATOR_PREFERENCE_LOW, + 1); + } + if (err) + goto fail; + } + else + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + preferred_address, + prot_size); + if (err) + goto fail; + prot_mode_mem = get_virtual_current_address (ch); + prot_mode_target = get_physical_target_address (ch); + } + + grub_dprintf ("linux", "prot_mode_mem = %p, prot_mode_target = %lx, prot_size = %x\n", + prot_mode_mem, (unsigned long) prot_mode_target, + (unsigned) prot_size); + return GRUB_ERR_NONE; + + fail: + free_pages (); + return err; +} + +static grub_err_t +grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num, + grub_uint64_t start, grub_uint64_t size, + grub_uint32_t type) +{ + int n = *e820_num; + + if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) && + (e820_map[n - 1].type == type)) + e820_map[n - 1].size += size; + else + { + e820_map[n].addr = start; + e820_map[n].size = size; + e820_map[n].type = type; + (*e820_num)++; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_linux_setup_video (struct linux_kernel_params *params) +{ + struct grub_video_mode_info mode_info; + void *framebuffer; + grub_err_t err; + grub_video_driver_id_t driver_id; + const char *gfxlfbvar = grub_env_get ("gfxpayloadforcelfb"); + + driver_id = grub_video_get_driver_id (); + + if (driver_id == GRUB_VIDEO_DRIVER_NONE) + return 1; + + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + + if (err) + { + grub_errno = GRUB_ERR_NONE; + return 1; + } + + params->lfb_width = mode_info.width; + params->lfb_height = mode_info.height; + params->lfb_depth = mode_info.bpp; + params->lfb_line_len = mode_info.pitch; + + params->lfb_base = (grub_size_t) framebuffer; + +#if defined (GRUB_MACHINE_EFI) && defined (__x86_64__) + params->ext_lfb_base = (grub_size_t) (((grub_uint64_t)(grub_size_t) framebuffer) >> 32); + params->capabilities |= VIDEO_CAPABILITY_64BIT_BASE; +#endif + + params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, 65536); + + params->red_mask_size = mode_info.red_mask_size; + params->red_field_pos = mode_info.red_field_pos; + params->green_mask_size = mode_info.green_mask_size; + params->green_field_pos = mode_info.green_field_pos; + params->blue_mask_size = mode_info.blue_mask_size; + params->blue_field_pos = mode_info.blue_field_pos; + params->reserved_mask_size = mode_info.reserved_mask_size; + params->reserved_field_pos = mode_info.reserved_field_pos; + + if (gfxlfbvar && (gfxlfbvar[0] == '1' || gfxlfbvar[0] == 'y')) + params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; + else + { + switch (driver_id) + { + case GRUB_VIDEO_DRIVER_VBE: + params->lfb_size >>= 16; + params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA; + break; + + case GRUB_VIDEO_DRIVER_EFI_UGA: + case GRUB_VIDEO_DRIVER_EFI_GOP: + params->have_vga = GRUB_VIDEO_LINUX_TYPE_EFIFB; + break; + + /* FIXME: check if better id is available. */ + case GRUB_VIDEO_DRIVER_SM712: + case GRUB_VIDEO_DRIVER_SIS315PRO: + case GRUB_VIDEO_DRIVER_VGA: + case GRUB_VIDEO_DRIVER_CIRRUS: + case GRUB_VIDEO_DRIVER_BOCHS: + case GRUB_VIDEO_DRIVER_RADEON_FULOONG2E: + case GRUB_VIDEO_DRIVER_RADEON_YEELOONG3A: + case GRUB_VIDEO_DRIVER_IEEE1275: + case GRUB_VIDEO_DRIVER_COREBOOT: + /* Make gcc happy. */ + case GRUB_VIDEO_DRIVER_XEN: + case GRUB_VIDEO_DRIVER_SDL: + case GRUB_VIDEO_DRIVER_NONE: + case GRUB_VIDEO_ADAPTER_CAPTURE: + params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; + break; + } + } + +#ifdef GRUB_MACHINE_PCBIOS + /* VESA packed modes may come with zeroed mask sizes, which need + to be set here according to DAC Palette width. If we don't, + this results in Linux displaying a black screen. */ + if (driver_id == GRUB_VIDEO_DRIVER_VBE && mode_info.bpp <= 8) + { + struct grub_vbe_info_block controller_info; + int status; + int width = 8; + + status = grub_vbe_bios_get_controller_info (&controller_info); + + if (status == GRUB_VBE_STATUS_OK && + (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH)) + status = grub_vbe_bios_set_dac_palette_width (&width); + + if (status != GRUB_VBE_STATUS_OK) + /* 6 is default after mode reset. */ + width = 6; + + params->red_mask_size = params->green_mask_size + = params->blue_mask_size = width; + params->reserved_mask_size = 0; + } +#endif + + return GRUB_ERR_NONE; +} + +/* Context for grub_linux_boot. */ +struct grub_linux_boot_ctx +{ + grub_addr_t real_mode_target; + grub_size_t real_size; + struct linux_kernel_params *params; + int e820_num; +}; + +/* Helper for grub_linux_boot. */ +static int +grub_linux_boot_mmap_find (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type, void *data) +{ + struct grub_linux_boot_ctx *ctx = data; + + /* We must put real mode code in the traditional space. */ + if (type != GRUB_MEMORY_AVAILABLE || addr > 0x90000) + return 0; + + if (addr + size < 0x10000) + return 0; + + if (addr < 0x10000) + { + size += addr - 0x10000; + addr = 0x10000; + } + + if (addr + size > 0x90000) + size = 0x90000 - addr; + + if (ctx->real_size + efi_mmap_size > size) + return 0; + + grub_dprintf ("linux", "addr = %lx, size = %x, need_size = %x\n", + (unsigned long) addr, + (unsigned) size, + (unsigned) (ctx->real_size + efi_mmap_size)); + ctx->real_mode_target = ((addr + size) - (ctx->real_size + efi_mmap_size)); + return 1; +} + +/* GRUB types conveniently match E820 types. */ +static int +grub_linux_boot_mmap_fill (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type, void *data) +{ + struct grub_linux_boot_ctx *ctx = data; + + if (grub_e820_add_region (ctx->params->e820_map, &ctx->e820_num, + addr, size, type)) + return 1; + + return 0; +} + +static void ventoy_debug_pause(void) +{ + char key; + + if (0 == ventoy_debug) + { + return; + } + + grub_printf("press Enter to continue ......\n"); + while (1) + { + key = grub_getkey(); + if (key == '\n' || key == '\r') + { + break; + } + } +} + +static int ventoy_preboot(void) +{ + int i; + const char *file; + char buf[128]; + + if (ventoy_debug) + { + grub_printf("ventoy_preboot %d %d\n", ventoy_linux_argc, ventoy_initrd_called); + ventoy_debug_pause(); + } + + if (ventoy_linux_argc == 0) + { + return 0; + } + + if (ventoy_initrd_called) + { + ventoy_initrd_called = 0; + return 0; + } + + grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size")); + + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf); + + file = grub_env_get("vtoy_img_part_file"); + if (file) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file); + } + + if (ventoy_debug) + { + grub_printf("========== initrd list ==========\n"); + for (i = 0; i < ventoy_extra_initrd_num; i++) + { + grub_printf("%s\n", ventoy_extra_initrd_list[i]); + } + grub_printf("=================================\n"); + + ventoy_debug_pause(); + } + + grub_cmd_initrd(NULL, ventoy_extra_initrd_num, ventoy_extra_initrd_list); + + return 0; +} + +static int ventoy_boot_opt_filter(char *opt) +{ + if (grub_strcmp(opt, "noinitrd") == 0) + { + return 1; + } + + if (grub_strcmp(opt, "vga=current") == 0) + { + return 1; + } + + if (grub_strncmp(opt, "rdinit=", 7) == 0) + { + if (grub_strcmp(opt, "rdinit=/vtoy/vtoy") != 0) + { + opt[0] = 'v'; + opt[1] = 't'; + } + return 0; + } + + if (grub_strncmp(opt, "init=", 5) == 0) + { + opt[0] = 'v'; + opt[1] = 't'; + return 0; + } + + if (grub_strncmp(opt, "dm=", 3) == 0) + { + opt[0] = 'D'; + opt[1] = 'M'; + return 0; + } + + if (ventoy_debug) + { + if (grub_strcmp(opt, "quiet") == 0) + { + return 1; + } + + if (grub_strncmp(opt, "loglevel=", 9) == 0) + { + return 1; + } + + if (grub_strcmp(opt, "splash") == 0) + { + return 1; + } + } + + return 0; +} + +static int ventoy_bootopt_hook(int argc, char *argv[]) +{ + int i; + int TmpIdx; + int count = 0; + const char *env; + char c; + char *newenv; + char *last, *pos; + + //grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc); + + if (ventoy_linux_argc == 0) + { + return 0; + } + + /* To avoid --- parameter, we split two parts */ + for (TmpIdx = 0; TmpIdx < argc; TmpIdx++) + { + if (ventoy_boot_opt_filter(argv[TmpIdx])) + { + continue; + } + + if (grub_strncmp(argv[TmpIdx], "--", 2) == 0) + { + break; + } + + ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]); + } + + for (i = 0; i < ventoy_linux_argc; i++) + { + ventoy_linux_args[count] = ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)]; + ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)] = NULL; + + if (ventoy_linux_args[count][0] == '@') + { + env = grub_env_get(ventoy_linux_args[count] + 1); + if (env) + { + grub_free(ventoy_linux_args[count]); + + newenv = grub_strdup(env); + last = newenv; + + while (*last) + { + while (*last) + { + if (*last != ' ' && *last != '\t') + { + break; + } + last++; + } + + if (*last == 0) + { + break; + } + + for (pos = last; *pos; pos++) + { + if (*pos == ' ' || *pos == '\t') + { + c = *pos; + *pos = 0; + if (0 == ventoy_boot_opt_filter(last)) + { + ventoy_linux_args[count++] = grub_strdup(last); + } + *pos = c; + break; + } + } + + if (*pos == 0) + { + if (0 == ventoy_boot_opt_filter(last)) + { + ventoy_linux_args[count++] = grub_strdup(last); + } + break; + } + + last = pos + 1; + } + } + else + { + count++; + } + } + else + { + count++; + } + } + + while (TmpIdx < argc) + { + if (ventoy_boot_opt_filter(argv[TmpIdx])) + { + continue; + } + + ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]); + TmpIdx++; + } + + if (ventoy_debug) + { + ventoy_linux_args[count++] = grub_strdup("loglevel=7"); + } + + ventoy_linux_argc = count; + + if (ventoy_debug) + { + grub_printf("========== bootoption ==========\n"); + for (i = 0; i < count; i++) + { + grub_printf("%s ", ventoy_linux_args[i]); + } + grub_printf("\n================================\n"); + } + + return 0; +} + +static grub_err_t +grub_cmd_extra_initrd_append (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_uint32_t i; + int newclen = 0; + char *pos = NULL; + char *end = NULL; + char buf[256] = {0}; + const char *suffix = NULL; + const char *check_suffix[] = { ".ko", ".ko.zst", ".ko.xz", ".ko.gz" }; + + if (argc != 1) + { + return 1; + } + + if (grub_strstr(argv[0], ".ko")) + { + if (ventoy_check_file_exist("%s", argv[0])) + { + suffix = ""; + } + } + else + { + for (i = 0; i < sizeof(check_suffix) / sizeof(check_suffix[0]); i++) + { + if (ventoy_check_file_exist("%s%s", argv[0], check_suffix[i])) + { + suffix = check_suffix[i]; + break; + } + } + } + + if (!suffix) + { + grub_printf("ko file <%s> not exist\n", argv[0]); + return 0; + } + + for (pos = argv[0]; *pos; pos++) + { + if (*pos == '/') + { + end = pos; + } + } + + if (end) + { + /* grub2 newc bug workaround */ + newclen = (int)grub_strlen(end + 1); + if ((110 + newclen) % 4 == 0) + { + grub_snprintf(buf, sizeof(buf), "newc:.%s%s:%s%s", end + 1, suffix, argv[0], suffix); + } + else + { + grub_snprintf(buf, sizeof(buf), "newc:%s%s:%s%s", end + 1, suffix, argv[0], suffix); + } + + if (ventoy_extra_initrd_num < 256) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf); + } + } + + return 0; +} + + +static grub_err_t +grub_cmd_extra_initrd_reset (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + + (void)argc; + (void)argv; + + for (i = 0; i < ventoy_extra_initrd_num; i++) + { + if (ventoy_extra_initrd_list[i]) + { + grub_free(ventoy_extra_initrd_list[i]); + } + } + + grub_memset(ventoy_extra_initrd_list, 0, sizeof(ventoy_extra_initrd_list)); + + return 0; +} + + +static grub_err_t +grub_linux_boot (void) +{ + grub_err_t err = 0; + const char *modevar; + char *tmp; + struct grub_relocator32_state state; + void *real_mode_mem; + struct grub_linux_boot_ctx ctx = { + .real_mode_target = 0 + }; + grub_size_t mmap_size; + grub_size_t cl_offset; + + /* To be simple, just deny to boot linux kernel when SecureBoot is enabled and Policy is check */ + if (g_sys_sb && g_sb_policy == VTOY_SB_POLICY_CHECK) + { + grub_printf("\n\n ######### Can not do linux boot in SecureBoot Policy Check #######\n\n"); + grub_refresh(); + grub_sleep(5); + grub_errno = GRUB_ERR_BAD_SIGNATURE; + return 0; + } + + ventoy_preboot(); + +#ifdef GRUB_MACHINE_IEEE1275 + { + const char *bootpath; + grub_ssize_t len; + + bootpath = grub_env_get ("root"); + if (bootpath) + grub_ieee1275_set_property (grub_ieee1275_chosen, + "bootpath", bootpath, + grub_strlen (bootpath) + 1, + &len); + linux_params.ofw_signature = GRUB_LINUX_OFW_SIGNATURE; + linux_params.ofw_num_items = 1; + linux_params.ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn; + linux_params.ofw_idt = 0; + } +#endif + + modevar = grub_env_get ("gfxpayload"); + + /* Now all graphical modes are acceptable. + May change in future if we have modes without framebuffer. */ + if (modevar && *modevar != 0) + { + tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); + if (! tmp) + return grub_errno; +#if ACCEPTS_PURE_TEXT + err = grub_video_set_mode (tmp, 0, 0); +#else + err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); +#endif + grub_free (tmp); + } + else /* We can't go back to text mode from coreboot fb. */ +#ifdef GRUB_MACHINE_COREBOOT + if (grub_video_get_driver_id () == GRUB_VIDEO_DRIVER_COREBOOT) + err = GRUB_ERR_NONE; + else +#endif + { +#if ACCEPTS_PURE_TEXT + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); +#else + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); +#endif + } + + if (err) + { + grub_print_error (); + grub_puts_ (N_("Booting in blind mode")); + grub_errno = GRUB_ERR_NONE; + } + + if (grub_linux_setup_video (&linux_params)) + { +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) + linux_params.have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT; + linux_params.video_mode = 0x3; +#else + linux_params.have_vga = 0; + linux_params.video_mode = 0; + linux_params.video_width = 0; + linux_params.video_height = 0; +#endif + } + + +#ifndef GRUB_MACHINE_IEEE1275 + if (linux_params.have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT) +#endif + { + grub_term_output_t term; + int found = 0; + FOR_ACTIVE_TERM_OUTPUTS(term) + if (grub_strcmp (term->name, "vga_text") == 0 + || grub_strcmp (term->name, "console") == 0 + || grub_strcmp (term->name, "ofconsole") == 0) + { + struct grub_term_coordinate pos = grub_term_getxy (term); + linux_params.video_cursor_x = pos.x; + linux_params.video_cursor_y = pos.y; + linux_params.video_width = grub_term_width (term); + linux_params.video_height = grub_term_height (term); + found = 1; + break; + } + if (!found) + { + linux_params.video_cursor_x = 0; + linux_params.video_cursor_y = 0; + linux_params.video_width = 80; + linux_params.video_height = 25; + } + } + +#ifdef GRUB_KERNEL_USE_RSDP_ADDR + linux_params.acpi_rsdp_addr = grub_le_to_cpu64 (grub_rsdp_addr); +#endif + + mmap_size = find_mmap_size (); + /* Make sure that each size is aligned to a page boundary. */ + cl_offset = ALIGN_UP (mmap_size + sizeof (linux_params), 4096); + if (cl_offset < ((grub_size_t) linux_params.setup_sects << GRUB_DISK_SECTOR_BITS)) + cl_offset = ALIGN_UP ((grub_size_t) (linux_params.setup_sects + << GRUB_DISK_SECTOR_BITS), 4096); + ctx.real_size = ALIGN_UP (cl_offset + maximal_cmdline_size, 4096); + +#ifdef GRUB_MACHINE_EFI + efi_mmap_size = grub_efi_find_mmap_size (); + if (efi_mmap_size == 0) + return grub_errno; +#endif + + grub_dprintf ("linux", "real_size = %x, mmap_size = %x\n", + (unsigned) ctx.real_size, (unsigned) mmap_size); + +#ifdef GRUB_MACHINE_EFI + grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 1); + if (! ctx.real_mode_target) + grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 0); +#else + grub_mmap_iterate (grub_linux_boot_mmap_find, &ctx); +#endif + grub_dprintf ("linux", "real_mode_target = %lx, real_size = %x, efi_mmap_size = %x\n", + (unsigned long) ctx.real_mode_target, + (unsigned) ctx.real_size, + (unsigned) efi_mmap_size); + + if (! ctx.real_mode_target) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + ctx.real_mode_target, + (ctx.real_size + efi_mmap_size)); + if (err) + return err; + real_mode_mem = get_virtual_current_address (ch); + } + efi_mmap_buf = (grub_uint8_t *) real_mode_mem + ctx.real_size; + + grub_dprintf ("linux", "real_mode_mem = %p\n", + real_mode_mem); + + ctx.params = real_mode_mem; + + *ctx.params = linux_params; + ctx.params->cmd_line_ptr = ctx.real_mode_target + cl_offset; + grub_memcpy ((char *) ctx.params + cl_offset, linux_cmdline, + maximal_cmdline_size); + + grub_dprintf ("linux", "code32_start = %x\n", + (unsigned) ctx.params->code32_start); + + ctx.e820_num = 0; + if (grub_mmap_iterate (grub_linux_boot_mmap_fill, &ctx)) + return grub_errno; + ctx.params->mmap_size = ctx.e820_num; + +#ifdef GRUB_MACHINE_EFI + { + grub_efi_uintn_t efi_desc_size; + grub_size_t efi_mmap_target; + grub_efi_uint32_t efi_desc_version; + err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL, + &efi_desc_size, &efi_desc_version); + if (err) + return err; + + /* Note that no boot services are available from here. */ + efi_mmap_target = ctx.real_mode_target + + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem); + /* Pass EFI parameters. */ + if (grub_le_to_cpu16 (ctx.params->version) >= 0x0208) + { + ctx.params->v0208.efi_mem_desc_size = efi_desc_size; + ctx.params->v0208.efi_mem_desc_version = efi_desc_version; + ctx.params->v0208.efi_mmap = efi_mmap_target; + ctx.params->v0208.efi_mmap_size = efi_mmap_size; + +#ifdef __x86_64__ + ctx.params->v0208.efi_mmap_hi = (efi_mmap_target >> 32); +#endif + } + else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0206) + { + ctx.params->v0206.efi_mem_desc_size = efi_desc_size; + ctx.params->v0206.efi_mem_desc_version = efi_desc_version; + ctx.params->v0206.efi_mmap = efi_mmap_target; + ctx.params->v0206.efi_mmap_size = efi_mmap_size; + } + else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0204) + { + ctx.params->v0204.efi_mem_desc_size = efi_desc_size; + ctx.params->v0204.efi_mem_desc_version = efi_desc_version; + ctx.params->v0204.efi_mmap = efi_mmap_target; + ctx.params->v0204.efi_mmap_size = efi_mmap_size; + } + } +#endif + + /* FIXME. */ + /* asm volatile ("lidt %0" : : "m" (idt_desc)); */ + state.ebp = state.edi = state.ebx = 0; + state.esi = ctx.real_mode_target; + state.esp = ctx.real_mode_target; + state.eip = ctx.params->code32_start; + return grub_relocator32_boot (relocator, state, 0); +} + +static grub_err_t +grub_linux_unload (void) +{ + grub_dl_unref (my_mod); + loaded = 0; + grub_free (linux_cmdline); + linux_cmdline = 0; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + struct linux_i386_kernel_header lh; + grub_uint8_t setup_sects; + grub_size_t real_size, prot_size, prot_file_size; + grub_ssize_t len; + int i; + grub_size_t align, min_align; + int relocatable; + grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR; + + grub_dl_ref (my_mod); + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + goto fail; + } + + file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (! file) + goto fail; + + if (ventoy_linux_argc) + { + const char *tip = grub_env_get("ventoy_loading_tip"); + if (tip) + { + grub_printf("%s\n", tip); + grub_refresh(); + } + } + + if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + argv[0]); + goto fail; + } + + if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)) + { + grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); + goto fail; + } + + if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) + { + grub_error (GRUB_ERR_BAD_OS, "too many setup sectors"); + goto fail; + } + + /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and + still not support 32-bit boot. */ + if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE) + || grub_le_to_cpu16 (lh.version) < 0x0203) + { + grub_error (GRUB_ERR_BAD_OS, "version too old for 32-bit boot" +#ifdef GRUB_MACHINE_PCBIOS + " (try with `linux16')" +#endif + ); + goto fail; + } + + if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL)) + { + grub_error (GRUB_ERR_BAD_OS, "zImage doesn't support 32-bit boot" +#ifdef GRUB_MACHINE_PCBIOS + " (try with `linux16')" +#endif + ); + goto fail; + } + + if (grub_le_to_cpu16 (lh.version) >= 0x0206) + maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1; + else + maximal_cmdline_size = 256; + + if (maximal_cmdline_size < 128) + maximal_cmdline_size = 128; + + setup_sects = lh.setup_sects; + + /* If SETUP_SECTS is not set, set it to the default (4). */ + if (! setup_sects) + setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; + + real_size = setup_sects << GRUB_DISK_SECTOR_BITS; + prot_file_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; + + if (grub_le_to_cpu16 (lh.version) >= 0x205 + && lh.kernel_alignment != 0 + && ((lh.kernel_alignment - 1) & lh.kernel_alignment) == 0) + { + for (align = 0; align < 32; align++) + if (grub_le_to_cpu32 (lh.kernel_alignment) & (1 << align)) + break; + relocatable = grub_le_to_cpu32 (lh.relocatable); + } + else + { + align = 0; + relocatable = 0; + } + + if (grub_le_to_cpu16 (lh.version) >= 0x020a) + { + min_align = lh.min_alignment; + prot_size = grub_le_to_cpu32 (lh.init_size); + prot_init_space = page_align (prot_size); + if (relocatable) + preferred_address = grub_le_to_cpu64 (lh.pref_address); + else + preferred_address = GRUB_LINUX_BZIMAGE_ADDR; + } + else + { + min_align = align; + prot_size = prot_file_size; + preferred_address = GRUB_LINUX_BZIMAGE_ADDR; + /* Usually, the compression ratio is about 50%. */ + prot_init_space = page_align (prot_size) * 3; + } + + if (allocate_pages (prot_size, &align, + min_align, relocatable, + preferred_address)) + goto fail; + + grub_memset (&linux_params, 0, sizeof (linux_params)); + grub_memcpy (&linux_params.setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1); + + linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; + linux_params.kernel_alignment = (1 << align); + linux_params.ps_mouse = linux_params.padding10 = 0; + + /* + * The Linux 32-bit boot protocol defines the setup header end + * to be at 0x202 + the byte value at 0x201. + */ + len = 0x202 + *((char *) &linux_params.jump + 1); + + /* Verify the struct is big enough so we do not write past the end. */ + if (len > (char *) &linux_params.edd_mbr_sig_buffer - (char *) &linux_params) { + grub_error (GRUB_ERR_BAD_OS, "Linux setup header too big"); + goto fail; + } + + /* We've already read lh so there is no need to read it second time. */ + len -= sizeof(lh); + + if (grub_file_read (file, (char *) &linux_params + sizeof (lh), len) != len) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + argv[0]); + goto fail; + } + + linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE; + + /* These two are used (instead of cmd_line_ptr) by older versions of Linux, + and otherwise ignored. */ + linux_params.cl_magic = GRUB_LINUX_CL_MAGIC; + linux_params.cl_offset = 0x1000; + + linux_params.ramdisk_image = 0; + linux_params.ramdisk_size = 0; + + linux_params.heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET; + linux_params.loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP; + + /* These are not needed to be precise, because Linux uses these values + only to raise an error when the decompression code cannot find good + space. */ + linux_params.ext_mem = ((32 * 0x100000) >> 10); + linux_params.alt_mem = ((32 * 0x100000) >> 10); + + /* Ignored by Linux. */ + linux_params.video_page = 0; + + /* Only used when `video_mode == 0x7', otherwise ignored. */ + linux_params.video_ega_bx = 0; + + linux_params.font_size = 16; /* XXX */ + +#ifdef GRUB_MACHINE_EFI +#ifdef __x86_64__ + if (grub_le_to_cpu16 (linux_params.version) < 0x0208 && + ((grub_addr_t) grub_efi_system_table >> 32) != 0) + return grub_error(GRUB_ERR_BAD_OS, + "kernel does not support 64-bit addressing"); +#endif + + if (grub_le_to_cpu16 (linux_params.version) >= 0x0208) + { + linux_params.v0208.efi_signature = GRUB_LINUX_EFI_SIGNATURE; + linux_params.v0208.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table; +#ifdef __x86_64__ + linux_params.v0208.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32); +#endif + } + else if (grub_le_to_cpu16 (linux_params.version) >= 0x0206) + { + linux_params.v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE; + linux_params.v0206.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table; + } + else if (grub_le_to_cpu16 (linux_params.version) >= 0x0204) + { + linux_params.v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204; + linux_params.v0204.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table; + } +#endif + + /* The other parameters are filled when booting. */ + + grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); + + grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n", + (unsigned) real_size, (unsigned) prot_size); + + /* Look for memory size and video mode specified on the command line. */ + linux_mem_size = 0; + for (i = 1; i < argc; i++) +#ifdef GRUB_MACHINE_PCBIOS + if (grub_memcmp (argv[i], "vga=", 4) == 0 && (grub_memcmp (argv[i], "vga=current", 11) != 0)) + { + /* Video mode selection support. */ + char *val = argv[i] + 4; + unsigned vid_mode = GRUB_LINUX_VID_MODE_NORMAL; + struct grub_vesa_mode_table_entry *linux_mode; + grub_err_t err; + char *buf; + + grub_dl_load ("vbe"); + + if (grub_strcmp (val, "normal") == 0) + vid_mode = GRUB_LINUX_VID_MODE_NORMAL; + else if (grub_strcmp (val, "ext") == 0) + vid_mode = GRUB_LINUX_VID_MODE_EXTENDED; + else if (grub_strcmp (val, "ask") == 0) + { + grub_puts_ (N_("Legacy `ask' parameter no longer supported.")); + + /* We usually would never do this in a loader, but "vga=ask" means user + requested interaction, so it can't hurt to request keyboard input. */ + grub_wait_after_message (); + + goto fail; + } + else + vid_mode = (grub_uint16_t) grub_strtoul (val, 0, 0); + + switch (vid_mode) + { + case 0: + case GRUB_LINUX_VID_MODE_NORMAL: + grub_env_set ("gfxpayload", "text"); + grub_printf_ (N_("%s is deprecated. " + "Use set gfxpayload=%s before " + "linux command instead.\n"), + argv[i], "text"); + break; + + case 1: + case GRUB_LINUX_VID_MODE_EXTENDED: + /* FIXME: support 80x50 text. */ + grub_env_set ("gfxpayload", "text"); + grub_printf_ (N_("%s is deprecated. " + "Use set gfxpayload=%s before " + "linux command instead.\n"), + argv[i], "text"); + break; + default: + /* Ignore invalid values. */ + if (vid_mode < GRUB_VESA_MODE_TABLE_START || + vid_mode > GRUB_VESA_MODE_TABLE_END) + { + grub_env_set ("gfxpayload", "text"); + /* TRANSLATORS: "x" has to be entered in, like an identifier, + so please don't use better Unicode codepoints. */ + grub_printf_ (N_("%s is deprecated. VGA mode %d isn't recognized. " + "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] " + "before linux command instead.\n"), + argv[i], vid_mode); + break; + } + + linux_mode = &grub_vesa_mode_table[vid_mode + - GRUB_VESA_MODE_TABLE_START]; + + buf = grub_xasprintf ("%ux%ux%u,%ux%u", + linux_mode->width, linux_mode->height, + linux_mode->depth, + linux_mode->width, linux_mode->height); + if (! buf) + goto fail; + + grub_printf_ (N_("%s is deprecated. " + "Use set gfxpayload=%s before " + "linux command instead.\n"), + argv[i], buf); + err = grub_env_set ("gfxpayload", buf); + grub_free (buf); + if (err) + goto fail; + } + } + else +#endif /* GRUB_MACHINE_PCBIOS */ + if (grub_memcmp (argv[i], "mem=", 4) == 0) + { + char *val = argv[i] + 4; + + linux_mem_size = grub_strtoul (val, &val, 0); + + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; + linux_mem_size = 0; + } + else + { + int shift = 0; + + switch (grub_tolower (val[0])) + { + case 'g': + shift += 10; + /* FALLTHROUGH */ + case 'm': + shift += 10; + /* FALLTHROUGH */ + case 'k': + shift += 10; + /* FALLTHROUGH */ + default: + break; + } + + /* Check an overflow. */ + if (linux_mem_size > (~0UL >> shift)) + linux_mem_size = 0; + else + linux_mem_size <<= shift; + } + } + else if (grub_memcmp (argv[i], "quiet", sizeof ("quiet") - 1) == 0) + { + linux_params.loadflags |= GRUB_LINUX_FLAG_QUIET; + } + + /* Create kernel command line. */ + linux_cmdline = grub_zalloc (maximal_cmdline_size + 1); + if (!linux_cmdline) + goto fail; + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + { + grub_err_t err; + + if (ventoy_linux_argc) + { + ventoy_bootopt_hook(argc, argv); + err = grub_create_loader_cmdline (ventoy_linux_argc, ventoy_linux_args, + linux_cmdline + + sizeof (LINUX_IMAGE) - 1, + maximal_cmdline_size + - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + } + else + { + err = grub_create_loader_cmdline (argc, argv, + linux_cmdline + + sizeof (LINUX_IMAGE) - 1, + maximal_cmdline_size + - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + } + + if (err) + goto fail; + } + + len = prot_file_size; + if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + argv[0]); + + if (grub_errno == GRUB_ERR_NONE) + { + grub_loader_set (grub_linux_boot, grub_linux_unload, + 0 /* set noreturn=0 in order to avoid grub_console_fini() */); + loaded = 1; + } + + fail: + + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_dl_unref (my_mod); + loaded = 0; + } + + return grub_errno; +} + +static grub_err_t +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_size_t size = 0, aligned_size = 0; + grub_addr_t addr_min, addr_max; + grub_addr_t addr; + grub_err_t err; + struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + goto fail; + } + + if (! loaded) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); + goto fail; + } + + if (grub_initrd_init (argc, argv, &initrd_ctx)) + goto fail; + + size = grub_get_initrd_size (&initrd_ctx); + aligned_size = ALIGN_UP (size, 4096); + + /* Get the highest address available for the initrd. */ + if (grub_le_to_cpu16 (linux_params.version) >= 0x0203) + { + addr_max = grub_cpu_to_le32 (linux_params.initrd_addr_max); + + /* XXX in reality, Linux specifies a bogus value, so + it is necessary to make sure that ADDR_MAX does not exceed + 0x3fffffff. */ + if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS) + addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS; + } + else + addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS; + + if (linux_mem_size != 0 && linux_mem_size < addr_max) + addr_max = linux_mem_size; + + /* Linux 2.3.xx has a bug in the memory range check, so avoid + the last page. + Linux 2.2.xx has a bug in the memory range check, which is + worse than that of Linux 2.3.xx, so avoid the last 64kb. */ + addr_max -= 0x10000; + + addr_min = (grub_addr_t) prot_mode_target + prot_init_space; + + /* Put the initrd as high as possible, 4KiB aligned. */ + addr = (addr_max - aligned_size) & ~0xFFF; + + if (addr < addr_min) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big"); + goto fail; + } + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + addr_min, addr, aligned_size, + 0x1000, + GRUB_RELOCATOR_PREFERENCE_HIGH, + 1); + if (err) + return err; + initrd_mem = get_virtual_current_address (ch); + initrd_mem_target = get_physical_target_address (ch); + } + + if (grub_initrd_load (&initrd_ctx, argv, initrd_mem)) + goto fail; + + grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n", + (unsigned) addr, (unsigned) size); + + linux_params.ramdisk_image = initrd_mem_target; + linux_params.ramdisk_size = size; + linux_params.root_dev = 0x0100; /* XXX */ + + fail: + grub_initrd_close (&initrd_ctx); + + return grub_errno; +} + +static grub_err_t +ventoy_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + const char *file; + char buf[64]; + + if (ventoy_debug) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc); + + if (ventoy_linux_argc == 0) + { + return grub_cmd_initrd(cmd, argc, argv); + } + + grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size")); + + if (ventoy_debug) grub_printf("membuf=%s\n", buf); + + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf); + + file = grub_env_get("vtoy_img_part_file"); + if (file) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file); + } + + for (i = 0; i < argc; i++) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(argv[i]); + } + + ventoy_initrd_called = 1; + + if (ventoy_debug) + { + grub_printf("========== initrd list ==========\n"); + for (i = 0; i < ventoy_extra_initrd_num; i++) + { + grub_printf("%s\n", ventoy_extra_initrd_list[i]); + } + grub_printf("=================================\n"); + } + + return grub_cmd_initrd(cmd, ventoy_extra_initrd_num, ventoy_extra_initrd_list); +} + +static grub_err_t +grub_cmd_set_boot_opt (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + const char *vtdebug; + grub_command_t regcmd; + + for (i = 0; i < argc; i++) + { + ventoy_linux_args[ventoy_linux_argc + (LINUX_MAX_ARGC / 2) ] = grub_strdup(argv[i]); + ventoy_linux_argc++; + } + + vtdebug = grub_env_get("vtdebug_flag"); + if (vtdebug && vtdebug[0]) + { + ventoy_debug = 1; + } + + if (ventoy_debug) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc); + + ventoy_linux16_func = ventoy_initrd16_func = NULL; + regcmd = grub_command_find("linux16"); + if (regcmd) + { + ventoy_linux16_func = regcmd->func; + regcmd->func = grub_cmd_linux; + } + + regcmd = grub_command_find("initrd16"); + if (regcmd) + { + ventoy_initrd16_func = regcmd->func; + regcmd->func = ventoy_cmd_initrd; + } + + return 0; +} + +static grub_err_t +grub_cmd_unset_boot_opt (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + grub_command_t regcmd; + + (void)argc; + (void)argv; + + for (i = 0; i < LINUX_MAX_ARGC; i++) + { + if (ventoy_linux_args[i]) + { + grub_free(ventoy_linux_args[i]); + } + } + + ventoy_debug = 0; + ventoy_linux_argc = 0; + ventoy_initrd_called = 0; + grub_memset(ventoy_linux_args, 0, sizeof(char *) * LINUX_MAX_ARGC); + + if (ventoy_linux16_func) + { + regcmd = grub_command_find("linux16"); + if (regcmd) + { + regcmd->func = ventoy_linux16_func; + } + ventoy_linux16_func = NULL; + } + + if (ventoy_initrd16_func) + { + regcmd = grub_command_find("initrd16"); + if (regcmd) + { + regcmd->func = ventoy_initrd16_func; + } + ventoy_initrd16_func = NULL; + } + + return 0; +} + + +static grub_command_t cmd_linux, cmd_initrd, cmd_linuxefi, cmd_initrdefi; +static grub_command_t cmd_set_bootopt, cmd_unset_bootopt, cmd_extra_initrd_append, cmd_extra_initrd_reset; + +GRUB_MOD_INIT(linux) +{ + cmd_linux = grub_register_command ("linux", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", ventoy_cmd_initrd, + 0, N_("Load initrd.")); + + cmd_linuxefi = grub_register_command ("linuxefi", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrdefi = grub_register_command ("initrdefi", ventoy_cmd_initrd, + 0, N_("Load initrd.")); + cmd_set_bootopt = grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt, 0, N_("set ext boot opt")); + cmd_unset_bootopt = grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt, 0, N_("unset ext boot opt")); + + cmd_extra_initrd_append = grub_register_command ("vt_img_extra_initrd_append", grub_cmd_extra_initrd_append, 0, N_("")); + cmd_extra_initrd_reset = grub_register_command ("vt_img_extra_initrd_reset", grub_cmd_extra_initrd_reset, 0, N_("")); + + ventoy_linux_args = grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC); + + my_mod = mod; +} + +GRUB_MOD_FINI(linux) +{ + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/linux.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/linux.c new file mode 100644 index 0000000..f497585 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/linux.c @@ -0,0 +1,327 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct newc_head +{ + char magic[6]; + char ino[8]; + char mode[8]; + char uid[8]; + char gid[8]; + char nlink[8]; + char mtime[8]; + char filesize[8]; + char devmajor[8]; + char devminor[8]; + char rdevmajor[8]; + char rdevminor[8]; + char namesize[8]; + char check[8]; +} GRUB_PACKED; + +struct grub_linux_initrd_component +{ + grub_file_t file; + char *newc_name; + grub_off_t size; +}; + +struct dir +{ + char *name; + struct dir *next; + struct dir *child; +}; + +static char +hex (grub_uint8_t val) +{ + if (val < 10) + return '0' + val; + return 'a' + val - 10; +} + +static void +set_field (char *var, grub_uint32_t val) +{ + int i; + char *ptr = var; + for (i = 28; i >= 0; i -= 4) + *ptr++ = hex((val >> i) & 0xf); +} + +static grub_uint8_t * +make_header (grub_uint8_t *ptr, + const char *name, grub_size_t len, + grub_uint32_t mode, + grub_off_t fsize) +{ + struct newc_head *head = (struct newc_head *) ptr; + grub_uint8_t *optr; + grub_size_t oh = 0; + grub_memcpy (head->magic, "070701", 6); + set_field (head->ino, 0); + set_field (head->mode, mode); + set_field (head->uid, 0); + set_field (head->gid, 0); + set_field (head->nlink, 1); + set_field (head->mtime, 0); + set_field (head->filesize, fsize); + set_field (head->devmajor, 0); + set_field (head->devminor, 0); + set_field (head->rdevmajor, 0); + set_field (head->rdevminor, 0); + set_field (head->namesize, len); + set_field (head->check, 0); + optr = ptr; + ptr += sizeof (struct newc_head); + grub_memcpy (ptr, name, len); + ptr += len; + oh = ALIGN_UP_OVERHEAD (ptr - optr, 4); + grub_memset (ptr, 0, oh); + ptr += oh; + return ptr; +} + +static void +free_dir (struct dir *root) +{ + if (!root) + return; + free_dir (root->next); + free_dir (root->child); + grub_free (root->name); + grub_free (root); +} + +static grub_size_t +insert_dir (const char *name, struct dir **root, + grub_uint8_t *ptr) +{ + struct dir *cur, **head = root; + const char *cb, *ce = name; + grub_size_t size = 0; + while (1) + { + for (cb = ce; *cb == '/'; cb++); + for (ce = cb; *ce && *ce != '/'; ce++); + if (!*ce) + break; + + for (cur = *root; cur; cur = cur->next) + if (grub_memcmp (cur->name, cb, ce - cb) + && cur->name[ce - cb] == 0) + break; + if (!cur) + { + struct dir *n; + n = grub_zalloc (sizeof (*n)); + if (!n) + return 0; + n->next = *head; + n->name = grub_strndup (cb, ce - cb); + if (ptr) + { + /* + * Create the substring with the trailing NUL byte + * to be included in the cpio header. + */ + char *tmp_name = grub_strndup (name, ce - name); + if (!tmp_name) { + grub_free (n->name); + grub_free (n); + return grub_errno; + } + grub_dprintf ("linux", "Creating directory %s, %s\n", name, ce); + ptr = make_header (ptr, tmp_name, ce - name + 1, + 040777, 0); + grub_free (tmp_name); + } + size += ALIGN_UP ((ce - (char *) name + 1) + + sizeof (struct newc_head), 4); + *head = n; + cur = n; + } + root = &cur->next; + } + return size; +} + +grub_err_t +grub_initrd_init (int argc, char *argv[], + struct grub_linux_initrd_context *initrd_ctx) +{ + int i; + int newc = 0; + struct dir *root = 0; + + initrd_ctx->nfiles = 0; + initrd_ctx->components = 0; + + initrd_ctx->components = grub_zalloc (argc + * sizeof (initrd_ctx->components[0])); + if (!initrd_ctx->components) + return grub_errno; + + initrd_ctx->size = 0; + + for (i = 0; i < argc; i++) + { + const char *fname = argv[i]; + + initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4); + + if (grub_memcmp (argv[i], "newc:", 5) == 0) + { + const char *ptr, *eptr; + ptr = argv[i] + 5; + while (*ptr == '/') + ptr++; + eptr = grub_strchr (ptr, ':'); + if (eptr) + { + initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr); + if (!initrd_ctx->components[i].newc_name) + { + grub_initrd_close (initrd_ctx); + return grub_errno; + } + initrd_ctx->size + += ALIGN_UP (sizeof (struct newc_head) + + grub_strlen (initrd_ctx->components[i].newc_name) + 1, + 4); + initrd_ctx->size += insert_dir (initrd_ctx->components[i].newc_name, + &root, 0); + newc = 1; + fname = eptr + 1; + } + } + else if (newc) + { + initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head) + + sizeof ("TRAILER!!!"), 4); + free_dir (root); + root = 0; + newc = 0; + } + initrd_ctx->components[i].file = grub_file_open (fname, + GRUB_FILE_TYPE_LINUX_INITRD + | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (!initrd_ctx->components[i].file) + { + grub_initrd_close (initrd_ctx); + return grub_errno; + } + initrd_ctx->nfiles++; + initrd_ctx->components[i].size + = grub_file_size (initrd_ctx->components[i].file); + initrd_ctx->size += initrd_ctx->components[i].size; + } + + if (newc) + { + initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4); + initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head) + + sizeof ("TRAILER!!!"), 4); + free_dir (root); + root = 0; + } + + return GRUB_ERR_NONE; +} + +grub_size_t +grub_get_initrd_size (struct grub_linux_initrd_context *initrd_ctx) +{ + return initrd_ctx->size; +} + +void +grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx) +{ + int i; + if (!initrd_ctx->components) + return; + for (i = 0; i < initrd_ctx->nfiles; i++) + { + grub_free (initrd_ctx->components[i].newc_name); + grub_file_close (initrd_ctx->components[i].file); + } + grub_free (initrd_ctx->components); + initrd_ctx->components = 0; +} + +extern int ventoy_need_prompt_load_file(void); +extern grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size); +grub_err_t +grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx, + char *argv[], void *target) +{ + grub_uint8_t *ptr = target; + int i; + int newc = 0; + struct dir *root = 0; + grub_ssize_t cursize = 0; + grub_ssize_t readsize = 0; + + for (i = 0; i < initrd_ctx->nfiles; i++) + { + grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4)); + ptr += ALIGN_UP_OVERHEAD (cursize, 4); + + if (initrd_ctx->components[i].newc_name) + { + ptr += insert_dir (initrd_ctx->components[i].newc_name, + &root, ptr); + ptr = make_header (ptr, initrd_ctx->components[i].newc_name, + grub_strlen (initrd_ctx->components[i].newc_name) + 1, + 0100777, + initrd_ctx->components[i].size); + newc = 1; + } + else if (newc) + { + ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"), + 0, 0); + free_dir (root); + root = 0; + newc = 0; + } + + cursize = initrd_ctx->components[i].size; + if (ventoy_need_prompt_load_file() && initrd_ctx->components[i].newc_name && + grub_strcmp(initrd_ctx->components[i].newc_name, "boot.wim") == 0) + { + readsize = ventoy_load_file_with_prompt(initrd_ctx->components[i].file, ptr, cursize); + } + else + { + readsize = grub_file_read (initrd_ctx->components[i].file, ptr, cursize); + } + + if (readsize != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), + argv[i]); + grub_initrd_close (initrd_ctx); + return grub_errno; + } + ptr += cursize; + } + if (newc) + { + grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4)); + ptr += ALIGN_UP_OVERHEAD (cursize, 4); + ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"), 0, 0); + } + free_dir (root); + root = 0; + return GRUB_ERR_NONE; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/mips64/linux.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/mips64/linux.c new file mode 100644 index 0000000..5f04463 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/loader/mips64/linux.c @@ -0,0 +1,1069 @@ +/* linux.c - boot Linux */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,2007,2009,2010,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define _ull unsigned long long +#pragma GCC diagnostic ignored "-Wcast-align" + +typedef unsigned long size_t; + +static grub_dl_t my_mod; + +static int loaded; + +static grub_uint32_t tmp_index = 0; +static grub_size_t linux_size; + +static struct grub_relocator *relocator; +static grub_addr_t target_addr, entry_addr; +static int linux_argc; +static grub_uint8_t *linux_args_addr; +static grub_off_t rd_addr_arg_off, rd_size_arg_off; +static int initrd_loaded = 0; + + +static grub_uint32_t j = 0; +static grub_uint32_t t = 0; +grub_uint64_t tempMemsize = 0; +grub_uint32_t free_index = 0; +grub_uint32_t reserve_index = 0; +grub_uint32_t acpi_table_index = 0; +grub_uint32_t acpi_nvs_index = 0; + +#define LINUX_MAX_ARGC 1024 +static int ventoy_debug = 0; +static int ventoy_initrd_called = 0; +static int ventoy_linux_argc = 0; +static char **ventoy_linux_args = NULL; +static int ventoy_extra_initrd_num = 0; +static char *ventoy_extra_initrd_list[256]; +static grub_err_t +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]); + + + +static inline grub_size_t +page_align (grub_size_t size) +{ + return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); +} + +/* Find the optimal number of pages for the memory map. Is it better to + move this code to efi/mm.c? */ +static grub_efi_uintn_t +find_mmap_size (void) +{ + static grub_efi_uintn_t mmap_size = 0; + + if (mmap_size != 0) + return mmap_size; + + mmap_size = (1 << 12); + while (1) + { + int ret; + grub_efi_memory_descriptor_t *mmap; + grub_efi_uintn_t desc_size; + + mmap = grub_malloc (mmap_size); + if (! mmap) + return 0; + + ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); + grub_free (mmap); + + if (ret < 0) + { + grub_error (GRUB_ERR_IO, "cannot get memory map"); + return 0; + } + else if (ret > 0) + break; + + mmap_size += (1 << 12); + } + + + /* Increase the size a bit for safety, because GRUB allocates more on + later, and EFI itself may allocate more. */ + mmap_size += (1 << 12); + + return page_align (mmap_size); +} + + +static void ventoy_debug_pause(void) +{ + char key; + + if (0 == ventoy_debug) + { + return; + } + + grub_printf("press Enter to continue ......\n"); + while (1) + { + key = grub_getkey(); + if (key == '\n' || key == '\r') + { + break; + } + } +} + +static int ventoy_preboot(void) +{ + int i; + const char *file; + char buf[128]; + + if (ventoy_debug) + { + grub_printf("ventoy_preboot %d %d\n", ventoy_linux_argc, ventoy_initrd_called); + ventoy_debug_pause(); + } + + if (ventoy_linux_argc == 0) + { + return 0; + } + + if (ventoy_initrd_called) + { + ventoy_initrd_called = 0; + return 0; + } + + grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size")); + + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf); + + file = grub_env_get("vtoy_img_part_file"); + if (file) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file); + } + + if (ventoy_debug) + { + grub_printf("========== initrd list ==========\n"); + for (i = 0; i < ventoy_extra_initrd_num; i++) + { + grub_printf("%s\n", ventoy_extra_initrd_list[i]); + } + grub_printf("=================================\n"); + + ventoy_debug_pause(); + } + + grub_cmd_initrd(NULL, ventoy_extra_initrd_num, ventoy_extra_initrd_list); + + return 0; +} + +static int ventoy_boot_opt_filter(char *opt) +{ + if (grub_strcmp(opt, "noinitrd") == 0) + { + return 1; + } + + if (grub_strcmp(opt, "vga=current") == 0) + { + return 1; + } + + if (grub_strncmp(opt, "rdinit=", 7) == 0) + { + if (grub_strcmp(opt, "rdinit=/vtoy/vtoy") != 0) + { + opt[0] = 'v'; + opt[1] = 't'; + } + return 0; + } + + if (grub_strncmp(opt, "init=", 5) == 0) + { + opt[0] = 'v'; + opt[1] = 't'; + return 0; + } + + if (grub_strncmp(opt, "dm=", 3) == 0) + { + opt[0] = 'D'; + opt[1] = 'M'; + return 0; + } + + if (ventoy_debug) + { + if (grub_strcmp(opt, "quiet") == 0) + { + return 1; + } + + if (grub_strncmp(opt, "loglevel=", 9) == 0) + { + return 1; + } + + if (grub_strcmp(opt, "splash") == 0) + { + return 1; + } + } + + return 0; +} + +static int ventoy_bootopt_hook(int argc, char *argv[]) +{ + int i; + int TmpIdx; + int count = 0; + const char *env; + char c; + char *newenv; + char *last, *pos; + + //grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc); + + if (ventoy_linux_argc == 0) + { + return 0; + } + + /* To avoid --- parameter, we split two parts */ + for (TmpIdx = 0; TmpIdx < argc; TmpIdx++) + { + if (ventoy_boot_opt_filter(argv[TmpIdx])) + { + continue; + } + + if (grub_strncmp(argv[TmpIdx], "--", 2) == 0) + { + break; + } + + ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]); + } + + for (i = 0; i < ventoy_linux_argc; i++) + { + ventoy_linux_args[count] = ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)]; + ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)] = NULL; + + if (ventoy_linux_args[count][0] == '@') + { + env = grub_env_get(ventoy_linux_args[count] + 1); + if (env) + { + grub_free(ventoy_linux_args[count]); + + newenv = grub_strdup(env); + last = newenv; + + while (*last) + { + while (*last) + { + if (*last != ' ' && *last != '\t') + { + break; + } + last++; + } + + if (*last == 0) + { + break; + } + + for (pos = last; *pos; pos++) + { + if (*pos == ' ' || *pos == '\t') + { + c = *pos; + *pos = 0; + if (0 == ventoy_boot_opt_filter(last)) + { + ventoy_linux_args[count++] = grub_strdup(last); + } + *pos = c; + break; + } + } + + if (*pos == 0) + { + if (0 == ventoy_boot_opt_filter(last)) + { + ventoy_linux_args[count++] = grub_strdup(last); + } + break; + } + + last = pos + 1; + } + } + else + { + count++; + } + } + else + { + count++; + } + } + + while (TmpIdx < argc) + { + if (ventoy_boot_opt_filter(argv[TmpIdx])) + { + continue; + } + + ventoy_linux_args[count++] = grub_strdup(argv[TmpIdx]); + TmpIdx++; + } + + if (ventoy_debug) + { + ventoy_linux_args[count++] = grub_strdup("loglevel=7"); + } + + ventoy_linux_argc = count; + + if (ventoy_debug) + { + grub_printf("========== bootoption ==========\n"); + for (i = 0; i < count; i++) + { + grub_printf("%s ", ventoy_linux_args[i]); + } + grub_printf("\n================================\n"); + } + + return 0; +} + +static grub_err_t +grub_cmd_set_boot_opt (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + const char *vtdebug; + + for (i = 0; i < argc; i++) + { + ventoy_linux_args[ventoy_linux_argc + (LINUX_MAX_ARGC / 2) ] = grub_strdup(argv[i]); + ventoy_linux_argc++; + } + + vtdebug = grub_env_get("vtdebug_flag"); + if (vtdebug && vtdebug[0]) + { + ventoy_debug = 1; + } + + if (ventoy_debug) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc); + + return 0; +} + +static grub_err_t +grub_cmd_unset_boot_opt (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + + (void)argc; + (void)argv; + + for (i = 0; i < LINUX_MAX_ARGC; i++) + { + if (ventoy_linux_args[i]) + { + grub_free(ventoy_linux_args[i]); + } + } + + ventoy_debug = 0; + ventoy_linux_argc = 0; + ventoy_initrd_called = 0; + grub_memset(ventoy_linux_args, 0, sizeof(char *) * LINUX_MAX_ARGC); + return 0; +} + +static grub_err_t +grub_cmd_extra_initrd_append (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_uint32_t i; + int newclen = 0; + char *pos = NULL; + char *end = NULL; + char buf[256] = {0}; + const char *suffix = NULL; + const char *check_suffix[] = { ".ko", ".ko.zst", ".ko.xz", ".ko.gz" }; + + if (argc != 1) + { + return 1; + } + + if (grub_strstr(argv[0], ".ko")) + { + if (ventoy_check_file_exist("%s", argv[0])) + { + suffix = ""; + } + } + else + { + for (i = 0; i < sizeof(check_suffix) / sizeof(check_suffix[0]); i++) + { + if (ventoy_check_file_exist("%s%s", argv[0], check_suffix[i])) + { + suffix = check_suffix[i]; + break; + } + } + } + + if (!suffix) + { + grub_printf("ko file <%s> not exist\n", argv[0]); + return 0; + } + + for (pos = argv[0]; *pos; pos++) + { + if (*pos == '/') + { + end = pos; + } + } + + if (end) + { + /* grub2 newc bug workaround */ + newclen = (int)grub_strlen(end + 1); + if ((110 + newclen) % 4 == 0) + { + grub_snprintf(buf, sizeof(buf), "newc:.%s%s:%s%s", end + 1, suffix, argv[0], suffix); + } + else + { + grub_snprintf(buf, sizeof(buf), "newc:%s%s:%s%s", end + 1, suffix, argv[0], suffix); + } + + if (ventoy_extra_initrd_num < 256) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf); + } + } + + return 0; +} + +static grub_err_t +grub_cmd_extra_initrd_reset (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + + (void)argc; + (void)argv; + + for (i = 0; i < ventoy_extra_initrd_num; i++) + { + if (ventoy_extra_initrd_list[i]) + { + grub_free(ventoy_extra_initrd_list[i]); + } + } + + grub_memset(ventoy_extra_initrd_list, 0, sizeof(ventoy_extra_initrd_list)); + + return 0; +} + + +static grub_err_t +grub_linux_boot (void) +{ + struct grub_relocator64_state state; + grub_int8_t checksum = 0; + grub_efi_memory_descriptor_t * lsdesc = NULL; + + ventoy_preboot(); + + grub_memset (&state, 0, sizeof (state)); + + /* Boot the kernel. */ + state.gpr[1] = entry_addr; + grub_dprintf("loongson", "entry_addr is 0x%llx\n", (_ull)state.gpr[1]); + state.gpr[4] = linux_argc; + grub_dprintf("loongson", "linux_argc is %lld\n", (_ull)state.gpr[4]); + state.gpr[5] = (grub_addr_t) linux_args_addr; + grub_dprintf("loongson", "args_addr is 0x%llx\n", (_ull)state.gpr[5]); + + if(grub_efi_is_loongson ()) + { + grub_efi_uintn_t mmap_size; + grub_efi_uintn_t desc_size; + grub_efi_memory_descriptor_t *mmap_buf; + grub_err_t err; + struct bootparamsinterface * boot_params; + void * tmp_boot_params = NULL; + grub_efi_uint8_t new_interface_flag = 0; + mem_map * new_interface_mem = NULL; + char *p = NULL; + + struct memmap reserve_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; + struct memmap free_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; + struct memmap acpi_table_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; + struct memmap acpi_nvs_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; + + grub_memset(reserve_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); + grub_memset(free_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); + grub_memset(acpi_table_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); + grub_memset(acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); + + tmp_boot_params = grub_efi_loongson_get_boot_params(); + if(tmp_boot_params == NULL) + { + grub_printf("not find param\n"); + return -1; + } + + boot_params = (struct bootparamsinterface *)tmp_boot_params; + p = (char *)&(boot_params->signature); + if(grub_strncmp(p, "BPI", 3) == 0) + { + /* Check extlist headers */ + ext_list * listpointer = NULL; + listpointer = boot_params->extlist; + for( ;listpointer != NULL; listpointer = listpointer->next) + { + char *pl= (char *)&(listpointer->signature); + if(grub_strncmp(pl, "MEM", 3) == 0) + { + new_interface_mem = (mem_map *)listpointer; + } + } + + new_interface_flag = 1; + grub_dprintf("loongson", "get new parameter interface\n"); + }else{ + new_interface_flag = 0; + grub_dprintf("loongson", "get old parameter interface\n"); + + } + state.gpr[6] = (grub_uint64_t)tmp_boot_params; + grub_dprintf("loongson", "boot_params is 0x%llx\n", (_ull)state.gpr[6]); + + mmap_size = find_mmap_size (); + if (! mmap_size) + return grub_errno; + mmap_buf = grub_efi_allocate_any_pages (page_align (mmap_size) >> 12); + if (! mmap_buf) + return grub_error (GRUB_ERR_IO, "cannot allocate memory map"); + err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL, + &desc_size, NULL); + //grub_printf("%s-%d\n", __func__, __LINE__); + if (err) + return err; + + if(new_interface_flag) + { + if (!mmap_buf || !mmap_size || !desc_size) + return -1; + + tmp_index = new_interface_mem -> mapcount; + //grub_printf("%s-%d mapcount %d\n", __func__, __LINE__, tmp_index); + + /* + According to UEFI SPEC,mmap_buf is the accurate Memory Map array \ + now we can fill platform specific memory structure. + */ + for(lsdesc = mmap_buf; lsdesc < (grub_efi_memory_descriptor_t *)((char *)mmap_buf + mmap_size); lsdesc = (grub_efi_memory_descriptor_t *)((char *)lsdesc + desc_size)) + { + /* Recovery */ + if((lsdesc->type != GRUB_EFI_ACPI_RECLAIM_MEMORY) && \ + (lsdesc->type != GRUB_EFI_ACPI_MEMORY_NVS) && \ + (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_DATA) && \ + (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_CODE) && \ + (lsdesc->type != GRUB_EFI_RESERVED_MEMORY_TYPE) && \ + (lsdesc->type != GRUB_EFI_PAL_CODE)) + { + + free_mem[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW; + free_mem[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; + free_mem[free_index].memsize = lsdesc->num_pages * 4096; + free_index++; + /*ACPI*/ + }else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){ + acpi_table_mem[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE; + acpi_table_mem[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; + acpi_table_mem[acpi_table_index].memsize = lsdesc->num_pages * 4096; + acpi_table_index++; + + }else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){ + acpi_nvs_mem[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS; + acpi_nvs_mem[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; + acpi_nvs_mem[acpi_nvs_index].memsize = lsdesc->num_pages * 4096; + acpi_nvs_index++; + + /* Reserve */ + }else{ + reserve_mem[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED; + reserve_mem[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; + reserve_mem[reserve_index].memsize = lsdesc->num_pages * 4096; + reserve_index++; + } + } + + /* Recovery sort */ + for(j = 0; j < free_index;) + { + tempMemsize = free_mem[j].memsize; + for(t = j + 1; t < free_index; t++) + { + if((free_mem[j].memstart + tempMemsize == free_mem[t].memstart) && (free_mem[j].memtype == free_mem[t].memtype)) + { + tempMemsize += free_mem[t].memsize; + }else{ + break; + } + } + if(free_mem[j].memstart >= 0x10000000) /*HIGH MEM*/ + new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_HIGH; + else + new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW; + new_interface_mem->map[tmp_index].memstart = free_mem[j].memstart; + new_interface_mem->map[tmp_index].memsize = tempMemsize; + grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", + tmp_index, + new_interface_mem->map[tmp_index].memtype, + (_ull)new_interface_mem->map[tmp_index].memstart, + (_ull)new_interface_mem->map[tmp_index].memstart+ new_interface_mem->map[tmp_index].memsize + ); + j = t; + tmp_index++; + } + + /*ACPI Sort*/ + tmp_index = grub_efi_loongson_memmap_sort(acpi_table_mem, acpi_table_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE); + tmp_index = grub_efi_loongson_memmap_sort(acpi_nvs_mem, acpi_nvs_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS); + /*Reserve Sort*/ + tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED); + + new_interface_mem->mapcount = tmp_index; + new_interface_mem->header.checksum = 0; + //grub_printf("%s-%d mapcount %d\n", __func__, __LINE__, tmp_index); + + checksum = grub_efi_loongson_grub_calculatechecksum8((grub_uint8_t *)new_interface_mem, new_interface_mem->header.length); + new_interface_mem->header.checksum = checksum; + } + } + + state.jumpreg = 1; + grub_relocator64_boot (relocator, state); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_linux_unload (void) +{ + grub_relocator_unload (relocator); + grub_dl_unref (my_mod); + + loaded = 0; + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_linux_load32 (grub_elf_t elf, const char *filename) +{ + Elf32_Addr base; + grub_err_t err; + grub_uint8_t *playground; + + /* Linux's entry point incorrectly contains a virtual address. */ + entry_addr = elf->ehdr.ehdr32.e_entry; + + linux_size = grub_elf32_size (elf, &base, 0); + if (linux_size == 0) + return grub_errno; + target_addr = base; + linux_size = ALIGN_UP (base + linux_size - base, 8); + + relocator = grub_relocator_new (); + if (!relocator) + return grub_errno; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + grub_vtop ((void *) target_addr), + linux_size); + if (err) + return err; + playground = get_virtual_current_address (ch); + } + + /* Now load the segments into the area we claimed. */ + return grub_elf32_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0); +} + +static grub_err_t +grub_linux_load64 (grub_elf_t elf, const char *filename) +{ + Elf64_Addr base; + grub_err_t err; + grub_uint8_t *playground; + + /* Linux's entry point incorrectly contains a virtual address. */ + entry_addr = elf->ehdr.ehdr64.e_entry; + grub_dprintf("loongson", "entry address = 0x%llx\n", (_ull)entry_addr); + + linux_size = grub_elf64_size (elf, &base, 0); + grub_dprintf("loongson", "base = 0x%llx\n", (_ull)base); + + if (linux_size == 0) + return grub_errno; + target_addr = base; + linux_size = ALIGN_UP (base + linux_size - base, 8); + + relocator = grub_relocator_new (); + if (!relocator) + return grub_errno; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + grub_vtop ((void *) target_addr), + linux_size); + if (err) + return err; + playground = get_virtual_current_address (ch); + //playground = 0xffffffff81ee0000; //½«ÄںËֱ½Óloadµ½elfͷָ¶¨Äڴ棬¶ø·Çgrub·ÖÅäµĿռä + //playground = 0xffffffff80200000; + } + + grub_printf("playground:0x%llx\n", (_ull)playground); + + /* Now load the segments into the area we claimed. */ + return grub_elf64_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0); +} + +static grub_err_t +grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_elf_t elf = 0; + int size; + int i; + grub_uint32_t *linux_argv; + char *linux_args; + grub_err_t err; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + if (ventoy_linux_argc) + { + ventoy_bootopt_hook(argc, argv); + argc = ventoy_linux_argc; + argv = ventoy_linux_args; + } + + elf = grub_elf_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); + if (! elf) + return grub_errno; + + if (elf->ehdr.ehdr32.e_type != ET_EXEC) + { + grub_elf_close (elf); + return grub_error (GRUB_ERR_UNKNOWN_OS, + N_("this ELF file is not of the right type")); + } + + /* Release the previously used memory. */ + grub_loader_unset (); + loaded = 0; + + /* For arguments. */ + linux_argc = argc; + /* Main arguments. */ + size = (linux_argc) * sizeof (grub_uint32_t); + /* Initrd address and size. */ + size += 2 * sizeof (grub_uint32_t); + /* NULL terminator. */ + size += sizeof (grub_uint32_t); + /* First argument is always "a0". */ + size += ALIGN_UP (sizeof ("a0"), 4); + /* Normal arguments. */ + for (i = 1; i < argc; i++) + size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); + + /* rd arguments. */ + size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); + size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); + + size = ALIGN_UP (size, 8); + + if (grub_elf_is_elf32 (elf)) + err = grub_linux_load32 (elf, argv[0]); + else + if (grub_elf_is_elf64 (elf)) + err = grub_linux_load64 (elf, argv[0]); + else + err = grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); + + grub_elf_close (elf); + + if (err) + return err; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + 0, (0xffffffff - size) + 1, + size, 8, + GRUB_RELOCATOR_PREFERENCE_HIGH, 0); + if (err) + return err; + linux_args_addr = get_virtual_current_address (ch); + } + + linux_argv = (grub_uint32_t *) linux_args_addr; + linux_args = (char *) (linux_argv + (linux_argc + 1 + 2)); + + grub_memcpy (linux_args, "a0", sizeof ("a0")); + *linux_argv = (grub_uint32_t) (grub_addr_t) linux_args; + linux_argv++; + linux_args += ALIGN_UP (sizeof ("a0"), 4); + + for (i = 1; i < argc; i++) + { + grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1); + *linux_argv = (grub_uint32_t) (grub_addr_t) linux_args; + linux_argv++; + linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); + } + + /* Reserve space for rd arguments. */ + rd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; + linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); + *linux_argv = 0; + linux_argv++; + + rd_size_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; + linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); + *linux_argv = 0; + linux_argv++; + + *linux_argv = 0; + + //wake up other cores + { + __asm__( + "dli $8, 0x900000003ff01000\n\t" + "dli $11, 0 \n\t" + "dsll $11, 8 \n\t" + "or $8, $8,$11 \n\t" + "li $9, 0x5a5a \n\t" + "sw $9, 32($8) \n\t" + "nop \n\t" + : + : + ); + } + grub_loader_set (grub_linux_boot, grub_linux_unload, 0); + initrd_loaded = 0; + loaded = 1; + grub_dl_ref (my_mod); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_size_t size = 0; + void *initrd_dest; + grub_err_t err; + struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); + + if (!loaded) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); + + if (initrd_loaded) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued."); + + if (grub_initrd_init (argc, argv, &initrd_ctx)) + goto fail; + + size = grub_get_initrd_size (&initrd_ctx); + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + 0, (0xffffffff - size) + 1, + size, 0x10000, + GRUB_RELOCATOR_PREFERENCE_HIGH, 0); + + if (err) + goto fail; + initrd_dest = get_virtual_current_address (ch); + } + + if (grub_initrd_load (&initrd_ctx, argv, initrd_dest)) + goto fail; + + grub_snprintf ((char *) linux_args_addr + rd_addr_arg_off, + sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%lx", + (grub_uint64_t) initrd_dest); + ((grub_uint32_t *) linux_args_addr)[linux_argc] + = (grub_uint32_t) ((grub_addr_t) linux_args_addr + rd_addr_arg_off); + linux_argc++; + + grub_snprintf ((char *) linux_args_addr + rd_size_arg_off, + sizeof ("rd_size=0xXXXXXXXXXXXXXXXXX"), "rd_size=0x%lx", + (grub_uint64_t) size); + ((grub_uint32_t *) linux_args_addr)[linux_argc] + = (grub_uint32_t) ((grub_addr_t) linux_args_addr + rd_size_arg_off); + linux_argc++; + + initrd_loaded = 1; + + fail: + grub_initrd_close (&initrd_ctx); + + return grub_errno; +} + +static grub_err_t +ventoy_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int i; + const char *file; + char buf[64]; + + if (ventoy_debug) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc); + + if (ventoy_linux_argc == 0) + { + return grub_cmd_initrd(cmd, argc, argv); + } + + grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size")); + + if (ventoy_debug) grub_printf("membuf=%s\n", buf); + + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(buf); + + file = grub_env_get("vtoy_img_part_file"); + if (file) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(file); + } + + for (i = 0; i < argc; i++) + { + ventoy_extra_initrd_list[ventoy_extra_initrd_num++] = grub_strdup(argv[i]); + } + + ventoy_initrd_called = 1; + + if (ventoy_debug) + { + grub_printf("========== initrd list ==========\n"); + for (i = 0; i < ventoy_extra_initrd_num; i++) + { + grub_printf("%s\n", ventoy_extra_initrd_list[i]); + } + grub_printf("=================================\n"); + } + + return grub_cmd_initrd(cmd, ventoy_extra_initrd_num, ventoy_extra_initrd_list); +} + +static grub_command_t cmd_linux, cmd_initrd; +static grub_command_t cmd_set_bootopt, cmd_unset_bootopt, cmd_extra_initrd_append, cmd_extra_initrd_reset; + +GRUB_MOD_INIT(linux) +{ + cmd_linux = grub_register_command ("linux", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", ventoy_cmd_initrd, + 0, N_("Load initrd.")); + + cmd_set_bootopt = grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt, 0, N_("set ext boot opt")); + cmd_unset_bootopt = grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt, 0, N_("unset ext boot opt")); + + cmd_extra_initrd_append = grub_register_command ("vt_img_extra_initrd_append", grub_cmd_extra_initrd_append, 0, N_("")); + cmd_extra_initrd_reset = grub_register_command ("vt_img_extra_initrd_reset", grub_cmd_extra_initrd_reset, 0, N_("")); + + ventoy_linux_args = grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC); + + my_mod = mod; +} + +GRUB_MOD_FINI(linux) +{ + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/charset.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/charset.c new file mode 100644 index 0000000..2c2f960 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/charset.c @@ -0,0 +1,1352 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +/* + Current problems with Unicode rendering: + - B and BN bidi type characters (ignored) + - Mc type characters with combining class 0 (poorly combined) + - Mn type characters with combining class 0 (poorly combined) + - Me type characters with combining class 0 (poorly combined) + - Cf type characters (ignored) + - Cc type characters (ignored) + - Line-breaking rules (e.g. Zs type characters) + - Indic languages + - non-Semitic shaping (rarely used) + - Zl and Zp characters + - Combining characters of types 7, 8, 9, 21, 35, 36, 84, 91, 103, 107, + 118, 122, 129, 130, 132, 218, 224, 226, 233, 234 + - Private use characters (not really a problem) + - Variations (no font support) + - Vertical text + - Ligatures + Font information ignored: + - Kerning + - Justification data + - Glyph posititioning + - Baseline data + Most underline diacritics aren't displayed in gfxterm + */ + +#include +#include +#include +#include +#include +#include + +#if HAVE_FONT_SOURCE +#include "widthspec.h" +#endif + +/* Returns -2 if not enough space, -1 on invalid character. */ +grub_ssize_t +grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend, + grub_uint32_t code) +{ + if (dest >= destend) + return -2; + if (code <= 0x007F) + { + *dest++ = code; + return 1; + } + if (code <= 0x07FF) + { + if (dest + 1 >= destend) + return -2; + *dest++ = (code >> 6) | 0xC0; + *dest++ = (code & 0x3F) | 0x80; + return 2; + } + if ((code >= 0xDC00 && code <= 0xDFFF) + || (code >= 0xD800 && code <= 0xDBFF)) + { + /* No surrogates in UCS-4... */ + return -1; + } + if (code < 0x10000) + { + if (dest + 2 >= destend) + return -2; + *dest++ = (code >> 12) | 0xE0; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + return 3; + } + { + if (dest + 3 >= destend) + return -2; + *dest++ = (code >> 18) | 0xF0; + *dest++ = ((code >> 12) & 0x3F) | 0x80; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + return 4; + } + +} + +/* Convert UCS-4 to UTF-8. */ +grub_size_t +grub_ucs4_to_utf8 (const grub_uint32_t *src, grub_size_t size, + grub_uint8_t *dest, grub_size_t destsize) +{ + /* Keep last char for \0. */ + grub_uint8_t *destend = dest + destsize - 1; + grub_uint8_t *dest0 = dest; + + while (size-- && dest < destend) + { + grub_uint32_t code = *src++; + grub_ssize_t s; + s = grub_encode_utf8_character (dest, destend, code); + if (s == -2) + break; + if (s == -1) + { + *dest++ = '?'; + continue; + } + dest += s; + } + *dest = 0; + return dest - dest0; +} + +/* Returns the number of bytes the string src would occupy is converted + to UTF-8, excluding trailing \0. */ +grub_size_t +grub_get_num_of_utf8_bytes (const grub_uint32_t *src, grub_size_t size) +{ + grub_size_t remaining; + const grub_uint32_t *ptr; + grub_size_t cnt = 0; + + remaining = size; + ptr = src; + while (remaining--) + { + grub_uint32_t code = *ptr++; + + if (code <= 0x007F) + cnt++; + else if (code <= 0x07FF) + cnt += 2; + else if ((code >= 0xDC00 && code <= 0xDFFF) + || (code >= 0xD800 && code <= 0xDBFF)) + /* No surrogates in UCS-4... */ + cnt++; + else if (code < 0x10000) + cnt += 3; + else + cnt += 4; + } + return cnt; +} + +/* Convert UCS-4 to UTF-8. */ +char * +grub_ucs4_to_utf8_alloc (const grub_uint32_t *src, grub_size_t size) +{ + grub_uint8_t *ret; + grub_size_t cnt = grub_get_num_of_utf8_bytes (src, size) + 1; + + ret = grub_malloc (cnt); + if (!ret) + return 0; + + grub_ucs4_to_utf8 (src, size, ret, cnt); + + return (char *) ret; +} + +int +grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize) +{ + int count = 0; + grub_uint32_t code = 0; + + while (srcsize) + { + if (srcsize != (grub_size_t)-1) + srcsize--; + if (!grub_utf8_process (*src++, &code, &count)) + return 0; + if (count != 0) + continue; + if (code == 0) + return 1; + if (code > GRUB_UNICODE_LAST_VALID) + return 0; + } + + return 1; +} + +grub_ssize_t +grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, + grub_uint32_t **last_position) +{ + grub_size_t msg_len = grub_strlen (msg); + + *unicode_msg = grub_malloc (msg_len * sizeof (grub_uint32_t)); + + if (!*unicode_msg) + return -1; + + msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len, + (grub_uint8_t *) msg, -1, 0); + + if (last_position) + *last_position = *unicode_msg + msg_len; + + return msg_len; +} + +/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE + bytes (if SRCSIZE is -1, it is ignored) in length to a UCS-4 string. + Return the number of characters converted. DEST must be able to hold + at least DESTSIZE characters. + If SRCEND is not NULL, then *SRCEND is set to the next byte after the + last byte used in SRC. */ +grub_size_t +grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, + const grub_uint8_t *src, grub_size_t srcsize, + const grub_uint8_t **srcend) +{ + grub_uint32_t *p = dest; + int count = 0; + grub_uint32_t code = 0; + + if (srcend) + *srcend = src; + + while (srcsize && destsize) + { + int was_count = count; + if (srcsize != (grub_size_t)-1) + srcsize--; + if (!grub_utf8_process (*src++, &code, &count)) + { + code = '?'; + count = 0; + /* Character c may be valid, don't eat it. */ + if (was_count) + src--; + } + if (count != 0) + continue; + if (code == 0) + break; + *p++ = code; + destsize--; + } + + if (srcend) + *srcend = src; + return p - dest; +} + +static grub_uint8_t *join_types = NULL; + +static void +unpack_join (void) +{ + unsigned i; + struct grub_unicode_compact_range *cur; + + join_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR); + if (!join_types) + { + grub_errno = GRUB_ERR_NONE; + return; + } + for (cur = grub_unicode_compact; cur->len; cur++) + for (i = cur->start; i < cur->start + (unsigned) cur->len + && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) + join_types[i] = cur->join_type; +} + +static grub_uint8_t *bidi_types = NULL; + +static void +unpack_bidi (void) +{ + unsigned i; + struct grub_unicode_compact_range *cur; + + bidi_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR); + if (!bidi_types) + { + grub_errno = GRUB_ERR_NONE; + return; + } + for (cur = grub_unicode_compact; cur->len; cur++) + for (i = cur->start; i < cur->start + (unsigned) cur->len + && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) + if (cur->bidi_mirror) + bidi_types[i] = cur->bidi_type | 0x80; + else + bidi_types[i] = cur->bidi_type | 0x00; +} + +static inline enum grub_bidi_type +get_bidi_type (grub_uint32_t c) +{ + struct grub_unicode_compact_range *cur; + + if (!bidi_types) + unpack_bidi (); + + if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) + return bidi_types[c] & 0x7f; + + for (cur = grub_unicode_compact; cur->len; cur++) + if (cur->start <= c && c < cur->start + (unsigned) cur->len) + return cur->bidi_type; + + return GRUB_BIDI_TYPE_L; +} + +static inline enum grub_join_type +get_join_type (grub_uint32_t c) +{ + struct grub_unicode_compact_range *cur; + + if (!join_types) + unpack_join (); + + if (join_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) + return join_types[c]; + + for (cur = grub_unicode_compact; cur->len; cur++) + if (cur->start <= c && c < cur->start + (unsigned) cur->len) + return cur->join_type; + + return GRUB_JOIN_TYPE_NONJOINING; +} + +static inline int +is_mirrored (grub_uint32_t c) +{ + struct grub_unicode_compact_range *cur; + + if (!bidi_types) + unpack_bidi (); + + if (bidi_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) + return !!(bidi_types[c] & 0x80); + + for (cur = grub_unicode_compact; cur->len; cur++) + if (cur->start <= c && c < cur->start + (unsigned) cur->len) + return cur->bidi_mirror; + + return 0; +} + +enum grub_comb_type +grub_unicode_get_comb_type (grub_uint32_t c) +{ + static grub_uint8_t *comb_types = NULL; + struct grub_unicode_compact_range *cur; + + if (!comb_types) + { + unsigned i; + comb_types = grub_zalloc (GRUB_UNICODE_MAX_CACHED_CHAR); + if (comb_types) + for (cur = grub_unicode_compact; cur->len; cur++) + for (i = cur->start; i < cur->start + (unsigned) cur->len + && i < GRUB_UNICODE_MAX_CACHED_CHAR; i++) + comb_types[i] = cur->comb_type; + else + grub_errno = GRUB_ERR_NONE; + } + + if (comb_types && c < GRUB_UNICODE_MAX_CACHED_CHAR) + return comb_types[c]; + + for (cur = grub_unicode_compact; cur->len; cur++) + if (cur->start <= c && c < cur->start + (unsigned) cur->len) + return cur->comb_type; + + return GRUB_UNICODE_COMB_NONE; +} + +#if HAVE_FONT_SOURCE + +grub_size_t +grub_unicode_estimate_width (const struct grub_unicode_glyph *c) +{ + if (grub_unicode_get_comb_type (c->base)) + return 0; + if (widthspec[c->base >> 3] & (1 << (c->base & 7))) + return 2; + else + return 1; +} + +#endif + +static inline int +is_type_after (enum grub_comb_type a, enum grub_comb_type b) +{ + /* Shadda is numerically higher than most of Arabic diacritics but has + to be rendered before them. */ + if (a == GRUB_UNICODE_COMB_ARABIC_SHADDA + && b <= GRUB_UNICODE_COMB_ARABIC_KASRA + && b >= GRUB_UNICODE_COMB_ARABIC_FATHATAN) + return 0; + if (b == GRUB_UNICODE_COMB_ARABIC_SHADDA + && a <= GRUB_UNICODE_COMB_ARABIC_KASRA + && a >= GRUB_UNICODE_COMB_ARABIC_FATHATAN) + return 1; + return a > b; +} + +grub_size_t +grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, + struct grub_unicode_glyph *out) +{ + int haveout = 0; + const grub_uint32_t *ptr; + unsigned last_comb_pointer = 0; + + grub_memset (out, 0, sizeof (*out)); + + if (inlen && grub_iscntrl (*in)) + { + out->base = *in; + out->variant = 0; + out->attributes = 0; + out->ncomb = 0; + out->estimated_width = 1; + return 1; + } + + for (ptr = in; ptr < in + inlen; ptr++) + { + /* Variation selectors >= 17 are outside of BMP and SMP. + Handle variation selectors first to avoid potentially costly lookups. + */ + if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1 + && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16) + { + if (haveout) + out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_1 + 1; + continue; + } + if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17 + && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256) + { + if (haveout) + out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_17 + 17; + continue; + } + + enum grub_comb_type comb_type; + comb_type = grub_unicode_get_comb_type (*ptr); + if (comb_type) + { + struct grub_unicode_combining *n; + unsigned j; + + if (!haveout) + continue; + + if (comb_type == GRUB_UNICODE_COMB_MC + || comb_type == GRUB_UNICODE_COMB_ME + || comb_type == GRUB_UNICODE_COMB_MN) + last_comb_pointer = out->ncomb; + + if (out->ncomb + 1 <= (int) ARRAY_SIZE (out->combining_inline)) + n = out->combining_inline; + else if (out->ncomb > (int) ARRAY_SIZE (out->combining_inline)) + { + n = grub_realloc (out->combining_ptr, + sizeof (n[0]) * (out->ncomb + 1)); + if (!n) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + out->combining_ptr = n; + } + else + { + n = grub_malloc (sizeof (n[0]) * (out->ncomb + 1)); + if (!n) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + grub_memcpy (n, out->combining_inline, + sizeof (out->combining_inline)); + out->combining_ptr = n; + } + + for (j = last_comb_pointer; j < out->ncomb; j++) + if (is_type_after (n[j].type, comb_type)) + break; + grub_memmove (n + j + 1, + n + j, + (out->ncomb - j) + * sizeof (n[0])); + n[j].code = *ptr; + n[j].type = comb_type; + out->ncomb++; + continue; + } + if (haveout) + return ptr - in; + haveout = 1; + out->base = *ptr; + out->variant = 0; + out->attributes = 0; + out->ncomb = 0; + out->estimated_width = 1; + } + return ptr - in; +} + +static void +revert (struct grub_unicode_glyph *visual, + struct grub_term_pos *pos, + unsigned start, unsigned end) +{ + struct grub_unicode_glyph t; + unsigned i; + int a = 0, b = 0; + if (pos) + { + a = pos[visual[start].orig_pos].x; + b = pos[visual[end].orig_pos].x; + } + for (i = 0; i < (end - start) / 2 + 1; i++) + { + t = visual[start + i]; + visual[start + i] = visual[end - i]; + visual[end - i] = t; + + if (pos) + { + pos[visual[start + i].orig_pos].x = a + b - pos[visual[start + i].orig_pos].x; + pos[visual[end - i].orig_pos].x = a + b - pos[visual[end - i].orig_pos].x; + } + } +} + + +static grub_ssize_t +bidi_line_wrap (struct grub_unicode_glyph *visual_out, + struct grub_unicode_glyph *visual, + grub_size_t visual_len, + grub_size_t (*getcharwidth) (const struct grub_unicode_glyph *visual, void *getcharwidth_arg), + void *getcharwidth_arg, + grub_size_t maxwidth, grub_size_t startwidth, + grub_uint32_t contchar, + struct grub_term_pos *pos, int primitive_wrap, + grub_size_t log_end) +{ + struct grub_unicode_glyph *outptr = visual_out; + unsigned line_start = 0; + grub_ssize_t line_width; + unsigned k; + grub_ssize_t last_space = -1; + grub_ssize_t last_space_width = 0; + int lines = 0; + + if (!visual_len) + return 0; + + if (startwidth >= maxwidth && (grub_ssize_t) maxwidth > 0) + { + if (contchar) + { + grub_memset (outptr, 0, sizeof (visual[0])); + outptr->base = contchar; + outptr++; + } + grub_memset (outptr, 0, sizeof (visual[0])); + outptr->base = '\n'; + outptr++; + startwidth = 0; + } + + line_width = startwidth; + + for (k = 0; k <= visual_len; k++) + { + grub_ssize_t last_width = 0; + + if (pos && k != visual_len) + { + pos[visual[k].orig_pos].x = line_width; + pos[visual[k].orig_pos].y = lines; + pos[visual[k].orig_pos].valid = 1; + } + + if (k == visual_len && pos) + { + pos[log_end].x = line_width; + pos[log_end].y = lines; + pos[log_end].valid = 1; + } + + if (getcharwidth && k != visual_len) + line_width += last_width = getcharwidth (&visual[k], getcharwidth_arg); + + if (k != visual_len && (visual[k].base == ' ' + || visual[k].base == '\t') + && !primitive_wrap) + { + last_space = k; + last_space_width = line_width; + } + + if (((grub_ssize_t) maxwidth > 0 + && line_width > (grub_ssize_t) maxwidth) || k == visual_len) + { + unsigned min_odd_level = 0xffffffff; + unsigned max_level = 0; + unsigned kk = k; + + lines++; + + if (k != visual_len && last_space > (signed) line_start) + { + kk = last_space; + line_width -= last_space_width; + } + else if (k != visual_len && line_start == 0 && startwidth != 0 + && !primitive_wrap && lines == 1 + && line_width - startwidth < maxwidth) + { + kk = 0; + line_width -= startwidth; + } + else + line_width = last_width; + + { + unsigned i; + for (i = line_start; i < kk; i++) + { + if (visual[i].bidi_level > max_level) + max_level = visual[i].bidi_level; + if (visual[i].bidi_level < min_odd_level && (visual[i].bidi_level & 1)) + min_odd_level = visual[i].bidi_level; + } + } + + { + unsigned j; + /* FIXME: can be optimized. */ + for (j = max_level; j > min_odd_level - 1; j--) + { + unsigned in = line_start; + unsigned i; + for (i = line_start; i < kk; i++) + { + if (i != line_start && visual[i].bidi_level >= j + && visual[i-1].bidi_level < j) + in = i; + if (visual[i].bidi_level >= j && (i + 1 == kk + || visual[i+1].bidi_level < j)) + revert (visual, pos, in, i); + } + } + } + + { + unsigned i; + for (i = line_start; i < kk; i++) + { + if (is_mirrored (visual[i].base) && visual[i].bidi_level) + visual[i].attributes |= GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR; + if ((visual[i].attributes & GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN) + && visual[i].bidi_level) + { + int left, right; + left = visual[i].attributes + & (GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED + | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT); + right = visual[i].attributes + & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED + | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT); + visual[i].attributes &= ~GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN; + left <<= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT; + right >>= GRUB_UNICODE_GLYPH_ATTRIBUTES_JOIN_LEFT_TO_RIGHT_SHIFT; + visual[i].attributes |= (left | right); + } + } + } + + { + int left_join = 0; + unsigned i; + for (i = line_start; i < kk; i++) + { + enum grub_join_type join_type = get_join_type (visual[i].base); + if (!(visual[i].attributes + & GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT) + && (join_type == GRUB_JOIN_TYPE_LEFT + || join_type == GRUB_JOIN_TYPE_DUAL)) + { + if (left_join) + visual[i].attributes + |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED; + else + visual[i].attributes + &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED; + } + if (join_type == GRUB_JOIN_TYPE_NONJOINING + || join_type == GRUB_JOIN_TYPE_LEFT) + left_join = 0; + if (join_type == GRUB_JOIN_TYPE_RIGHT + || join_type == GRUB_JOIN_TYPE_DUAL + || join_type == GRUB_JOIN_TYPE_CAUSING) + left_join = 1; + } + } + + { + int right_join = 0; + signed i; + for (i = kk - 1; i >= 0 && (unsigned) i + 1 > line_start; + i--) + { + enum grub_join_type join_type = get_join_type (visual[i].base); + if (!(visual[i].attributes + & GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT) + && (join_type == GRUB_JOIN_TYPE_RIGHT + || join_type == GRUB_JOIN_TYPE_DUAL)) + { + if (right_join) + visual[i].attributes + |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED; + else + visual[i].attributes + &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED; + } + if (join_type == GRUB_JOIN_TYPE_NONJOINING + || join_type == GRUB_JOIN_TYPE_RIGHT) + right_join = 0; + if (join_type == GRUB_JOIN_TYPE_LEFT + || join_type == GRUB_JOIN_TYPE_DUAL + || join_type == GRUB_JOIN_TYPE_CAUSING) + right_join = 1; + } + } + + grub_memcpy (outptr, &visual[line_start], + (kk - line_start) * sizeof (visual[0])); + outptr += kk - line_start; + if (kk != visual_len) + { + if (contchar) + { + grub_memset (outptr, 0, sizeof (visual[0])); + outptr->base = contchar; + outptr++; + } + grub_memset (outptr, 0, sizeof (visual[0])); + outptr->base = '\n'; + outptr++; + } + + if ((signed) kk == last_space) + kk++; + + line_start = kk; + if (pos && kk != visual_len) + { + pos[visual[kk].orig_pos].x = 0; + pos[visual[kk].orig_pos].y = lines; + } + } + } + + return outptr - visual_out; +} + + +static grub_ssize_t +grub_bidi_line_logical_to_visual (const grub_uint32_t *logical, + grub_size_t logical_len, + struct grub_unicode_glyph *visual_out, + grub_size_t (*getcharwidth) (const struct grub_unicode_glyph *visual, void *getcharwidth_arg), + void *getcharwidth_arg, + grub_size_t maxwidth, grub_size_t startwidth, + grub_uint32_t contchar, + struct grub_term_pos *pos, + int primitive_wrap, + grub_size_t log_end) +{ + enum grub_bidi_type type = GRUB_BIDI_TYPE_L; + enum override_status {OVERRIDE_NEUTRAL = 0, OVERRIDE_R, OVERRIDE_L}; + unsigned base_level; + enum override_status cur_override; + unsigned i; + unsigned stack_level[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3]; + enum override_status stack_override[GRUB_BIDI_MAX_EXPLICIT_LEVEL + 3]; + unsigned stack_depth = 0; + unsigned invalid_pushes = 0; + unsigned visual_len = 0; + unsigned run_start, run_end; + struct grub_unicode_glyph *visual; + unsigned cur_level; + int bidi_needed = 0; + +#define push_stack(new_override, new_level) \ + { \ + if (new_level > GRUB_BIDI_MAX_EXPLICIT_LEVEL) \ + { \ + invalid_pushes++; \ + } \ + else \ + { \ + stack_level[stack_depth] = cur_level; \ + stack_override[stack_depth] = cur_override; \ + stack_depth++; \ + cur_level = new_level; \ + cur_override = new_override; \ + } \ + } + +#define pop_stack() \ + { \ + if (invalid_pushes) \ + { \ + invalid_pushes--; \ + } \ + else if (stack_depth) \ + { \ + stack_depth--; \ + cur_level = stack_level[stack_depth]; \ + cur_override = stack_override[stack_depth]; \ + } \ + } + + visual = grub_malloc (sizeof (visual[0]) * logical_len); + if (!visual) + return -1; + + for (i = 0; i < logical_len; i++) + { + type = get_bidi_type (logical[i]); + if (type == GRUB_BIDI_TYPE_L || type == GRUB_BIDI_TYPE_AL + || type == GRUB_BIDI_TYPE_R) + break; + } + if (type == GRUB_BIDI_TYPE_R || type == GRUB_BIDI_TYPE_AL) + base_level = 1; + else + base_level = 0; + + cur_level = base_level; + cur_override = OVERRIDE_NEUTRAL; + { + const grub_uint32_t *lptr; + enum {JOIN_DEFAULT, NOJOIN, JOIN_FORCE} join_state = JOIN_DEFAULT; + int zwj_propagate_to_previous = 0; + for (lptr = logical; lptr < logical + logical_len;) + { + grub_size_t p; + + if (*lptr == GRUB_UNICODE_ZWJ) + { + if (zwj_propagate_to_previous) + { + visual[visual_len - 1].attributes + |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT + | GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED; + } + zwj_propagate_to_previous = 0; + join_state = JOIN_FORCE; + lptr++; + continue; + } + + if (*lptr == GRUB_UNICODE_ZWNJ) + { + if (zwj_propagate_to_previous) + { + visual[visual_len - 1].attributes + |= GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED_EXPLICIT; + visual[visual_len - 1].attributes + &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED; + } + zwj_propagate_to_previous = 0; + join_state = NOJOIN; + lptr++; + continue; + } + + /* The tags: deprecated, never used. */ + if (*lptr >= GRUB_UNICODE_TAG_START && *lptr <= GRUB_UNICODE_TAG_END) + continue; + + p = grub_unicode_aglomerate_comb (lptr, logical + logical_len - lptr, + &visual[visual_len]); + visual[visual_len].orig_pos = lptr - logical; + type = get_bidi_type (visual[visual_len].base); + switch (type) + { + case GRUB_BIDI_TYPE_RLE: + bidi_needed = 1; + push_stack (cur_override, (cur_level | 1) + 1); + break; + case GRUB_BIDI_TYPE_RLO: + bidi_needed = 1; + push_stack (OVERRIDE_R, (cur_level | 1) + 1); + break; + case GRUB_BIDI_TYPE_LRE: + push_stack (cur_override, (cur_level & ~1) + 2); + break; + case GRUB_BIDI_TYPE_LRO: + push_stack (OVERRIDE_L, (cur_level & ~1) + 2); + break; + case GRUB_BIDI_TYPE_PDF: + pop_stack (); + break; + case GRUB_BIDI_TYPE_BN: + break; + case GRUB_BIDI_TYPE_R: + case GRUB_BIDI_TYPE_AL: + bidi_needed = 1; + /* Fallthrough. */ + default: + { + if (join_state == JOIN_FORCE) + { + visual[visual_len].attributes + |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT + | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED; + } + + if (join_state == NOJOIN) + { + visual[visual_len].attributes + |= GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED_EXPLICIT; + visual[visual_len].attributes + &= ~GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED; + } + + join_state = JOIN_DEFAULT; + zwj_propagate_to_previous = 1; + + visual[visual_len].bidi_level = cur_level; + if (cur_override != OVERRIDE_NEUTRAL) + visual[visual_len].bidi_type = + (cur_override == OVERRIDE_L) ? GRUB_BIDI_TYPE_L + : GRUB_BIDI_TYPE_R; + else + visual[visual_len].bidi_type = type; + visual_len++; + } + } + lptr += p; + } + } + + if (bidi_needed) + { + for (run_start = 0; run_start < visual_len; run_start = run_end) + { + unsigned prev_level, next_level, cur_run_level; + unsigned last_type, last_strong_type; + for (run_end = run_start; run_end < visual_len && + visual[run_end].bidi_level == visual[run_start].bidi_level; run_end++); + if (run_start == 0) + prev_level = base_level; + else + prev_level = visual[run_start - 1].bidi_level; + if (run_end == visual_len) + next_level = base_level; + else + next_level = visual[run_end].bidi_level; + cur_run_level = visual[run_start].bidi_level; + if (prev_level & 1) + last_type = GRUB_BIDI_TYPE_R; + else + last_type = GRUB_BIDI_TYPE_L; + last_strong_type = last_type; + for (i = run_start; i < run_end; i++) + { + switch (visual[i].bidi_type) + { + case GRUB_BIDI_TYPE_NSM: + visual[i].bidi_type = last_type; + break; + case GRUB_BIDI_TYPE_EN: + if (last_strong_type == GRUB_BIDI_TYPE_AL) + visual[i].bidi_type = GRUB_BIDI_TYPE_AN; + break; + case GRUB_BIDI_TYPE_L: + case GRUB_BIDI_TYPE_R: + last_strong_type = visual[i].bidi_type; + break; + case GRUB_BIDI_TYPE_ES: + if (last_type == GRUB_BIDI_TYPE_EN + && i + 1 < run_end + && visual[i + 1].bidi_type == GRUB_BIDI_TYPE_EN) + visual[i].bidi_type = GRUB_BIDI_TYPE_EN; + else + visual[i].bidi_type = GRUB_BIDI_TYPE_ON; + break; + case GRUB_BIDI_TYPE_ET: + { + unsigned j; + if (last_type == GRUB_BIDI_TYPE_EN) + { + visual[i].bidi_type = GRUB_BIDI_TYPE_EN; + break; + } + for (j = i; j < run_end + && visual[j].bidi_type == GRUB_BIDI_TYPE_ET; j++); + if (j != run_end && visual[j].bidi_type == GRUB_BIDI_TYPE_EN) + { + for (; i < run_end + && visual[i].bidi_type == GRUB_BIDI_TYPE_ET; i++) + visual[i].bidi_type = GRUB_BIDI_TYPE_EN; + i--; + break; + } + for (; i < run_end + && visual[i].bidi_type == GRUB_BIDI_TYPE_ET; i++) + visual[i].bidi_type = GRUB_BIDI_TYPE_ON; + i--; + break; + } + break; + case GRUB_BIDI_TYPE_CS: + if (last_type == GRUB_BIDI_TYPE_EN + && i + 1 < run_end + && visual[i + 1].bidi_type == GRUB_BIDI_TYPE_EN) + { + visual[i].bidi_type = GRUB_BIDI_TYPE_EN; + break; + } + if (last_type == GRUB_BIDI_TYPE_AN + && i + 1 < run_end + && (visual[i + 1].bidi_type == GRUB_BIDI_TYPE_AN + || (visual[i + 1].bidi_type == GRUB_BIDI_TYPE_EN + && last_strong_type == GRUB_BIDI_TYPE_AL))) + { + visual[i].bidi_type = GRUB_BIDI_TYPE_EN; + break; + } + visual[i].bidi_type = GRUB_BIDI_TYPE_ON; + break; + case GRUB_BIDI_TYPE_AL: + last_strong_type = visual[i].bidi_type; + visual[i].bidi_type = GRUB_BIDI_TYPE_R; + break; + default: /* Make GCC happy. */ + break; + } + last_type = visual[i].bidi_type; + if (visual[i].bidi_type == GRUB_BIDI_TYPE_EN + && last_strong_type == GRUB_BIDI_TYPE_L) + visual[i].bidi_type = GRUB_BIDI_TYPE_L; + } + if (prev_level & 1) + last_type = GRUB_BIDI_TYPE_R; + else + last_type = GRUB_BIDI_TYPE_L; + for (i = run_start; i < run_end; ) + { + unsigned j; + unsigned next_type; + for (j = i; j < run_end && + (visual[j].bidi_type == GRUB_BIDI_TYPE_B + || visual[j].bidi_type == GRUB_BIDI_TYPE_S + || visual[j].bidi_type == GRUB_BIDI_TYPE_WS + || visual[j].bidi_type == GRUB_BIDI_TYPE_ON); j++); + if (j == i) + { + if (visual[i].bidi_type == GRUB_BIDI_TYPE_L) + last_type = GRUB_BIDI_TYPE_L; + else + last_type = GRUB_BIDI_TYPE_R; + i++; + continue; + } + if (j == run_end) + next_type = (next_level & 1) ? GRUB_BIDI_TYPE_R : GRUB_BIDI_TYPE_L; + else + { + if (visual[j].bidi_type == GRUB_BIDI_TYPE_L) + next_type = GRUB_BIDI_TYPE_L; + else + next_type = GRUB_BIDI_TYPE_R; + } + if (next_type == last_type) + for (; i < j; i++) + visual[i].bidi_type = last_type; + else + for (; i < j; i++) + visual[i].bidi_type = (cur_run_level & 1) ? GRUB_BIDI_TYPE_R + : GRUB_BIDI_TYPE_L; + } + } + + for (i = 0; i < visual_len; i++) + { + if (!(visual[i].bidi_level & 1) && visual[i].bidi_type == GRUB_BIDI_TYPE_R) + { + visual[i].bidi_level++; + continue; + } + if (!(visual[i].bidi_level & 1) && (visual[i].bidi_type == GRUB_BIDI_TYPE_AN + || visual[i].bidi_type == GRUB_BIDI_TYPE_EN)) + { + visual[i].bidi_level += 2; + continue; + } + if ((visual[i].bidi_level & 1) && (visual[i].bidi_type == GRUB_BIDI_TYPE_L + || visual[i].bidi_type == GRUB_BIDI_TYPE_AN + || visual[i].bidi_type == GRUB_BIDI_TYPE_EN)) + { + visual[i].bidi_level++; + continue; + } + } + } + else + { + for (i = 0; i < visual_len; i++) + visual[i].bidi_level = 0; + } + + { + grub_ssize_t ret; + ret = bidi_line_wrap (visual_out, visual, visual_len, + getcharwidth, getcharwidth_arg, maxwidth, startwidth, contchar, + pos, primitive_wrap, log_end); + grub_free (visual); + return ret; + } +} + +static int +is_visible (const struct grub_unicode_glyph *gl) +{ + if (gl->ncomb) + return 1; + if (gl->base == GRUB_UNICODE_LRM || gl->base == GRUB_UNICODE_RLM) + return 0; + return 1; +} + +grub_ssize_t +grub_bidi_logical_to_visual (const grub_uint32_t *logical, + grub_size_t logical_len, + struct grub_unicode_glyph **visual_out, + grub_size_t (*getcharwidth) (const struct grub_unicode_glyph *visual, void *getcharwidth_arg), + void *getcharwidth_arg, + grub_size_t max_length, grub_size_t startwidth, + grub_uint32_t contchar, struct grub_term_pos *pos, int primitive_wrap) +{ + const grub_uint32_t *line_start = logical, *ptr; + struct grub_unicode_glyph *visual_ptr; + *visual_out = visual_ptr = grub_malloc (3 * sizeof (visual_ptr[0]) + * (logical_len + 2)); + if (!visual_ptr) + return -1; + for (ptr = logical; ptr <= logical + logical_len; ptr++) + { + if (ptr == logical + logical_len || *ptr == '\n') + { + grub_ssize_t ret; + grub_ssize_t i, j; + ret = grub_bidi_line_logical_to_visual (line_start, + ptr - line_start, + visual_ptr, + getcharwidth, + getcharwidth_arg, + max_length, + startwidth, + contchar, + pos, + primitive_wrap, + logical_len); + startwidth = 0; + + if (ret < 0) + { + grub_free (*visual_out); + return ret; + } + for (i = 0, j = 0; i < ret; i++) + if (is_visible(&visual_ptr[i])) + visual_ptr[j++] = visual_ptr[i]; + visual_ptr += j; + line_start = ptr; + if (ptr != logical + logical_len) + { + grub_memset (visual_ptr, 0, sizeof (visual_ptr[0])); + visual_ptr->base = '\n'; + visual_ptr++; + line_start++; + } + } + } + return visual_ptr - *visual_out; +} + +grub_uint32_t +grub_unicode_mirror_code (grub_uint32_t in) +{ + int i; + for (i = 0; grub_unicode_bidi_pairs[i].key; i++) + if (grub_unicode_bidi_pairs[i].key == in) + return grub_unicode_bidi_pairs[i].replace; + return in; +} + +grub_uint32_t +grub_unicode_shape_code (grub_uint32_t in, grub_uint8_t attr) +{ + int i; + if (!(in >= GRUB_UNICODE_ARABIC_START + && in < GRUB_UNICODE_ARABIC_END)) + return in; + + for (i = 0; grub_unicode_arabic_shapes[i].code; i++) + if (grub_unicode_arabic_shapes[i].code == in) + { + grub_uint32_t out = 0; + switch (attr & (GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED + | GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED)) + { + case 0: + out = grub_unicode_arabic_shapes[i].isolated; + break; + case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED: + out = grub_unicode_arabic_shapes[i].right_linked; + break; + case GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED: + out = grub_unicode_arabic_shapes[i].left_linked; + break; + case GRUB_UNICODE_GLYPH_ATTRIBUTE_RIGHT_JOINED + |GRUB_UNICODE_GLYPH_ATTRIBUTE_LEFT_JOINED: + out = grub_unicode_arabic_shapes[i].both_linked; + break; + } + if (out) + return out; + } + + return in; +} + +const grub_uint32_t * +grub_unicode_get_comb_start (const grub_uint32_t *str, + const grub_uint32_t *cur) +{ + const grub_uint32_t *ptr; + for (ptr = cur; ptr >= str; ptr--) + { + if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1 + && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16) + continue; + + if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17 + && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256) + continue; + + enum grub_comb_type comb_type; + comb_type = grub_unicode_get_comb_type (*ptr); + if (comb_type) + continue; + return ptr; + } + return str; +} + +const grub_uint32_t * +grub_unicode_get_comb_end (const grub_uint32_t *end, + const grub_uint32_t *cur) +{ + const grub_uint32_t *ptr; + for (ptr = cur; ptr < end; ptr++) + { + if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1 + && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16) + continue; + + if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17 + && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256) + continue; + + enum grub_comb_type comb_type; + comb_type = grub_unicode_get_comb_type (*ptr); + if (comb_type) + continue; + return ptr; + } + return end; +} + +int +grub_utf8_get_num_code (const char *src, grub_size_t srcsize) +{ + int count = 0; + grub_uint32_t code = 0; + int num = 0; + + while (srcsize) + { + if (srcsize != (grub_size_t) -1) + srcsize--; + if (!grub_utf8_process ((grub_uint8_t)*src++, &code, &count)) + return 0; + if (count != 0) + continue; + if (code == 0 || code > GRUB_UNICODE_LAST_VALID) + return num; + ++num; + } + return num; +} + +const char * +grub_utf8_offset_code (const char *src, grub_size_t srcsize, int num) +{ + int count = 0; + grub_uint32_t code = 0; + + while (srcsize && num) + { + if (srcsize != (grub_size_t) -1) + srcsize--; + if (!grub_utf8_process ((grub_uint8_t)*src++, &code, &count)) + return 0; + if (count != 0) + continue; + if (code == 0 || code > GRUB_UNICODE_LAST_VALID) + return 0; + --num; + } + + if (!num) + return src; + + return 0; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/context.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/context.c new file mode 100644 index 0000000..dde3e5f --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/context.c @@ -0,0 +1,214 @@ +/* env.c - Environment variables */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +struct menu_pointer +{ + grub_menu_t menu; + struct menu_pointer *prev; +}; + +static struct menu_pointer initial_menu; +static struct menu_pointer *current_menu = &initial_menu; + +void +grub_env_unset_menu (void) +{ + current_menu->menu = NULL; +} + +grub_menu_t +grub_env_get_menu (void) +{ + return current_menu->menu; +} + +void +grub_env_set_menu (grub_menu_t nmenu) +{ + current_menu->menu = nmenu; +} + +static grub_err_t +grub_env_new_context (int export_all) +{ + struct grub_env_context *context; + int i; + struct menu_pointer *menu; + + context = grub_zalloc (sizeof (*context)); + if (! context) + return grub_errno; + menu = grub_zalloc (sizeof (*menu)); + if (! menu) + { + grub_free (context); + return grub_errno; + } + + context->prev = grub_current_context; + grub_current_context = context; + + menu->prev = current_menu; + current_menu = menu; + + /* Copy exported variables. */ + for (i = 0; i < HASHSZ; i++) + { + struct grub_env_var *var; + + for (var = context->prev->vars[i]; var; var = var->next) + if (var->global || export_all) + { + if (grub_env_set (var->name, var->value) != GRUB_ERR_NONE) + { + grub_env_context_close (); + return grub_errno; + } + grub_env_export (var->name); + grub_register_variable_hook (var->name, var->read_hook, var->write_hook); + } + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_env_context_open (void) +{ + return grub_env_new_context (grub_env_get("ventoy_new_context") ? 0 : 1); +} + +int grub_extractor_level = 0; + +grub_err_t +grub_env_extractor_open (int source) +{ + grub_extractor_level++; + return grub_env_new_context (source); +} + +grub_err_t +grub_env_context_close (void) +{ + struct grub_env_context *context; + int i; + struct menu_pointer *menu; + + if (! grub_current_context->prev) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "cannot close the initial context"); + + /* Free the variables associated with this context. */ + for (i = 0; i < HASHSZ; i++) + { + struct grub_env_var *p, *q; + + for (p = grub_current_context->vars[i]; p; p = q) + { + q = p->next; + grub_free (p->name); + grub_free (p->value); + grub_free (p); + } + } + + /* Restore the previous context. */ + context = grub_current_context->prev; + grub_free (grub_current_context); + grub_current_context = context; + + menu = current_menu->prev; + if (current_menu->menu) + grub_normal_free_menu (current_menu->menu); + grub_free (current_menu); + current_menu = menu; + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_env_extractor_close (int source) +{ + grub_menu_t menu = NULL; + grub_menu_entry_t *last; + grub_err_t err; + + if (source) + { + menu = grub_env_get_menu (); + grub_env_unset_menu (); + } + err = grub_env_context_close (); + + if (source && menu) + { + grub_menu_t menu2; + menu2 = grub_env_get_menu (); + + last = &menu2->entry_list; + while (*last) + last = &(*last)->next; + + *last = menu->entry_list; + menu2->size += menu->size; + } + + grub_extractor_level--; + return err; +} + +static grub_command_t export_cmd; + +static grub_err_t +grub_cmd_export (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + int i; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("one argument expected")); + + for (i = 0; i < argc; i++) + grub_env_export (args[i]); + + return 0; +} + +void +grub_context_init (void) +{ + export_cmd = grub_register_command ("export", grub_cmd_export, + N_("ENVVAR [ENVVAR] ..."), + N_("Export variables.")); +} + +void +grub_context_fini (void) +{ + grub_unregister_command (export_cmd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/main.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/main.c new file mode 100644 index 0000000..9a47039 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/main.c @@ -0,0 +1,575 @@ +/* main.c - the normal mode main routine */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define GRUB_DEFAULT_HISTORY_SIZE 50 + +static int nested_level = 0; +int grub_normal_exit_level = 0; + +void +grub_normal_free_menu (grub_menu_t menu) +{ + grub_menu_entry_t entry = menu->entry_list; + + while (entry) + { + grub_menu_entry_t next_entry = entry->next; + grub_size_t i; + + if (entry->classes) + { + struct grub_menu_entry_class *class; + for (class = entry->classes; class; class = class->next) + grub_free (class->name); + grub_free (entry->classes); + } + + if (entry->args) + { + for (i = 0; entry->args[i]; i++) + grub_free (entry->args[i]); + grub_free (entry->args); + } + + if (entry->bls) + { + entry->bls->visible = 0; + } + + grub_free ((void *) entry->id); + grub_free ((void *) entry->users); + grub_free ((void *) entry->title); + grub_free ((void *) entry->sourcecode); + grub_free (entry); + entry = next_entry; + } + + grub_free (menu); + grub_env_unset_menu (); +} + +/* Helper for read_config_file. */ +static grub_err_t +read_config_file_getline (char **line, int cont __attribute__ ((unused)), + void *data) +{ + grub_file_t file = data; + + while (1) + { + char *buf; + + *line = buf = grub_file_getline (file); + if (! buf) + return grub_errno; + + if (buf[0] == '#') + grub_free (*line); + else + break; + } + + return GRUB_ERR_NONE; +} + +static grub_menu_t +read_config_file (const char *config) +{ + grub_file_t rawfile, file; + char *old_file = 0, *old_dir = 0; + char *config_dir, *ptr = 0; + const char *ctmp; + + grub_menu_t newmenu; + + newmenu = grub_env_get_menu (); + if (! newmenu) + { + newmenu = grub_zalloc (sizeof (*newmenu)); + if (! newmenu) + return 0; + + grub_env_set_menu (newmenu); + } + + /* Try to open the config file. */ + rawfile = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); + if (! rawfile) + return 0; + + file = grub_bufio_open (rawfile, 0); + if (! file) + { + grub_file_close (rawfile); + return 0; + } + + ctmp = grub_env_get ("config_file"); + if (ctmp) + old_file = grub_strdup (ctmp); + ctmp = grub_env_get ("config_directory"); + if (ctmp) + old_dir = grub_strdup (ctmp); + if (*config == '(') + { + grub_env_set ("config_file", config); + config_dir = grub_strdup (config); + } + else + { + /* $root is guranteed to be defined, otherwise open above would fail */ + config_dir = grub_xasprintf ("(%s)%s", grub_env_get ("root"), config); + if (config_dir) + grub_env_set ("config_file", config_dir); + } + if (config_dir) + { + ptr = grub_strrchr (config_dir, '/'); + if (ptr) + *ptr = 0; + grub_env_set ("config_directory", config_dir); + grub_free (config_dir); + } + + grub_env_export ("config_file"); + grub_env_export ("config_directory"); + + while (1) + { + char *line; + + /* Print an error, if any. */ + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + + if ((read_config_file_getline (&line, 0, file)) || (! line)) + break; + + grub_normal_parse_line (line, read_config_file_getline, file); + grub_free (line); + } + + if (old_file) + grub_env_set ("config_file", old_file); + else + grub_env_unset ("config_file"); + if (old_dir) + grub_env_set ("config_directory", old_dir); + else + grub_env_unset ("config_directory"); + grub_free (old_file); + grub_free (old_dir); + + grub_file_close (file); + + return newmenu; +} + +/* Initialize the screen. */ +void +grub_normal_init_page (struct grub_term_output *term, + int y) +{ + grub_ssize_t msg_len; + int posx; + char *msg_formatted; + grub_uint32_t *unicode_msg; + grub_uint32_t *last_position; + + grub_term_cls (term); + + msg_formatted = grub_xasprintf (_("GNU GRUB version %s"), PACKAGE_VERSION); + if (!msg_formatted) + return; + + msg_len = grub_utf8_to_ucs4_alloc (msg_formatted, + &unicode_msg, &last_position); + grub_free (msg_formatted); + + if (msg_len < 0) + { + return; + } + + posx = grub_getstringwidth (unicode_msg, last_position, term); + posx = ((int) grub_term_width (term) - posx) / 2; + if (posx < 0) + posx = 0; + grub_term_gotoxy (term, (struct grub_term_coordinate) { posx, y }); + + grub_print_ucs4 (unicode_msg, last_position, 0, 0, term); + grub_putcode ('\n', term); + grub_putcode ('\n', term); + grub_free (unicode_msg); +} + +static void +read_lists (const char *val) +{ + if (! grub_no_modules) + { + read_command_list (val); + read_fs_list (val); + read_crypto_list (val); + read_terminal_list (val); + } + grub_gettext_reread_prefix (val); +} + +static char * +read_lists_hook (struct grub_env_var *var __attribute__ ((unused)), + const char *val) +{ + read_lists (val); + return val ? grub_strdup (val) : NULL; +} + +/* Read the config file CONFIG and execute the menu interface or + the command line interface if BATCH is false. */ +void +grub_normal_execute (const char *config, int nested, int batch) +{ + grub_menu_t menu = 0; + const char *prefix; + + if (! nested) + { + prefix = grub_env_get ("prefix"); + read_lists (prefix); + grub_register_variable_hook ("prefix", NULL, read_lists_hook); + } + + grub_boot_time ("Executing config file"); + + if (config) + { + menu = read_config_file (config); + + /* Ignore any error. */ + grub_errno = GRUB_ERR_NONE; + } + + grub_boot_time ("Executed config file"); + + if (! batch) + { + if (menu && menu->size) + { + + grub_boot_time ("Entering menu"); + grub_show_menu (menu, nested, 0); + if (nested) + grub_normal_free_menu (menu); + } + } +} + +/* This starts the normal mode. */ +void +grub_enter_normal_mode (const char *config) +{ + grub_boot_time ("Entering normal mode"); + nested_level++; + grub_normal_execute (config, 0, 0); + grub_boot_time ("Entering shell"); + grub_cmdline_run (0, 1); + nested_level--; + if (grub_normal_exit_level) + grub_normal_exit_level--; + grub_boot_time ("Exiting normal mode"); +} + +/* Enter normal mode from rescue mode. */ +static grub_err_t +grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + if (argc == 0) + { + /* Guess the config filename. It is necessary to make CONFIG static, + so that it won't get broken by longjmp. */ + char *config; + const char *prefix; + + prefix = grub_env_get ("prefix"); + if (prefix) + { + config = grub_xasprintf ("%s/grub.cfg", prefix); + if (! config) + goto quit; + + grub_enter_normal_mode (config); + grub_free (config); + } + else + grub_enter_normal_mode (0); + } + else + grub_enter_normal_mode (argv[0]); + +quit: + return 0; +} + +/* Exit from normal mode to rescue mode. */ +static grub_err_t +grub_cmd_normal_exit (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + if (nested_level <= grub_normal_exit_level) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in normal environment"); + grub_normal_exit_level++; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_normal_reader_init (int nested) +{ + struct grub_term_output *term; + const char *msg_esc = _("ESC at any time exits."); + char *msg_formatted; + + msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For " + "the first word, TAB lists possible command completions. Anywhere " + "else TAB lists possible device or file completions. %s"), + nested ? msg_esc : ""); + if (!msg_formatted) + return grub_errno; + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + grub_normal_init_page (term, 1); + grub_term_setcursor (term, 1); + + if (grub_term_width (term) > 3 + STANDARD_MARGIN + 20) + grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term); + else + grub_print_message_indented (msg_formatted, 0, 0, term); + grub_putcode ('\n', term); + grub_putcode ('\n', term); + grub_putcode ('\n', term); + } + grub_free (msg_formatted); + + return 0; +} + +static grub_err_t +grub_normal_read_line_real (char **line, int cont, int nested) +{ + const char *prompt; + + if (cont) + /* TRANSLATORS: it's command line prompt. */ + prompt = _(">"); + else + /* TRANSLATORS: it's command line prompt. */ + prompt = _("grub>"); + + if (!prompt) + return grub_errno; + + while (1) + { + *line = grub_cmdline_get (prompt); + if (*line) + return 0; + + if (cont || nested) + { + grub_free (*line); + *line = 0; + return grub_errno; + } + } + +} + +static grub_err_t +grub_normal_read_line (char **line, int cont, + void *data __attribute__ ((unused))) +{ + return grub_normal_read_line_real (line, cont, 0); +} + +void +grub_cmdline_run (int nested, int force_auth) +{ + grub_err_t err = GRUB_ERR_NONE; + + do + { + err = grub_auth_check_authentication (NULL); + } + while (err && force_auth); + + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } + + grub_normal_reader_init (nested); + + while (1) + { + char *line = NULL; + + if (grub_normal_exit_level) + break; + + /* Print an error, if any. */ + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + + grub_normal_read_line_real (&line, 0, nested); + if (! line) + break; + + grub_normal_parse_line (line, grub_normal_read_line, NULL); + grub_free (line); + } +} + +static char * +grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)), + const char *val) +{ + grub_set_more ((*val == '1')); + return grub_strdup (val); +} + +/* clear */ +static grub_err_t +grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + grub_cls (); + return 0; +} + +static grub_command_t cmd_clear; + +static void (*grub_xputs_saved) (const char *str); +static const char *features[] = { + "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint", + "feature_default_font_path", "feature_all_video_module", + "feature_menuentry_id", "feature_menuentry_options", "feature_200_final", + "feature_nativedisk_cmd", "feature_timeout_style" +}; + +GRUB_MOD_INIT(normal) +{ + unsigned i; + + grub_boot_time ("Preparing normal module"); + + /* Previously many modules depended on gzio. Be nice to user and load it. */ + grub_dl_load ("gzio"); + grub_errno = 0; + + grub_normal_auth_init (); + grub_context_init (); + grub_script_init (); + grub_menu_init (); + + grub_xputs_saved = grub_xputs; + grub_xputs = grub_xputs_normal; + + /* Normal mode shouldn't be unloaded. */ + if (mod) + grub_dl_ref (mod); + + cmd_clear = + grub_register_command ("clear", grub_mini_cmd_clear, + 0, N_("Clear the screen.")); + + grub_set_history (GRUB_DEFAULT_HISTORY_SIZE); + + grub_register_variable_hook ("pager", 0, grub_env_write_pager); + grub_env_export ("pager"); + + /* Register a command "normal" for the rescue mode. */ + grub_register_command ("normal", grub_cmd_normal, + 0, N_("Enter normal mode.")); + grub_register_command ("normal_exit", grub_cmd_normal_exit, + 0, N_("Exit from normal mode.")); + + /* Reload terminal colors when these variables are written to. */ + grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal); + grub_register_variable_hook ("color_highlight", NULL, grub_env_write_color_highlight); + + /* Preserve hooks after context changes. */ + grub_env_export ("color_normal"); + grub_env_export ("color_highlight"); + + /* Set default color names. */ + grub_env_set ("color_normal", "light-gray/black"); + grub_env_set ("color_highlight", "black/light-gray"); + + for (i = 0; i < ARRAY_SIZE (features); i++) + { + grub_env_set (features[i], "y"); + grub_env_export (features[i]); + } + grub_env_set ("grub_cpu", GRUB_TARGET_CPU); + grub_env_export ("grub_cpu"); + grub_env_set ("grub_platform", GRUB_PLATFORM); + grub_env_export ("grub_platform"); + + grub_boot_time ("Normal module prepared"); +} + +GRUB_MOD_FINI(normal) +{ + grub_context_fini (); + grub_script_fini (); + grub_menu_fini (); + grub_normal_auth_fini (); + + grub_xputs = grub_xputs_saved; + + grub_set_history (0); + grub_register_variable_hook ("pager", 0, 0); + grub_fs_autoload_hook = 0; + grub_unregister_command (cmd_clear); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c new file mode 100644 index 0000000..d05a480 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu.c @@ -0,0 +1,1234 @@ +/* menu.c - General supporting functionality for menus. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ventoy/ventoy_def.h" + +int g_ventoy_menu_refresh = 0; +int g_ventoy_memdisk_mode = 0; +int g_ventoy_iso_raw = 0; +int g_ventoy_grub2_mode = 0; +int g_ventoy_wimboot_mode = 0; +int g_ventoy_iso_uefi_drv = 0; +int g_ventoy_last_entry = -1; +int g_ventoy_suppress_esc = 0; +int g_ventoy_suppress_esc_default = 1; +int g_ventoy_menu_esc = 0; +int g_ventoy_fn_mutex = 0; +int g_ventoy_secondary_menu_on = 0; +int g_ventoy_terminal_output = 0; +char g_ventoy_hotkey_tip[256]; + +static int g_vt_key_num = 0; +static int g_vt_key_code[128]; + +static int ventoy_menu_pop_key(void) +{ + if (g_vt_key_num > 0 && g_vt_key_num < (int)(sizeof(g_vt_key_code) / sizeof(g_vt_key_code[0]))) + { + g_vt_key_num--; + return g_vt_key_code[g_vt_key_num]; + } + return -1; +} + +int ventoy_menu_push_key(int code) +{ + if (g_vt_key_num >= 0 && g_vt_key_num < (int)(sizeof(g_vt_key_code) / sizeof(g_vt_key_code[0]))) + { + g_vt_key_code[g_vt_key_num++] = code; + return 0; + } + return -1; +} + +#define VTOY_COMM_HOTKEY(cmdkey) \ +if (0 == g_ventoy_fn_mutex && 0 == g_ventoy_secondary_menu_on) { \ + cmdstr = grub_env_get(cmdkey); \ + if (cmdstr) \ + { \ + menu_fini (); \ + g_ventoy_fn_mutex = 1; \ + grub_script_execute_sourcecode(cmdstr); \ + g_ventoy_fn_mutex = 0; \ + goto refresh; \ + } \ +} + +/* Time to delay after displaying an error message about a default/fallback + entry failing to boot. */ +#define DEFAULT_ENTRY_ERROR_DELAY_MS 2500 + +grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, + int nested) = NULL; + +enum timeout_style { + TIMEOUT_STYLE_MENU, + TIMEOUT_STYLE_COUNTDOWN, + TIMEOUT_STYLE_HIDDEN +}; + +struct timeout_style_name { + const char *name; + enum timeout_style style; +} timeout_style_names[] = { + {"menu", TIMEOUT_STYLE_MENU}, + {"countdown", TIMEOUT_STYLE_COUNTDOWN}, + {"hidden", TIMEOUT_STYLE_HIDDEN}, + {NULL, 0} +}; + +/* Wait until the user pushes any key so that the user + can see what happened. */ +void +grub_wait_after_message (void) +{ + grub_uint64_t endtime; + grub_xputs ("\n"); + grub_printf_ (N_("Press any key to continue...")); + grub_refresh (); + + endtime = grub_get_time_ms () + 10000; + + while (grub_get_time_ms () < endtime + && grub_getkey_noblock () == GRUB_TERM_NO_KEY); + + grub_xputs ("\n"); +} + +/* Get a menu entry by its index in the entry list. */ +grub_menu_entry_t +grub_menu_get_entry (grub_menu_t menu, int no) +{ + grub_menu_entry_t e; + + for (e = menu->entry_list; e && no > 0; e = e->next, no--) + ; + + return e; +} + +/* Get the index of a menu entry associated with a given hotkey, or -1. */ +static int +get_entry_index_by_hotkey (grub_menu_t menu, int hotkey) +{ + grub_menu_entry_t entry; + int i; + + for (i = 0, entry = menu->entry_list; i < menu->size; + i++, entry = entry->next) + if (entry->hotkey == hotkey) + return i; + + return -1; +} + +/* Return the timeout style. If the variable "timeout_style" is not set or + invalid, default to TIMEOUT_STYLE_MENU. */ +static enum timeout_style +get_timeout_style (void) +{ + const char *val; + struct timeout_style_name *style_name; + + val = grub_env_get ("timeout_style"); + if (!val) + return TIMEOUT_STYLE_MENU; + + for (style_name = timeout_style_names; style_name->name; style_name++) + if (grub_strcmp (style_name->name, val) == 0) + return style_name->style; + + return TIMEOUT_STYLE_MENU; +} + +/* Return the current timeout. If the variable "timeout" is not set or + invalid, return -1. */ +int +grub_menu_get_timeout (void) +{ + const char *val; + int timeout; + + val = grub_env_get ("timeout"); + if (! val) + return -1; + + grub_error_push (); + + timeout = (int) grub_strtoul (val, 0, 0); + + /* If the value is invalid, unset the variable. */ + if (grub_errno != GRUB_ERR_NONE) + { + grub_env_unset ("timeout"); + grub_errno = GRUB_ERR_NONE; + timeout = -1; + } + + grub_error_pop (); + + return timeout; +} + +/* Set current timeout in the variable "timeout". */ +void +grub_menu_set_timeout (int timeout) +{ + /* Ignore TIMEOUT if it is zero, because it will be unset really soon. */ + if (timeout > 0) + { + char buf[16]; + + grub_snprintf (buf, sizeof (buf), "%d", timeout); + grub_env_set ("timeout", buf); + } +} + +/* Get the first entry number from the value of the environment variable NAME, + which is a space-separated list of non-negative integers. The entry number + which is returned is stripped from the value of NAME. If no entry number + can be found, -1 is returned. */ +static int +get_and_remove_first_entry_number (const char *name) +{ + const char *val; + char *tail; + int entry; + + val = grub_env_get (name); + if (! val) + return -1; + + grub_error_push (); + + entry = (int) grub_strtoul (val, &tail, 0); + + if (grub_errno == GRUB_ERR_NONE) + { + /* Skip whitespace to find the next digit. */ + while (*tail && grub_isspace (*tail)) + tail++; + grub_env_set (name, tail); + } + else + { + grub_env_unset (name); + grub_errno = GRUB_ERR_NONE; + entry = -1; + } + + grub_error_pop (); + + return entry; +} + +/* Run a menu entry. */ +static void +grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) +{ + grub_err_t err = GRUB_ERR_NONE; + int errs_before; + grub_menu_t menu = NULL; + char *optr, *buf, *oldchosen = NULL, *olddefault = NULL; + const char *ptr, *chosen, *def; + grub_size_t sz = 0; + + if (entry->restricted) + err = grub_auth_check_authentication (entry->users); + + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } + + errs_before = grub_err_printed_errors; + + chosen = grub_env_get ("chosen"); + def = grub_env_get ("default"); + + if (entry->submenu) + { + grub_env_context_open (); + menu = grub_zalloc (sizeof (*menu)); + if (! menu) + return; + grub_env_set_menu (menu); + if (auto_boot) + grub_env_set ("timeout", "0"); + } + + for (ptr = entry->id; *ptr; ptr++) + sz += (*ptr == '>') ? 2 : 1; + if (chosen) + { + oldchosen = grub_strdup (chosen); + if (!oldchosen) + grub_print_error (); + } + if (def) + { + olddefault = grub_strdup (def); + if (!olddefault) + grub_print_error (); + } + sz++; + if (chosen) + sz += grub_strlen (chosen); + sz++; + buf = grub_malloc (sz); + if (!buf) + grub_print_error (); + else + { + optr = buf; + if (chosen) + { + optr = grub_stpcpy (optr, chosen); + *optr++ = '>'; + } + for (ptr = entry->id; *ptr; ptr++) + { + if (*ptr == '>') + *optr++ = '>'; + *optr++ = *ptr; + } + *optr = 0; + grub_env_set ("chosen", buf); + grub_env_export ("chosen"); + grub_free (buf); + } + + for (ptr = def; ptr && *ptr; ptr++) + { + if (ptr[0] == '>' && ptr[1] == '>') + { + ptr++; + continue; + } + if (ptr[0] == '>') + break; + } + + if (ptr && ptr[0] && ptr[1]) + grub_env_set ("default", ptr + 1); + else + grub_env_unset ("default"); + + grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); + + if (errs_before != grub_err_printed_errors) + grub_wait_after_message (); + + errs_before = grub_err_printed_errors; + + if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) + /* Implicit execution of boot, only if something is loaded. */ + grub_command_execute ("boot", 0, 0); + + if (errs_before != grub_err_printed_errors) + grub_wait_after_message (); + + if (entry->submenu) + { + if (menu && menu->size) + { + grub_show_menu (menu, 1, auto_boot); + grub_normal_free_menu (menu); + } + grub_env_context_close (); + } + if (oldchosen) + grub_env_set ("chosen", oldchosen); + else + grub_env_unset ("chosen"); + if (olddefault) + grub_env_set ("default", olddefault); + else + grub_env_unset ("default"); + grub_env_unset ("timeout"); +} + +/* Execute ENTRY from the menu MENU, falling back to entries specified + in the environment variable "fallback" if it fails. CALLBACK is a + pointer to a struct of function pointers which are used to allow the + caller provide feedback to the user. */ +static void +grub_menu_execute_with_fallback (grub_menu_t menu, + grub_menu_entry_t entry, + int autobooted, + grub_menu_execute_callback_t callback, + void *callback_data) +{ + int fallback_entry; + + callback->notify_booting (entry, callback_data); + + grub_menu_execute_entry (entry, 1); + + /* Deal with fallback entries. */ + while ((fallback_entry = get_and_remove_first_entry_number ("fallback")) + >= 0) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + + entry = grub_menu_get_entry (menu, fallback_entry); + callback->notify_fallback (entry, callback_data); + grub_menu_execute_entry (entry, 1); + /* If the function call to execute the entry returns at all, then this is + taken to indicate a boot failure. For menu entries that do something + other than actually boot an operating system, this could assume + incorrectly that something failed. */ + } + + if (!autobooted) + callback->notify_failure (callback_data); +} + +static struct grub_menu_viewer *viewers; + +int g_menu_update_mode = 0; +int g_ventoy_tip_label_enable = 0; +const char * g_ventoy_tip_msg1 = NULL; +const char * g_ventoy_tip_msg2 = NULL; +char g_ventoy_theme_path[256] = {0}; +static const char *g_ventoy_cur_img_path = NULL; +static void menu_set_chosen_tip(grub_menu_t menu, int entry) +{ + int i; + img_info *img; + menu_tip *tip; + grub_menu_entry_t e = grub_menu_get_entry (menu, entry); + + if (g_ventoy_theme_path[0]) + { + grub_env_set("theme", g_ventoy_theme_path); + } + + g_ventoy_tip_msg1 = g_ventoy_tip_msg2 = NULL; + if (e && e->id && grub_strncmp(e->id, "VID_", 4) == 0) + { + g_ventoy_theme_path[0] = 0; + img = (img_info *)(void *)grub_strtoul(e->id + 4, NULL, 16); + if (img) + { + g_ventoy_tip_msg1 = img->tip1; + g_ventoy_tip_msg2 = img->tip2; + g_ventoy_cur_img_path = img->path; + } + } + else if (e && e->id && grub_strncmp(e->id, "DIR_", 4) == 0) + { + g_ventoy_theme_path[0] = 0; + for (i = 0; i < e->argc; i++) + { + if (e->args[i] && grub_strncmp(e->args[i], "_VTIP_", 6) == 0) + { + break; + } + } + + if (i < e->argc) + { + tip = (menu_tip *)(void *)grub_strtoul(e->args[i] + 6, NULL, 16); + if (tip) + { + g_ventoy_tip_msg1 = tip->tip1; + g_ventoy_tip_msg2 = tip->tip2; + } + } + } +} + +static void +menu_set_chosen_entry (grub_menu_t menu, int entry) +{ + struct grub_menu_viewer *cur; + + menu_set_chosen_tip(menu, entry); + for (cur = viewers; cur; cur = cur->next) + cur->set_chosen_entry (entry, cur->data); +} + +static void +menu_scroll_chosen_entry (int diren) +{ + struct grub_menu_viewer *cur; + for (cur = viewers; cur; cur = cur->next) + if (cur->scroll_chosen_entry) + cur->scroll_chosen_entry (cur->data, diren); +} + +static void +menu_print_timeout (int timeout) +{ + struct grub_menu_viewer *cur; + for (cur = viewers; cur; cur = cur->next) + cur->print_timeout (timeout, cur->data); +} + +static void +menu_fini (void) +{ + struct grub_menu_viewer *cur, *next; + for (cur = viewers; cur; cur = next) + { + next = cur->next; + cur->fini (cur->data); + grub_free (cur); + } + viewers = NULL; +} + +static void +menu_init (int entry, grub_menu_t menu, int nested) +{ + struct grub_term_output *term; + int gfxmenu = 0; + + FOR_ACTIVE_TERM_OUTPUTS(term) + if (term->fullscreen) + { + if (grub_env_get ("theme")) + { + if (!grub_gfxmenu_try_hook) + { + grub_dl_load ("gfxmenu"); + grub_print_error (); + } + if (grub_gfxmenu_try_hook) + { + grub_err_t err; + err = grub_gfxmenu_try_hook (entry, menu, nested); + if(!err) + { + gfxmenu = 1; + break; + } + } + else + grub_error (GRUB_ERR_BAD_MODULE, + N_("module `%s' isn't loaded"), + "gfxmenu"); + grub_print_error (); + grub_wait_after_message (); + } + grub_errno = GRUB_ERR_NONE; + term->fullscreen (); + break; + } + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + grub_err_t err; + + if (grub_strcmp (term->name, "gfxterm") == 0 && gfxmenu) + continue; + + err = grub_menu_try_text (term, entry, menu, nested); + if(!err) + continue; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } +} + +static void +clear_timeout (void) +{ + struct grub_menu_viewer *cur; + for (cur = viewers; cur; cur = cur->next) + cur->clear_timeout (cur->data); +} + +void +grub_menu_register_viewer (struct grub_menu_viewer *viewer) +{ + viewer->next = viewers; + viewers = viewer; +} + +static int +menuentry_eq (const char *id, const char *spec) +{ + const char *ptr1, *ptr2; + ptr1 = id; + ptr2 = spec; + while (1) + { + if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) + return 1; + if (*ptr2 == '>' && ptr2[1] != '>') + return 0; + if (*ptr2 == '>') + ptr2++; + if (*ptr1 != *ptr2) + return 0; + if (*ptr1 == 0) + return 1; + ptr1++; + ptr2++; + } +} + + +/* Get the entry number from the variable NAME. */ +static int +get_entry_number (grub_menu_t menu, const char *name) +{ + const char *val; + int entry; + + val = grub_env_get (name); + if (! val) + return -1; + + grub_error_push (); + + entry = (int) grub_strtoul (val, 0, 0); + + if (grub_errno == GRUB_ERR_BAD_NUMBER) + { + /* See if the variable matches the title of a menu entry. */ + grub_menu_entry_t e = menu->entry_list; + int i; + + grub_errno = GRUB_ERR_NONE; + + for (i = 0; e; i++) + { + if (menuentry_eq (e->title, val) + || menuentry_eq (e->id, val)) + { + entry = i; + break; + } + e = e->next; + } + + if (! e) + entry = -1; + } + + if (grub_errno != GRUB_ERR_NONE) + { + grub_errno = GRUB_ERR_NONE; + entry = -1; + } + + grub_error_pop (); + + return entry; +} + +/* Check whether a second has elapsed since the last tick. If so, adjust + the timer and return 1; otherwise, return 0. */ +static int +has_second_elapsed (grub_uint64_t *saved_time) +{ + grub_uint64_t current_time; + + current_time = grub_get_time_ms (); + if (current_time - *saved_time >= 1000) + { + *saved_time = current_time; + return 1; + } + else + return 0; +} + +static void +print_countdown (struct grub_term_coordinate *pos, int n) +{ + grub_term_restore_pos (pos); + /* NOTE: Do not remove the trailing space characters. + They are required to clear the line. */ + grub_printf ("%d ", n); + grub_refresh (); +} + +#define GRUB_MENU_PAGE_SIZE 10 + +/* Show the menu and handle menu entry selection. Returns the menu entry + index that should be executed or -1 if no entry should be executed (e.g., + Esc pressed to exit a sub-menu or switching menu viewers). + If the return value is not -1, then *AUTO_BOOT is nonzero iff the menu + entry to be executed is a result of an automatic default selection because + of the timeout. */ +static int +run_menu (grub_menu_t menu, int nested, int *auto_boot) +{ + const char *cmdstr; + grub_uint64_t saved_time; + int default_entry,current_entry; + int timeout; + enum timeout_style timeout_style; + + default_entry = get_entry_number (menu, "default"); + + if (g_ventoy_suppress_esc) + default_entry = g_ventoy_suppress_esc_default; + + /* If DEFAULT_ENTRY is not within the menu entries, fall back to + the first entry. */ + else if (default_entry < 0 || default_entry >= menu->size) + default_entry = 0; + + timeout = grub_menu_get_timeout (); + if (timeout < 0) + /* If there is no timeout, the "countdown" and "hidden" styles result in + the system doing nothing and providing no or very little indication + why. Technically this is what the user asked for, but it's not very + useful and likely to be a source of confusion, so we disallow this. */ + grub_env_unset ("timeout_style"); + + timeout_style = get_timeout_style (); + + if (timeout_style == TIMEOUT_STYLE_COUNTDOWN + || timeout_style == TIMEOUT_STYLE_HIDDEN) + { + static struct grub_term_coordinate *pos; + int entry = -1; + + if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout) + { + pos = grub_term_save_pos (); + print_countdown (pos, timeout); + } + + /* Enter interruptible sleep until Escape or a menu hotkey is pressed, + or the timeout expires. */ + saved_time = grub_get_time_ms (); + while (1) + { + int key; + + key = grub_getkey_noblock (); + if (key != GRUB_TERM_NO_KEY) + { + entry = get_entry_index_by_hotkey (menu, key); + if (entry >= 0) + break; + } + if (key == GRUB_TERM_ESC) + { + timeout = -1; + break; + } + + if (timeout > 0 && has_second_elapsed (&saved_time)) + { + timeout--; + if (timeout_style == TIMEOUT_STYLE_COUNTDOWN) + print_countdown (pos, timeout); + } + + if (timeout == 0) + /* We will fall through to auto-booting the default entry. */ + break; + } + + grub_env_unset ("timeout"); + grub_env_unset ("timeout_style"); + if (entry >= 0) + { + *auto_boot = 0; + return entry; + } + } + + /* If timeout is 0, drawing is pointless (and ugly). */ + if (timeout == 0) + { + *auto_boot = 1; + return default_entry; + } + + current_entry = default_entry; + + refresh: + menu_set_chosen_tip(menu, current_entry); + menu_init (current_entry, menu, nested); + + /* Initialize the time. */ + saved_time = grub_get_time_ms (); + + timeout = grub_menu_get_timeout (); + + if (timeout > 0) + menu_print_timeout (timeout); + else + clear_timeout (); + + while (1) + { + int c; + timeout = grub_menu_get_timeout (); + + if (grub_normal_exit_level) + return -1; + + if (timeout > 0 && has_second_elapsed (&saved_time)) + { + timeout--; + grub_menu_set_timeout (timeout); + menu_print_timeout (timeout); + } + + if (timeout == 0) + { + grub_env_unset ("timeout"); + *auto_boot = 1; + menu_fini (); + return default_entry; + } + + if (g_vt_key_num > 0) { + c = ventoy_menu_pop_key(); + } else { + c = grub_getkey_noblock (); + } + + /* Negative values are returned on error. */ + if ((c != GRUB_TERM_NO_KEY) && (c > 0)) + { + if (timeout >= 0) + { + grub_env_unset ("timeout"); + grub_env_unset ("fallback"); + clear_timeout (); + } + + switch (c) + { + case GRUB_TERM_KEY_HOME: + case GRUB_TERM_CTRL | 'a': + current_entry = 0; + menu_set_chosen_entry (menu, current_entry); + break; + + case GRUB_TERM_KEY_END: + case GRUB_TERM_CTRL | 'e': + current_entry = menu->size - 1; + menu_set_chosen_entry (menu, current_entry); + break; + + case GRUB_TERM_KEY_UP: + case GRUB_TERM_CTRL | 'p': + case '^': + if (current_entry > 0) + current_entry--; + menu_set_chosen_entry (menu, current_entry); + break; + + case GRUB_TERM_CTRL | 'n': + case GRUB_TERM_KEY_DOWN: + case 'v': + if (current_entry < menu->size - 1) + current_entry++; + menu_set_chosen_entry (menu, current_entry); + break; + + case GRUB_TERM_CTRL | 'g': + case GRUB_TERM_KEY_PPAGE: + if (current_entry < GRUB_MENU_PAGE_SIZE) + current_entry = 0; + else + current_entry -= GRUB_MENU_PAGE_SIZE; + menu_set_chosen_entry (menu, current_entry); + break; + + case GRUB_TERM_CTRL | 'c': + case GRUB_TERM_KEY_NPAGE: + if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size) + current_entry += GRUB_MENU_PAGE_SIZE; + else + current_entry = menu->size - 1; + menu_set_chosen_entry (menu, current_entry); + break; + + case GRUB_TERM_KEY_RIGHT: + menu_scroll_chosen_entry (1); + break; + case GRUB_TERM_KEY_LEFT: + menu_scroll_chosen_entry (-1); + break; + case GRUB_TERM_CTRL | GRUB_TERM_KEY_RIGHT: + menu_scroll_chosen_entry (1000000); + break; + case GRUB_TERM_CTRL | GRUB_TERM_KEY_LEFT: + menu_scroll_chosen_entry (-1000000); + break; + + case '\n': + case '\r': + // case GRUB_TERM_KEY_RIGHT: + case GRUB_TERM_CTRL | 'f': + menu_fini (); + *auto_boot = 0; + return current_entry; + + case GRUB_TERM_ESC: + if (nested && 0 == g_ventoy_suppress_esc) + { + menu_fini (); + return -1; + } + break; + + case 'c': + menu_fini (); + grub_cmdline_run (1, 0); + goto refresh; + + case 'e': + menu_fini (); + { + grub_menu_entry_t e = grub_menu_get_entry (menu, current_entry); + if (e) + grub_menu_entry_run (e); + } + goto refresh; + + case GRUB_TERM_KEY_F2: + case '2': + VTOY_COMM_HOTKEY("VTOY_F2_CMD"); + break; + case GRUB_TERM_KEY_F3: + case '3': + VTOY_COMM_HOTKEY("VTOY_F3_CMD"); + break; + case GRUB_TERM_KEY_F4: + case '4': + VTOY_COMM_HOTKEY("VTOY_F4_CMD"); + break; + case GRUB_TERM_KEY_F5: + case '5': + VTOY_COMM_HOTKEY("VTOY_F5_CMD"); + break; + case GRUB_TERM_KEY_F6: + case '6': + VTOY_COMM_HOTKEY("VTOY_F6_CMD"); + break; + case GRUB_TERM_KEY_F7: + menu_fini (); + if (g_ventoy_terminal_output == 0) + { + grub_script_execute_sourcecode("vt_push_menu_lang en_US\nterminal_output console"); + g_ventoy_terminal_output = 1; + } + else + { + grub_script_execute_sourcecode("terminal_output gfxterm\nvt_pop_menu_lang"); + g_ventoy_terminal_output = 0; + } + goto refresh; + case GRUB_TERM_KEY_F1: + case '1': + if (0 == g_ventoy_secondary_menu_on) + { + cmdstr = grub_env_get("VTOY_HELP_CMD"); + if (cmdstr) + { + grub_script_execute_sourcecode(cmdstr); + while (grub_getkey() != GRUB_TERM_ESC) + ; + menu_fini (); + goto refresh; + } + } + break; + case (GRUB_TERM_CTRL | 'd'): + case 'd': + if (0 == g_ventoy_secondary_menu_on) + { + menu_fini (); + g_ventoy_memdisk_mode = 1 - g_ventoy_memdisk_mode; + g_ventoy_menu_refresh = 1; + goto refresh; + } + break; + case (GRUB_TERM_CTRL | 'i'): + case 'i': + if (0 == g_ventoy_secondary_menu_on) + { + menu_fini (); + g_ventoy_iso_raw = 1 - g_ventoy_iso_raw; + g_ventoy_menu_refresh = 1; + goto refresh; + } + break; + case (GRUB_TERM_CTRL | 'r'): + case 'r': + if (0 == g_ventoy_secondary_menu_on) + { + menu_fini (); + g_ventoy_grub2_mode = 1 - g_ventoy_grub2_mode; + g_ventoy_menu_refresh = 1; + goto refresh; + } + break; + case (GRUB_TERM_CTRL | 'w'): + case 'w': + if (0 == g_ventoy_secondary_menu_on) + { + menu_fini (); + g_ventoy_wimboot_mode = 1 - g_ventoy_wimboot_mode; + g_ventoy_menu_refresh = 1; + goto refresh; + } + break; + case (GRUB_TERM_CTRL | 'u'): + case 'u': + if (0 == g_ventoy_secondary_menu_on) + { + menu_fini (); + g_ventoy_iso_uefi_drv = 1 - g_ventoy_iso_uefi_drv; + g_ventoy_menu_refresh = 1; + goto refresh; + } + break; + case (GRUB_TERM_CTRL | 'l'): + case (GRUB_TERM_CTRL | 'L'): + case (GRUB_TERM_SHIFT | 'l'): + case (GRUB_TERM_SHIFT | 'L'): + case 'l': + case 'L': + { + VTOY_COMM_HOTKEY("VTOY_LANG_CMD"); + break; + } + case (GRUB_TERM_CTRL | 'm'): + case 'm': + { + if (0 == g_ventoy_secondary_menu_on) + { + if (g_ventoy_cur_img_path) + { + grub_env_set("VTOY_CHKSUM_FILE_PATH", g_ventoy_cur_img_path); + cmdstr = grub_env_get("VTOY_CHKSUM_CMD"); + if (cmdstr) + { + menu_fini(); + grub_script_execute_sourcecode(cmdstr); + goto refresh; + } + } + else + { + grub_env_set("VTOY_CHKSUM_FILE_PATH", "X"); + } + } + break; + } + default: + { + int entry; + + entry = get_entry_index_by_hotkey (menu, c); + if (entry >= 0) + { + menu_fini (); + *auto_boot = 0; + return entry; + } + } + break; + } + } + } + + /* Never reach here. */ +} + +/* Callback invoked immediately before a menu entry is executed. */ +static void +notify_booting (grub_menu_entry_t entry, + void *userdata __attribute__((unused))) +{ + grub_printf (" "); + grub_printf_ (N_("Booting `%s'"), entry->title); + grub_printf ("\n\n"); +} + +/* Callback invoked when a default menu entry executed because of a timeout + has failed and an attempt will be made to execute the next fallback + entry, ENTRY. */ +static void +notify_fallback (grub_menu_entry_t entry, + void *userdata __attribute__((unused))) +{ + grub_printf ("\n "); + grub_printf_ (N_("Falling back to `%s'"), entry->title); + grub_printf ("\n\n"); + grub_millisleep (DEFAULT_ENTRY_ERROR_DELAY_MS); +} + +/* Callback invoked when a menu entry has failed and there is no remaining + fallback entry to attempt. */ +static void +notify_execution_failure (void *userdata __attribute__((unused))) +{ + if (grub_errno != GRUB_ERR_NONE) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + grub_printf ("\n "); + grub_printf_ (N_("Failed to boot both default and fallback entries.\n")); + grub_wait_after_message (); +} + +/* Callbacks used by the text menu to provide user feedback when menu entries + are executed. */ +static struct grub_menu_execute_callback execution_callback = +{ + .notify_booting = notify_booting, + .notify_fallback = notify_fallback, + .notify_failure = notify_execution_failure +}; + +static grub_err_t +show_menu (grub_menu_t menu, int nested, int autobooted) +{ + const char *def; + def = grub_env_get("VTOY_DEFAULT_IMAGE"); + + while (1) + { + int ndown; + char *pos = NULL; + int boot_entry; + grub_menu_entry_t e; + int auto_boot; + + boot_entry = run_menu (menu, nested, &auto_boot); + if (boot_entry < 0) + break; + + if (auto_boot && def && grub_strcmp(def, "VTOY_EXIT") == 0) { + grub_exit(); + } + + if (autobooted == 0 && auto_boot == 0) { + g_ventoy_last_entry = boot_entry; + if (g_ventoy_menu_esc) + break; + } + + if (autobooted == 0 && g_ventoy_menu_esc && auto_boot) { + g_ventoy_last_entry = boot_entry; + break; + } + + e = grub_menu_get_entry (menu, boot_entry); + if (! e) + continue; /* Menu is empty. */ + + if (2 == e->argc && e->args && e->args[1] && grub_strncmp(e->args[1], "VTOY_RET", 8) == 0) + break; + + grub_cls (); + + if (auto_boot) + grub_menu_execute_with_fallback (menu, e, autobooted, + &execution_callback, 0); + else + grub_menu_execute_entry (e, 0); + if (autobooted) + break; + + if (2 == e->argc && e->args && e->args[1] && grub_strncmp(e->args[1], "VTOY_RUN_RET", 12) == 0) + break; + else if (2 == e->argc && e->args && e->args[1] && grub_strncmp(e->args[1], "VTOY_RUN_SET_", 13) == 0) { + pos = NULL; + ndown = (int)grub_strtol(e->args[1] + 13, &pos, 10); + while (ndown > 0) + { + ventoy_menu_push_key(GRUB_TERM_KEY_DOWN); + ndown--; + } + + ventoy_menu_push_key('\n'); + + if (pos && *pos == '_') + { + ndown = (int)grub_strtol(pos + 1, NULL, 10); + while (ndown > 0) + { + ventoy_menu_push_key(GRUB_TERM_KEY_DOWN); + ndown--; + } + } + + break; + } + } + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_show_menu (grub_menu_t menu, int nested, int autoboot) +{ + grub_err_t err1, err2; + + while (1) + { + err1 = show_menu (menu, nested, autoboot); + autoboot = 0; + grub_print_error (); + + if (grub_normal_exit_level) + break; + + err2 = grub_auth_check_authentication (NULL); + if (err2) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + continue; + } + + break; + } + + return err1; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu_text.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu_text.c new file mode 100644 index 0000000..00c53c6 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/menu_text.c @@ -0,0 +1,655 @@ +/* menu_text.c - Basic text menu implementation. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_uint8_t grub_color_menu_normal; +static grub_uint8_t grub_color_menu_highlight; + +extern char g_ventoy_hotkey_tip[256]; + +struct menu_viewer_data +{ + int first, offset; + struct grub_term_screen_geometry geo; + enum { + TIMEOUT_UNKNOWN, + TIMEOUT_NORMAL, + TIMEOUT_TERSE, + TIMEOUT_TERSE_NO_MARGIN + } timeout_msg; + grub_menu_t menu; + int *menu_title_offset; + struct grub_term_output *term; +}; + +static inline int +grub_term_cursor_x (const struct grub_term_screen_geometry *geo) +{ + return (geo->first_entry_x + geo->entry_width); +} + +grub_size_t +grub_getstringwidth (grub_uint32_t * str, const grub_uint32_t * last_position, + struct grub_term_output *term) +{ + grub_ssize_t width = 0; + + while (str < last_position) + { + struct grub_unicode_glyph glyph; + glyph.ncomb = 0; + str += grub_unicode_aglomerate_comb (str, last_position - str, &glyph); + width += grub_term_getcharwidth (term, &glyph); + grub_unicode_destroy_glyph (&glyph); + } + return width; +} + +static int +grub_print_message_indented_real (const char *msg, int margin_left, + int margin_right, + struct grub_term_output *term, int dry_run) +{ + grub_uint32_t *unicode_msg; + grub_uint32_t *last_position; + grub_size_t msg_len = grub_strlen (msg) + 2; + int ret = 0; + + unicode_msg = grub_malloc (msg_len * sizeof (grub_uint32_t)); + + if (!unicode_msg) + return 0; + + msg_len = grub_utf8_to_ucs4 (unicode_msg, msg_len, + (grub_uint8_t *) msg, -1, 0); + + last_position = unicode_msg + msg_len; + *last_position = 0; + + if (dry_run) + ret = grub_ucs4_count_lines (unicode_msg, last_position, margin_left, + margin_right, term); + else + grub_print_ucs4_menu (unicode_msg, last_position, margin_left, + margin_right, term, 0, -1, 0, 0); + + grub_free (unicode_msg); + + return ret; +} + +void +grub_print_message_indented (const char *msg, int margin_left, int margin_right, + struct grub_term_output *term) +{ + grub_print_message_indented_real (msg, margin_left, margin_right, term, 0); +} + +static void +draw_border (struct grub_term_output *term, const struct grub_term_screen_geometry *geo) +{ + int i; + + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); + + grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1, + geo->first_entry_y - 1 }); + grub_putcode (GRUB_UNICODE_CORNER_UL, term); + for (i = 0; i < geo->entry_width + 1; i++) + grub_putcode (GRUB_UNICODE_HLINE, term); + grub_putcode (GRUB_UNICODE_CORNER_UR, term); + + for (i = 0; i < geo->num_entries; i++) + { + grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1, + geo->first_entry_y + i }); + grub_putcode (GRUB_UNICODE_VLINE, term); + grub_term_gotoxy (term, + (struct grub_term_coordinate) { geo->first_entry_x + geo->entry_width + 1, + geo->first_entry_y + i }); + grub_putcode (GRUB_UNICODE_VLINE, term); + } + + grub_term_gotoxy (term, + (struct grub_term_coordinate) { geo->first_entry_x - 1, + geo->first_entry_y - 1 + geo->num_entries + 1 }); + grub_putcode (GRUB_UNICODE_CORNER_LL, term); + for (i = 0; i < geo->entry_width + 1; i++) + grub_putcode (GRUB_UNICODE_HLINE, term); + grub_putcode (GRUB_UNICODE_CORNER_LR, term); + + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); + + grub_term_gotoxy (term, + (struct grub_term_coordinate) { geo->first_entry_x - 1, + (geo->first_entry_y - 1 + geo->num_entries + + GRUB_TERM_MARGIN + 1) }); +} + +static int +print_message (int nested, int edit, struct grub_term_output *term, int dry_run) +{ + int ret = 0; + grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL); + + if (edit) + { + ret += grub_print_message_indented_real (_("Minimum Emacs-like screen editing is \ +supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a \ +command-line or ESC to discard edits and return to the GRUB menu."), + STANDARD_MARGIN, STANDARD_MARGIN, + term, dry_run); + } + else + { + char *msg_translated; + + msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which " + "entry is highlighted."), + GRUB_UNICODE_UPARROW, + GRUB_UNICODE_DOWNARROW); + if (!msg_translated) + return 0; + ret += grub_print_message_indented_real (msg_translated, STANDARD_MARGIN, + STANDARD_MARGIN, term, dry_run); + + grub_free (msg_translated); + + if (nested) + { + #if 0 + ret += grub_print_message_indented_real + (_("Press enter to boot the selected OS, " + "`e' to edit the commands before booting " + "or `c' for a command-line. ESC to return previous menu."), + STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); + #endif + } + else + { + char szLine[128]; + const char *checkret = grub_env_get("VTOY_CHKDEV_RESULT_STRING"); + if (checkret == NULL || checkret[0] != '0') { + grub_snprintf(szLine, sizeof(szLine), "%s [Unofficial Ventoy]", grub_env_get("VTOY_TEXT_MENU_VER")); + } else { + grub_snprintf(szLine, sizeof(szLine), "%s", grub_env_get("VTOY_TEXT_MENU_VER")); + } + + ret += grub_print_message_indented_real("\n", STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); + + ret += grub_print_message_indented_real(szLine, STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); + + ret += grub_print_message_indented_real("\n", STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run); + ret += grub_print_message_indented_real(g_ventoy_hotkey_tip, + 3, 6, term, dry_run); + } + } + return ret; +} + +static void +print_entry (int y, int highlight, grub_menu_entry_t entry, + const struct menu_viewer_data *data) +{ + const char *title; + grub_size_t title_len; + grub_ssize_t len; + grub_uint32_t *unicode_title; + grub_ssize_t i; + grub_uint8_t old_color_normal, old_color_highlight; + + title = entry ? entry->title : ""; + title_len = grub_strlen (title); + unicode_title = grub_malloc (title_len * sizeof (*unicode_title)); + if (! unicode_title) + /* XXX How to show this error? */ + return; + + len = grub_utf8_to_ucs4 (unicode_title, title_len, + (grub_uint8_t *) title, -1, 0); + if (len < 0) + { + /* It is an invalid sequence. */ + grub_free (unicode_title); + return; + } + + old_color_normal = grub_term_normal_color; + old_color_highlight = grub_term_highlight_color; + grub_term_normal_color = grub_color_menu_normal; + grub_term_highlight_color = grub_color_menu_highlight; + grub_term_setcolorstate (data->term, highlight + ? GRUB_TERM_COLOR_HIGHLIGHT + : GRUB_TERM_COLOR_NORMAL); + + grub_term_gotoxy (data->term, (struct grub_term_coordinate) { + data->geo.first_entry_x, y }); + + for (i = 0; i < len; i++) + if (unicode_title[i] == '\n' || unicode_title[i] == '\b' + || unicode_title[i] == '\r' || unicode_title[i] == '\e') + unicode_title[i] = ' '; + + if (data->geo.num_entries > 1) + grub_putcode (highlight ? '*' : ' ', data->term); + + grub_print_ucs4_menu (unicode_title, + unicode_title + len, + 0, + data->geo.right_margin, + data->term, 0, 1, + GRUB_UNICODE_RIGHTARROW, 0); + + grub_term_setcolorstate (data->term, GRUB_TERM_COLOR_NORMAL); + grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { + grub_term_cursor_x (&data->geo), y }); + + grub_term_normal_color = old_color_normal; + grub_term_highlight_color = old_color_highlight; + + grub_term_setcolorstate (data->term, GRUB_TERM_COLOR_NORMAL); + grub_free (unicode_title); +} + +static void +print_entries (grub_menu_t menu, const struct menu_viewer_data *data) +{ + grub_menu_entry_t e; + int i; + + grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { + data->geo.first_entry_x + data->geo.entry_width + + data->geo.border + 1, + data->geo.first_entry_y }); + + if (data->geo.num_entries != 1) + { + if (data->first) + grub_putcode (GRUB_UNICODE_UPARROW, data->term); + else + grub_putcode (' ', data->term); + } + e = grub_menu_get_entry (menu, data->first); + + for (i = 0; i < data->geo.num_entries; i++) + { + print_entry (data->geo.first_entry_y + i, data->offset == i, + e, data); + if (e) + e = e->next; + } + + grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { data->geo.first_entry_x + data->geo.entry_width + + data->geo.border + 1, + data->geo.first_entry_y + data->geo.num_entries - 1 }); + if (data->geo.num_entries == 1) + { + if (data->first && e) + grub_putcode (GRUB_UNICODE_UPDOWNARROW, data->term); + else if (data->first) + grub_putcode (GRUB_UNICODE_UPARROW, data->term); + else if (e) + grub_putcode (GRUB_UNICODE_DOWNARROW, data->term); + else + grub_putcode (' ', data->term); + } + else + { + if (e) + grub_putcode (GRUB_UNICODE_DOWNARROW, data->term); + else + grub_putcode (' ', data->term); + } + + grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { grub_term_cursor_x (&data->geo), + data->geo.first_entry_y + data->offset }); +} + +/* Initialize the screen. If NESTED is non-zero, assume that this menu + is run from another menu or a command-line. If EDIT is non-zero, show + a message for the menu entry editor. */ +void +grub_menu_init_page (int nested, int edit, + struct grub_term_screen_geometry *geo, + struct grub_term_output *term) +{ + grub_uint8_t old_color_normal, old_color_highlight; + int msg_num_lines; + int bottom_message = 1; + int empty_lines = 1; + int version_msg = 1; + + geo->border = 1; + geo->first_entry_x = 1 /* margin */ + 1 /* border */; + geo->entry_width = grub_term_width (term) - 5; + + geo->first_entry_y = 2 /* two empty lines*/ + + 1 /* GNU GRUB version text */ + 1 /* top border */; + + geo->timeout_lines = 2; + + /* 3 lines for timeout message and bottom margin. 2 lines for the border. */ + geo->num_entries = grub_term_height (term) - geo->first_entry_y + - 1 /* bottom border */ + - 1 /* empty line before info message*/ + - geo->timeout_lines /* timeout */ + - 1 /* empty final line */; + msg_num_lines = print_message (nested, edit, term, 1); + if (geo->num_entries - msg_num_lines < 3 + || geo->entry_width < 10) + { + geo->num_entries += 4; + geo->first_entry_y -= 2; + empty_lines = 0; + geo->first_entry_x -= 1; + geo->entry_width += 1; + } + if (geo->num_entries - msg_num_lines < 3 + || geo->entry_width < 10) + { + geo->num_entries += 2; + geo->first_entry_y -= 1; + geo->first_entry_x -= 1; + geo->entry_width += 2; + geo->border = 0; + } + + if (geo->entry_width <= 0) + geo->entry_width = 1; + + if (geo->num_entries - msg_num_lines < 3 + && geo->timeout_lines == 2) + { + geo->timeout_lines = 1; + geo->num_entries++; + } + + if (geo->num_entries - msg_num_lines < 3) + { + geo->num_entries += 1; + geo->first_entry_y -= 1; + version_msg = 0; + } + + if (geo->num_entries - msg_num_lines >= 2) + geo->num_entries -= msg_num_lines; + else + bottom_message = 0; + + /* By default, use the same colors for the menu. */ + old_color_normal = grub_term_normal_color; + old_color_highlight = grub_term_highlight_color; + grub_color_menu_normal = grub_term_normal_color; + grub_color_menu_highlight = grub_term_highlight_color; + + /* Then give user a chance to replace them. */ + grub_parse_color_name_pair (&grub_color_menu_normal, + grub_env_get ("menu_color_normal")); + grub_parse_color_name_pair (&grub_color_menu_highlight, + grub_env_get ("menu_color_highlight")); + + if (version_msg) + grub_normal_init_page (term, empty_lines); + else + grub_term_cls (term); + + grub_term_normal_color = grub_color_menu_normal; + grub_term_highlight_color = grub_color_menu_highlight; + if (geo->border) + draw_border (term, geo); + grub_term_normal_color = old_color_normal; + grub_term_highlight_color = old_color_highlight; + geo->timeout_y = geo->first_entry_y + geo->num_entries + + geo->border + empty_lines; + if (bottom_message) + { + grub_term_gotoxy (term, + (struct grub_term_coordinate) { GRUB_TERM_MARGIN, + geo->timeout_y }); + + print_message (nested, edit, term, 0); + geo->timeout_y += msg_num_lines; + } + geo->right_margin = grub_term_width (term) + - geo->first_entry_x + - geo->entry_width - 1; +} + +static void +menu_text_print_timeout (int timeout, void *dataptr) +{ + struct menu_viewer_data *data = dataptr; + char *msg_translated = 0; + + grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { 0, data->geo.timeout_y }); + + if (data->timeout_msg == TIMEOUT_TERSE + || data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN) + msg_translated = grub_xasprintf (_("%ds"), timeout); + else + msg_translated = grub_xasprintf (_("The highlighted entry will be executed automatically in %ds."), timeout); + if (!msg_translated) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + return; + } + + if (data->timeout_msg == TIMEOUT_UNKNOWN) + { + data->timeout_msg = grub_print_message_indented_real (msg_translated, + 3, 1, data->term, 1) + <= data->geo.timeout_lines ? TIMEOUT_NORMAL : TIMEOUT_TERSE; + if (data->timeout_msg == TIMEOUT_TERSE) + { + grub_free (msg_translated); + msg_translated = grub_xasprintf (_("%ds"), timeout); + if (grub_term_width (data->term) < 10) + data->timeout_msg = TIMEOUT_TERSE_NO_MARGIN; + } + } + + grub_print_message_indented (msg_translated, + data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN ? 0 : 3, + data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN ? 0 : 1, + data->term); + grub_free (msg_translated); + + grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { + grub_term_cursor_x (&data->geo), + data->geo.first_entry_y + data->offset }); + grub_term_refresh (data->term); +} + +static void +menu_text_set_chosen_entry (int entry, void *dataptr) +{ + struct menu_viewer_data *data = dataptr; + int oldoffset = data->offset; + int complete_redraw = 0; + + data->offset = entry - data->first; + if (data->offset > data->geo.num_entries - 1) + { + data->first = entry - (data->geo.num_entries - 1); + data->offset = data->geo.num_entries - 1; + complete_redraw = 1; + } + if (data->offset < 0) + { + data->offset = 0; + data->first = entry; + complete_redraw = 1; + } + if (complete_redraw) + print_entries (data->menu, data); + else + { + print_entry (data->geo.first_entry_y + oldoffset, 0, + grub_menu_get_entry (data->menu, data->first + oldoffset), + data); + print_entry (data->geo.first_entry_y + data->offset, 1, + grub_menu_get_entry (data->menu, data->first + data->offset), + data); + } + grub_term_refresh (data->term); +} + +static void +menu_text_scroll_chosen_entry (void *dataptr, int diren) +{ + struct menu_viewer_data *data = dataptr; + const char *orig_title, *scrolled_title; + int off; + int selected; + grub_menu_entry_t entry; + + if (!data->menu->size) + return; + + selected = data->first + data->offset; + entry = grub_menu_get_entry (data->menu, selected); + orig_title = entry->title; + off = data->menu_title_offset[selected] + diren; + if (off < 0 + || off > grub_utf8_get_num_code (orig_title, grub_strlen(orig_title))) + return; + + scrolled_title = + grub_utf8_offset_code (orig_title, grub_strlen (orig_title), off); + if (scrolled_title) + entry->title = scrolled_title; + print_entry (data->geo.first_entry_y + data->offset, 1, entry, data); + + entry->title = orig_title; + data->menu_title_offset[selected] = off; + grub_term_refresh (data->term); +} + +static void +menu_text_fini (void *dataptr) +{ + struct menu_viewer_data *data = dataptr; + + grub_term_setcursor (data->term, 1); + grub_term_cls (data->term); + if (data->menu_title_offset) + grub_free (data->menu_title_offset); + grub_free (data); +} + +static void +menu_text_clear_timeout (void *dataptr) +{ + struct menu_viewer_data *data = dataptr; + int i; + + for (i = 0; i < data->geo.timeout_lines;i++) + { + grub_term_gotoxy (data->term, (struct grub_term_coordinate) { + 0, data->geo.timeout_y + i }); + grub_print_spaces (data->term, grub_term_width (data->term) - 1); + } + if (data->geo.num_entries <= 5 && !data->geo.border) + { + grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { + data->geo.first_entry_x + data->geo.entry_width + + data->geo.border + 1, + data->geo.first_entry_y + data->geo.num_entries - 1 + }); + grub_putcode (' ', data->term); + + data->geo.timeout_lines = 0; + data->geo.num_entries++; + print_entries (data->menu, data); + } + grub_term_gotoxy (data->term, + (struct grub_term_coordinate) { + grub_term_cursor_x (&data->geo), + data->geo.first_entry_y + data->offset }); + grub_term_refresh (data->term); +} + +grub_err_t +grub_menu_try_text (struct grub_term_output *term, + int entry, grub_menu_t menu, int nested) +{ + struct menu_viewer_data *data; + struct grub_menu_viewer *instance; + + instance = grub_zalloc (sizeof (*instance)); + if (!instance) + return grub_errno; + + data = grub_zalloc (sizeof (*data)); + if (!data) + { + grub_free (instance); + return grub_errno; + } + + if (menu->size) + data->menu_title_offset = grub_zalloc (sizeof (*data->menu_title_offset) * menu->size); + + data->term = term; + instance->data = data; + instance->set_chosen_entry = menu_text_set_chosen_entry; + if (data->menu_title_offset) + instance->scroll_chosen_entry = menu_text_scroll_chosen_entry; + instance->print_timeout = menu_text_print_timeout; + instance->clear_timeout = menu_text_clear_timeout; + instance->fini = menu_text_fini; + + data->menu = menu; + + data->offset = entry; + data->first = 0; + + grub_term_setcursor (data->term, 0); + grub_menu_init_page (nested, 0, &data->geo, data->term); + + if (data->offset > data->geo.num_entries - 1) + { + data->first = data->offset - (data->geo.num_entries - 1); + data->offset = data->geo.num_entries - 1; + } + + print_entries (menu, data); + grub_term_refresh (data->term); + grub_menu_register_viewer (instance); + + return GRUB_ERR_NONE; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/misc.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/misc.c new file mode 100644 index 0000000..a99f94d --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/normal/misc.c @@ -0,0 +1,194 @@ +/* misc.c - miscellaneous functions */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char *grub_human_sizes[3][6] = + { + /* This algorithm in reality would work only up to (2^64) / 100 B = 81 PiB. + Put here all possible suffixes it can produce so no array bounds check + is needed. + */ + /* TRANSLATORS: that's the list of binary unit prefixes. */ + { N_("B"), N_("KiB"), N_("MiB"), N_("GiB"), N_("TiB"), N_("PiB")}, + /* TRANSLATORS: that's the list of binary unit prefixes. */ + { "", N_("KB"), N_("MB"), N_("GB"), N_("TB"), N_("PB") }, + /* TRANSLATORS: that's the list of binary unit prefixes. */ + { N_("B/s"), N_("KiB/s"), N_("MiB/s"), N_("GiB/s"), N_("TiB/s"), N_("PiB/s"), }, + }; + +const char * +grub_get_human_size (grub_uint64_t size, enum grub_human_size_type type) +{ + grub_uint64_t fsize; + unsigned units = 0; + static char buf[30]; + const char *umsg; + + if (type != GRUB_HUMAN_SIZE_SPEED) + fsize = size * 100ULL; + else + fsize = size; + + /* Since 2^64 / 1024^5 < 102400, this can give at most 5 iterations. + So units <=5, so impossible to go past the end of array. + */ + while (fsize >= 102400) + { + fsize = (fsize + 512) / 1024; + units++; + } + + umsg = _(grub_human_sizes[type][units]); + + if (units || type == GRUB_HUMAN_SIZE_SPEED) + { + grub_uint64_t whole, fraction; + + whole = grub_divmod64 (fsize, 100, &fraction); + grub_snprintf (buf, sizeof (buf), + "%" PRIuGRUB_UINT64_T + ".%02" PRIuGRUB_UINT64_T "%s", whole, fraction, + umsg); + } + else + grub_snprintf (buf, sizeof (buf), "%llu%s", (unsigned long long) size, + umsg); + return buf; +} + +/* Print the information on the device NAME. */ +grub_err_t +grub_normal_print_device_info (const char *name) +{ + grub_device_t dev; + char *p; + + p = grub_strchr (name, ','); + if (p) + { + grub_xputs ("\t"); + grub_printf_ (N_("Partition %s:"), name); + grub_xputs (" "); + } + else + { + grub_printf_ (N_("Device %s:"), name); + grub_xputs (" "); + } + + dev = grub_device_open (name); + if (! dev) + grub_printf ("%s", _("Filesystem cannot be accessed")); + else if (dev->disk) + { + grub_fs_t fs; + + fs = grub_fs_probe (dev); + /* Ignore all errors. */ + grub_errno = 0; + + if (fs) + { + const char *fsname = fs->name; + if (grub_strcmp (fsname, "ext2") == 0) + fsname = "ext*"; + grub_printf_ (N_("Filesystem type %s"), fsname); + if (fs->fs_label) + { + char *label; + (fs->fs_label) (dev, &label); + if (grub_errno == GRUB_ERR_NONE) + { + if (label && grub_strlen (label)) + { + grub_xputs (" "); + grub_printf_ (N_("- Label `%s'"), label); + } + grub_free (label); + } + grub_errno = GRUB_ERR_NONE; + } + if (fs->fs_mtime) + { + grub_int32_t tm; + struct grub_datetime datetime; + (fs->fs_mtime) (dev, &tm); + if (grub_errno == GRUB_ERR_NONE) + { + grub_unixtime2datetime (tm, &datetime); + grub_xputs (" "); + /* TRANSLATORS: Arguments are year, month, day, hour, minute, + second, day of the week (translated). */ + grub_printf_ (N_("- Last modification time %d-%02d-%02d " + "%02d:%02d:%02d %s"), + datetime.year, datetime.month, datetime.day, + datetime.hour, datetime.minute, datetime.second, + grub_get_weekday_name (&datetime)); + + } + grub_errno = GRUB_ERR_NONE; + } + if (fs->fs_uuid) + { + char *uuid; + (fs->fs_uuid) (dev, &uuid); + if (grub_errno == GRUB_ERR_NONE) + { + if (uuid && grub_strlen (uuid)) + grub_printf (", UUID %s", uuid); + grub_free (uuid); + } + grub_errno = GRUB_ERR_NONE; + } + } + else + grub_printf ("%s", _("No known filesystem detected")); + + if (dev->disk->partition) + grub_printf (_(" - Partition start at %llu%sKiB"), + (unsigned long long) (grub_partition_get_start (dev->disk->partition) >> 1), + (grub_partition_get_start (dev->disk->partition) & 1) ? ".5" : "" ); + else + grub_printf_ (N_(" - Sector size %uB"), 1 << dev->disk->log_sector_size); + if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN) + grub_puts_ (N_(" - Total size unknown")); + else + grub_printf (_(" - Total size %llu%sKiB"), + (unsigned long long) (grub_disk_get_size (dev->disk) >> 1), + /* TRANSLATORS: Replace dot with appropriate decimal separator for + your language. */ + (grub_disk_get_size (dev->disk) & 1) ? _(".5") : ""); + } + + if (dev) + grub_device_close (dev); + + grub_xputs ("\n"); + return grub_errno; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/partmap/gpt.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/partmap/gpt.c new file mode 100644 index 0000000..418c554 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/partmap/gpt.c @@ -0,0 +1,232 @@ +/* gpt.c - Read GUID Partition Tables (GPT). */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_uint8_t grub_gpt_magic[8] = + { + 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54 + }; + +static const grub_gpt_part_guid_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY; + +#ifdef GRUB_UTIL +static const grub_gpt_part_guid_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT; +#endif + +/* 512 << 7 = 65536 byte sectors. */ +#define MAX_SECTOR_LOG 7 + +static struct grub_partition_map grub_gpt_partition_map; + + + +grub_err_t +grub_gpt_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data) +{ + struct grub_partition part; + struct grub_gpt_header gpt; + struct grub_gpt_partentry entry; + struct grub_msdos_partition_mbr mbr; + grub_uint64_t entries; + unsigned int i; + int last_offset = 0; + int sector_log = 0; + + /* Read the protective MBR. */ + if (grub_disk_read (disk, 0, 0, sizeof (mbr), &mbr)) + return grub_errno; + + /* Check if it is valid. */ + if (mbr.signature != grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); + + /* Make sure the MBR is a protective MBR and not a normal MBR. */ + for (i = 0; i < 4; i++) + if (mbr.entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK) + break; + if (i == 4) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no GPT partition map found"); + + /* Read the GPT header. */ + for (sector_log = 0; sector_log < MAX_SECTOR_LOG; sector_log++) + { + if (grub_disk_read (disk, 1 << sector_log, 0, sizeof (gpt), &gpt)) + return grub_errno; + + if (grub_memcmp (gpt.magic, grub_gpt_magic, sizeof (grub_gpt_magic)) == 0) + break; + } + if (sector_log == MAX_SECTOR_LOG) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no valid GPT header"); + + grub_dprintf ("gpt", "Read a valid GPT header\n"); + + entries = grub_le_to_cpu64 (gpt.partitions) << sector_log; + for (i = 0; i < grub_le_to_cpu32 (gpt.maxpart); i++) + { + if (grub_disk_read (disk, entries, last_offset, + sizeof (entry), &entry)) + return grub_errno; + + if (grub_memcmp (&grub_gpt_partition_type_empty, &entry.type, + sizeof (grub_gpt_partition_type_empty))) + { + /* Calculate the first block and the size of the partition. */ + part.start = grub_le_to_cpu64 (entry.start) << sector_log; + part.len = (grub_le_to_cpu64 (entry.end) + - grub_le_to_cpu64 (entry.start) + 1) << sector_log; + part.offset = entries; + part.number = i; + part.index = last_offset; + part.partmap = &grub_gpt_partition_map; + part.parent = disk->partition; + part.gpt_attrib = entry.attrib; + + grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i, + (unsigned long long) part.start, + (unsigned long long) part.len); + + if (hook (disk, &part, hook_data)) + return grub_errno; + } + + last_offset += grub_le_to_cpu32 (gpt.partentry_size); + if (last_offset == GRUB_DISK_SECTOR_SIZE) + { + last_offset = 0; + entries++; + } + } + + return GRUB_ERR_NONE; +} + +#ifdef GRUB_UTIL +/* Context for gpt_partition_map_embed. */ +struct gpt_partition_map_embed_ctx +{ + grub_disk_addr_t start, len; +}; + +/* Helper for gpt_partition_map_embed. */ +static int +find_usable_region (grub_disk_t disk __attribute__ ((unused)), + const grub_partition_t p, void *data) +{ + struct gpt_partition_map_embed_ctx *ctx = data; + struct grub_gpt_partentry gptdata; + grub_partition_t p2; + + p2 = disk->partition; + disk->partition = p->parent; + if (grub_disk_read (disk, p->offset, p->index, + sizeof (gptdata), &gptdata)) + { + disk->partition = p2; + return 0; + } + disk->partition = p2; + + /* If there's an embed region, it is in a dedicated partition. */ + if (! grub_memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16)) + { + ctx->start = p->start; + ctx->len = p->len; + return 1; + } + + return 0; +} + +static grub_err_t +gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, + unsigned int max_nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors) +{ + struct gpt_partition_map_embed_ctx ctx = { + .start = 0, + .len = 0 + }; + unsigned i; + grub_err_t err; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "GPT currently supports only PC-BIOS embedding"); + + err = grub_gpt_partition_map_iterate (disk, find_usable_region, &ctx); + if (err) + return err; + + if (ctx.len == 0) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + N_("this GPT partition label contains no BIOS Boot Partition;" + " embedding won't be possible")); + + if (ctx.len < *nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("your BIOS Boot Partition is too small;" + " embedding won't be possible")); + + *nsectors = ctx.len; + if (*nsectors > max_nsectors) + *nsectors = max_nsectors; + *sectors = grub_malloc (*nsectors * sizeof (**sectors)); + if (!*sectors) + return grub_errno; + for (i = 0; i < *nsectors; i++) + (*sectors)[i] = ctx.start + i; + + return GRUB_ERR_NONE; +} +#endif + + +/* Partition map type. */ +static struct grub_partition_map grub_gpt_partition_map = + { + .name = "gpt", + .iterate = grub_gpt_partition_map_iterate, +#ifdef GRUB_UTIL + .embed = gpt_partition_map_embed +#endif + }; + +GRUB_MOD_INIT(part_gpt) +{ + grub_partition_map_register (&grub_gpt_partition_map); +} + +GRUB_MOD_FINI(part_gpt) +{ + grub_partition_map_unregister (&grub_gpt_partition_map); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/script/function.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/script/function.c new file mode 100644 index 0000000..7bc94c0 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/script/function.c @@ -0,0 +1,113 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2007,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +grub_script_function_t grub_script_function_list; + +grub_script_function_t +grub_script_function_create (struct grub_script_arg *functionname_arg, + struct grub_script *cmd) +{ + grub_script_function_t func; + grub_script_function_t *p; + + func = (grub_script_function_t) grub_malloc (sizeof (*func)); + if (! func) + return 0; + + func->name = grub_strdup (functionname_arg->str); + if (! func->name) + { + grub_free (func); + return 0; + } + + func->func = cmd; + + /* Keep the list sorted for simplicity. */ + p = &grub_script_function_list; + while (*p) + { + if (grub_strcmp ((*p)->name, func->name) >= 0) + break; + + p = &((*p)->next); + } + + /* If the function already exists, overwrite the old function. */ + if (*p && grub_strcmp ((*p)->name, func->name) == 0) + { + grub_script_function_t q; + + q = *p; + grub_script_free (q->func); + q->func = cmd; + grub_free (func); + func = q; + } + else + { + func->next = *p; + *p = func; + } + + return func; +} + +void +grub_script_function_remove (const char *name) +{ + grub_script_function_t *p, q; + + for (p = &grub_script_function_list, q = *p; q; p = &(q->next), q = q->next) + if (grub_strcmp (name, q->name) == 0) + { + *p = q->next; + grub_free (q->name); + grub_script_free (q->func); + grub_free (q); + break; + } +} + +grub_script_function_t +grub_script_function_find (char *functionname) +{ + grub_script_function_t func; + + for (func = grub_script_function_list; func; func = func->next) + if (grub_strcmp (functionname, func->name) == 0) + break; + + if (! func) + { + char tmp[64]; + grub_strncpy (tmp, functionname, 63); + tmp[63] = 0; + /* Avoid truncating inside UTF-8 character. */ + tmp[grub_getend (tmp, tmp + grub_strlen (tmp))] = 0; + grub_error (GRUB_ERR_UNKNOWN_COMMAND, N_("can't find command `%s'"), tmp); + } + + return func; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/efi/mouse.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/efi/mouse.c new file mode 100644 index 0000000..e4b15f5 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/efi/mouse.c @@ -0,0 +1,260 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2022 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define GRUB_EFI_SIMPLE_POINTER_GUID \ + { 0x31878c87, 0x0b75, 0x11d5, \ + { 0x9a, 0x4f, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +typedef struct +{ + grub_efi_int32_t x; + grub_efi_int32_t y; + grub_efi_int32_t z; + grub_efi_boolean_t left; + grub_efi_boolean_t right; +} grub_efi_mouse_state; + +grub_efi_mouse_state no_move = {0, 0, 0, 0, 0}; + +typedef struct +{ + grub_efi_uint64_t x; + grub_efi_uint64_t y; + grub_efi_uint64_t z; + grub_efi_boolean_t left; + grub_efi_boolean_t right; +} grub_efi_mouse_mode; + +struct grub_efi_simple_pointer_protocol +{ + grub_efi_status_t (*reset) (struct grub_efi_simple_pointer_protocol *this, + grub_efi_boolean_t extended_verification); + grub_efi_status_t (*get_state) (struct grub_efi_simple_pointer_protocol *this, + grub_efi_mouse_state *state); + grub_efi_event_t *wait_for_input; + grub_efi_mouse_mode *mode; +}; +typedef struct grub_efi_simple_pointer_protocol grub_efi_simple_pointer_protocol_t; + +typedef struct +{ + grub_efi_uintn_t count; + grub_efi_simple_pointer_protocol_t **mouse; +} grub_efi_mouse_prot_t; + +static grub_int32_t +mouse_div (grub_int32_t a, grub_uint64_t b) +{ + grub_int32_t s = 1, q, ret; + grub_uint64_t n = a; + if (!b) + return 0; + if (a < 0) + { + s = -1; + n = -a; + } + q = grub_divmod64 (n, b, NULL); + ret = s * (q > 0 ? q : -q); + return ret; +} + +static grub_efi_mouse_prot_t * +grub_efi_mouse_prot_init (void) +{ + grub_efi_status_t status; + grub_efi_guid_t mouse_guid = GRUB_EFI_SIMPLE_POINTER_GUID; + grub_efi_mouse_prot_t *mouse_input = NULL; + grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; + grub_efi_handle_t *buf; + grub_efi_uintn_t count; + grub_efi_uintn_t i; + + status = efi_call_5 (b->locate_handle_buffer, GRUB_EFI_BY_PROTOCOL, + &mouse_guid, NULL, &count, &buf); + if (status != GRUB_EFI_SUCCESS) + { +#ifdef MOUSE_DEBUG + grub_printf ("ERROR: SimplePointerProtocol not found.\n"); +#endif + return NULL; + } + + mouse_input = grub_malloc (sizeof (grub_efi_mouse_prot_t)); + if (!mouse_input) + goto end; + mouse_input->mouse = grub_malloc (count + * sizeof (grub_efi_simple_pointer_protocol_t *)); + if (!mouse_input->mouse) + { + grub_free (mouse_input); + mouse_input = NULL; + goto end; + } + mouse_input->count = count; + for (i = 0; i < count; i++) + { + efi_call_3 (b->handle_protocol, + buf[i], &mouse_guid, (void **)&mouse_input->mouse[i]); +#ifdef MOUSE_DEBUG + grub_printf ("%d %p ", (int)i, mouse_input->mouse[i]); +#endif + efi_call_2 (mouse_input->mouse[i]->reset, mouse_input->mouse[i], 1); +#ifdef MOUSE_DEBUG + grub_printf + ("[%"PRIuGRUB_UINT64_T"] [%"PRIuGRUB_UINT64_T"] [%"PRIuGRUB_UINT64_T"]\n", + mouse_input->mouse[i]->mode->x, + mouse_input->mouse[i]->mode->y, mouse_input->mouse[i]->mode->z); +#endif + } + +end: + efi_call_1(b->free_pool, buf); + + return mouse_input; +} + +static grub_err_t +grub_efi_mouse_input_init (struct grub_term_input *term) +{ + grub_efi_mouse_prot_t *mouse_input = NULL; + if (term->data) + return 0; + mouse_input = grub_efi_mouse_prot_init (); + if (!mouse_input) + return GRUB_ERR_BAD_OS; + + term->data = (void *)mouse_input; + + return 0; +} + +static int +grub_mouse_getkey (struct grub_term_input *term) +{ + grub_efi_mouse_state cur; + grub_efi_mouse_prot_t *mouse = term->data; + //int x; + int y; + int delta = 0; + const char *env; + grub_efi_uintn_t i; + if (!mouse) + return GRUB_TERM_NO_KEY; + + env = grub_env_get("mouse_delta"); + if (env) + delta = (int)grub_strtol(env, NULL, 10); + + for (i = 0; i < mouse->count; i++) + { + efi_call_2 (mouse->mouse[i]->get_state, mouse->mouse[i], &cur); + if (grub_memcmp (&cur, &no_move, sizeof (grub_efi_mouse_state)) != 0) + { + y = mouse_div (cur.y, mouse->mouse[i]->mode->y); + if (cur.left) + return 0x0d; + if (cur.right) + return GRUB_TERM_ESC; + if (y > delta) + return GRUB_TERM_KEY_DOWN; + if (y < -delta) + return GRUB_TERM_KEY_UP; + } + } + return GRUB_TERM_NO_KEY; +} + +#ifdef MOUSE_DEBUG +static grub_err_t +grub_cmd_mouse_test (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) + +{ + grub_efi_mouse_state cur; + int x = 0, y = 0, z = 0; + grub_efi_uintn_t i; + grub_efi_mouse_prot_t *mouse = NULL; + + mouse = grub_efi_mouse_prot_init (); + if (!mouse) + return grub_error (GRUB_ERR_BAD_OS, "mouse not found.\n"); + grub_printf ("Press [1] to exit.\n"); + while (1) + { + if (grub_getkey_noblock () == '1') + break; + for (i = 0; i < mouse->count; i++) + { + efi_call_2 (mouse->mouse[i]->get_state, mouse->mouse[i], &cur); + if (grub_memcmp (&cur, &no_move, sizeof (grub_efi_mouse_state)) != 0) + { + x = mouse_div (cur.x, mouse->mouse[i]->mode->x); + y = mouse_div (cur.y, mouse->mouse[i]->mode->y); + z = mouse_div (cur.z, mouse->mouse[i]->mode->z); + grub_printf ("[ID=%d] X=%d Y=%d Z=%d L=%d R=%d\n", + (int)i, x, y, z, cur.left, cur.right); + } + } + grub_refresh (); + } + grub_free (mouse->mouse); + grub_free (mouse); + return GRUB_ERR_NONE; +} +static grub_command_t cmd; +#endif + +static struct grub_term_input grub_mouse_term_input = +{ + .name = "mouse", + .getkey = grub_mouse_getkey, + .init = grub_efi_mouse_input_init, +}; + +GRUB_MOD_INIT(mouse) +{ + grub_term_register_input ("mouse", &grub_mouse_term_input); +#ifdef MOUSE_DEBUG + cmd = grub_register_command ("mouse_test", grub_cmd_mouse_test, 0, + N_("UEFI mouse test.")); +#endif +} + +GRUB_MOD_FINI(mouse) +{ + grub_term_unregister_input (&grub_mouse_term_input); +#ifdef MOUSE_DEBUG + grub_unregister_command (cmd); +#endif +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/keyboard_layout.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/keyboard_layout.c new file mode 100644 index 0000000..900eaf7 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/keyboard_layout.c @@ -0,0 +1,795 @@ + +#define ventoy_keyboard_set_layout(name) if (grub_strcmp(layout, #name) == 0) return ventoy_keyboard_layout_##name() + +static void ventoy_keyboard_layout_QWERTY_USA(void) { + grub_keymap_reset(); + grub_keymap_disable(); +} +static void ventoy_keyboard_layout_AZERTY(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("a", "q"); +grub_keymap_add_by_string("A", "Q"); +grub_keymap_add_by_string("z", "w"); +grub_keymap_add_by_string("Z", "W"); +grub_keymap_add_by_string("q", "a"); +grub_keymap_add_by_string("Q", "A"); +grub_keymap_add_by_string("m", "semicolon"); +grub_keymap_add_by_string("M", "colon"); +grub_keymap_add_by_string("w", "z"); +grub_keymap_add_by_string("W", "Z"); +grub_keymap_add_by_string("comma", "m"); +grub_keymap_add_by_string("question", "M"); +grub_keymap_add_by_string("semicolon", "comma"); +grub_keymap_add_by_string("period", "less"); +grub_keymap_add_by_string("colon", "period"); +grub_keymap_add_by_string("slash", "greater"); +grub_keymap_add_by_string("exclam", "slash"); +grub_keymap_add_by_string("dollar", "bracketright"); +grub_keymap_add_by_string("asterisk", "backslash"); +grub_keymap_add_by_string("percent", "doublequote"); +grub_keymap_add_by_string("ampersand", "1"); +grub_keymap_add_by_string("1", "exclam"); +grub_keymap_add_by_string("tilde", "2"); +grub_keymap_add_by_string("2", "at"); +grub_keymap_add_by_string("doublequote", "3"); +grub_keymap_add_by_string("3", "numbersign"); +grub_keymap_add_by_string("quote", "4"); +grub_keymap_add_by_string("4", "dollar"); +grub_keymap_add_by_string("parenleft", "5"); +grub_keymap_add_by_string("5", "percent"); +grub_keymap_add_by_string("minus", "6"); +grub_keymap_add_by_string("6", "caret"); +grub_keymap_add_by_string("backquote", "7"); +grub_keymap_add_by_string("7", "ampersand"); +grub_keymap_add_by_string("underscore", "8"); +grub_keymap_add_by_string("8", "asterisk"); +grub_keymap_add_by_string("caret", "9"); +grub_keymap_add_by_string("9", "parenleft"); +grub_keymap_add_by_string("at", "0"); +grub_keymap_add_by_string("0", "parenright"); +grub_keymap_add_by_string("parenright", "minus"); +grub_keymap_add_by_string("less", "backquote"); +grub_keymap_add_by_string("greater", "tilde"); +grub_keymap_add_by_string("numbersign", "braceright"); +grub_keymap_add_by_string("backslash", "question"); +grub_keymap_add_by_string("bracketright", "braceleft"); +grub_keymap_add_by_string("braceleft", "quote"); +grub_keymap_add_by_string("braceright", "underscore"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_CZECH_QWERTY(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("semicolon", "backquote"); +grub_keymap_add_by_string("plus", "1"); +grub_keymap_add_by_string("equal", "minus"); +grub_keymap_add_by_string("quote", "equal"); +grub_keymap_add_by_string("parenright", "bracketright"); +grub_keymap_add_by_string("doublequote", "backslash"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("1", "exclam"); +grub_keymap_add_by_string("2", "at"); +grub_keymap_add_by_string("3", "numbersign"); +grub_keymap_add_by_string("4", "dollar"); +grub_keymap_add_by_string("5", "percent"); +grub_keymap_add_by_string("6", "caret"); +grub_keymap_add_by_string("7", "ampersand"); +grub_keymap_add_by_string("8", "asterisk"); +grub_keymap_add_by_string("9", "parenleft"); +grub_keymap_add_by_string("0", "parenright"); +grub_keymap_add_by_string("percent", "underscore"); +grub_keymap_add_by_string("slash", "braceleft"); +grub_keymap_add_by_string("parenleft", "braceright"); +grub_keymap_add_by_string("doublequote", "colon"); +grub_keymap_add_by_string("exclam", "doublequote"); +grub_keymap_add_by_string("quote", "bar"); +grub_keymap_add_by_string("question", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("backquote", "Abackquote"); +grub_keymap_add_by_string("exclam", "A1"); +grub_keymap_add_by_string("at", "A2"); +grub_keymap_add_by_string("numbersign", "A3"); +grub_keymap_add_by_string("dollar", "A4"); +grub_keymap_add_by_string("percent", "A5"); +grub_keymap_add_by_string("caret", "A6"); +grub_keymap_add_by_string("ampersand", "A7"); +grub_keymap_add_by_string("asterisk", "A8"); +grub_keymap_add_by_string("parenleft", "A9"); +grub_keymap_add_by_string("parenright", "A0"); +grub_keymap_add_by_string("minus", "Aminus"); +grub_keymap_add_by_string("equal", "Aequal"); +grub_keymap_add_by_string("bracketleft", "Abracketleft"); +grub_keymap_add_by_string("bracketright", "Abracketright"); +grub_keymap_add_by_string("semicolon", "Asemicolon"); +grub_keymap_add_by_string("backslash", "Abackslash"); +grub_keymap_add_by_string("less", "Acomma"); +grub_keymap_add_by_string("greater", "Aperiod"); +grub_keymap_add_by_string("slash", "Aslash"); +grub_keymap_add_by_string("tilde", "Atilde"); +grub_keymap_add_by_string("underscore", "Aunderscore"); +grub_keymap_add_by_string("plus", "Aplus"); +grub_keymap_add_by_string("braceleft", "Abraceleft"); +grub_keymap_add_by_string("braceright", "Abraceright"); +grub_keymap_add_by_string("caret", "Adoublequote"); +grub_keymap_add_by_string("colon", "Acolon"); +grub_keymap_add_by_string("question", "Aquestion"); +grub_keymap_add_by_string("bar", "Abar"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_CZECH_QWERTZ(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("y", "z"); +grub_keymap_add_by_string("z", "y"); +grub_keymap_add_by_string("Y", "Z"); +grub_keymap_add_by_string("Z", "Y"); +grub_keymap_add_by_string("semicolon", "backquote"); +grub_keymap_add_by_string("plus", "1"); +grub_keymap_add_by_string("equal", "minus"); +grub_keymap_add_by_string("quote", "equal"); +grub_keymap_add_by_string("parenright", "bracketright"); +grub_keymap_add_by_string("doublequote", "backslash"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("1", "exclam"); +grub_keymap_add_by_string("2", "at"); +grub_keymap_add_by_string("3", "numbersign"); +grub_keymap_add_by_string("4", "dollar"); +grub_keymap_add_by_string("5", "percent"); +grub_keymap_add_by_string("6", "caret"); +grub_keymap_add_by_string("7", "ampersand"); +grub_keymap_add_by_string("8", "asterisk"); +grub_keymap_add_by_string("9", "parenleft"); +grub_keymap_add_by_string("0", "parenright"); +grub_keymap_add_by_string("percent", "underscore"); +grub_keymap_add_by_string("slash", "braceleft"); +grub_keymap_add_by_string("parenleft", "braceright"); +grub_keymap_add_by_string("doublequote", "colon"); +grub_keymap_add_by_string("exclam", "doublequote"); +grub_keymap_add_by_string("quote", "bar"); +grub_keymap_add_by_string("question", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("tilde", "A1"); +grub_keymap_add_by_string("caret", "A3"); +grub_keymap_add_by_string("backslash", "Aq"); +grub_keymap_add_by_string("bar", "Aw"); +grub_keymap_add_by_string("bracketleft", "Af"); +grub_keymap_add_by_string("bracketright", "Ag"); +grub_keymap_add_by_string("dollar", "Asemicolon"); +grub_keymap_add_by_string("numbersign", "Ax"); +grub_keymap_add_by_string("ampersand", "Ac"); +grub_keymap_add_by_string("at", "Av"); +grub_keymap_add_by_string("braceleft", "Ab"); +grub_keymap_add_by_string("braceright", "An"); +grub_keymap_add_by_string("less", "Acomma"); +grub_keymap_add_by_string("greater", "Aperiod"); +grub_keymap_add_by_string("asterisk", "Aslash"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_DANISH(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("plus", "minus"); +grub_keymap_add_by_string("quote", "equal"); +grub_keymap_add_by_string("doublequote", "bracketright"); +grub_keymap_add_by_string("quote", "backslash"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("ampersand", "caret"); +grub_keymap_add_by_string("slash", "ampersand"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("equal", "parenright"); +grub_keymap_add_by_string("question", "underscore"); +grub_keymap_add_by_string("caret", "braceright"); +grub_keymap_add_by_string("asterisk", "bar"); +grub_keymap_add_by_string("backquote", "plus"); +grub_keymap_add_by_string("semicolon", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("bar", "Atilde"); +grub_keymap_add_by_string("backslash", "Abackquote"); +grub_keymap_add_by_string("greater", "tilde"); +grub_keymap_add_by_string("at", "A2"); +grub_keymap_add_by_string("dollar", "A4"); +grub_keymap_add_by_string("braceleft", "A7"); +grub_keymap_add_by_string("bracketleft", "A8"); +grub_keymap_add_by_string("bracketright", "A9"); +grub_keymap_add_by_string("braceright", "A0"); +grub_keymap_add_by_string("backslash", "Aminus"); +grub_keymap_add_by_string("less", "quote"); +grub_keymap_add_by_string("greater", "doublequote"); +grub_keymap_add_by_string("tilde", "Abracketright"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_DVORAK_USA(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("[", "minus"); +grub_keymap_add_by_string("braceleft", "underscore"); +grub_keymap_add_by_string("quote", "q"); +grub_keymap_add_by_string("doublequote", "Q"); +grub_keymap_add_by_string("comma", "w"); +grub_keymap_add_by_string("less", "W"); +grub_keymap_add_by_string("s", "semicolon"); +grub_keymap_add_by_string("S", "colon"); +grub_keymap_add_by_string("semicolon", "z"); +grub_keymap_add_by_string("colon", "Z"); +grub_keymap_add_by_string("w", "comma"); +grub_keymap_add_by_string("W", "less"); +grub_keymap_add_by_string("v", "period"); +grub_keymap_add_by_string("z", "greater"); +grub_keymap_add_by_string("z", "slash"); +grub_keymap_add_by_string("equal", "bracketright"); +grub_keymap_add_by_string("backslash", "backslash"); +grub_keymap_add_by_string("underscore", "doublequote"); +grub_keymap_add_by_string("quote", "q"); +grub_keymap_add_by_string("doublequote", "Q"); +grub_keymap_add_by_string("comma", "w"); +grub_keymap_add_by_string("less", "W"); +grub_keymap_add_by_string("period", "e"); +grub_keymap_add_by_string("greater", "E"); +grub_keymap_add_by_string("p", "r"); +grub_keymap_add_by_string("P", "R"); +grub_keymap_add_by_string("y", "t"); +grub_keymap_add_by_string("Y", "T"); +grub_keymap_add_by_string("f", "y"); +grub_keymap_add_by_string("F", "Y"); +grub_keymap_add_by_string("g", "u"); +grub_keymap_add_by_string("G", "U"); +grub_keymap_add_by_string("c", "c"); +grub_keymap_add_by_string("C", "I"); +grub_keymap_add_by_string("r", "o"); +grub_keymap_add_by_string("R", "O"); +grub_keymap_add_by_string("l", "p"); +grub_keymap_add_by_string("L", "P"); +grub_keymap_add_by_string("bracketright", "equal"); +grub_keymap_add_by_string("braceright", "plus"); +grub_keymap_add_by_string("a", "a"); +grub_keymap_add_by_string("A", "A"); +grub_keymap_add_by_string("o", "s"); +grub_keymap_add_by_string("O", "S"); +grub_keymap_add_by_string("e", "d"); +grub_keymap_add_by_string("E", "D"); +grub_keymap_add_by_string("u", "f"); +grub_keymap_add_by_string("U", "F"); +grub_keymap_add_by_string("i", "g"); +grub_keymap_add_by_string("I", "G"); +grub_keymap_add_by_string("d", "h"); +grub_keymap_add_by_string("D", "H"); +grub_keymap_add_by_string("h", "j"); +grub_keymap_add_by_string("H", "J"); +grub_keymap_add_by_string("t", "k"); +grub_keymap_add_by_string("T", "K"); +grub_keymap_add_by_string("n", "l"); +grub_keymap_add_by_string("N", "L"); +grub_keymap_add_by_string("s", "semicolon"); +grub_keymap_add_by_string("S", "colon"); +grub_keymap_add_by_string("minus", "quote"); +grub_keymap_add_by_string("underscore", "doublequote"); +grub_keymap_add_by_string("semicolon", "z"); +grub_keymap_add_by_string("colon", "Z"); +grub_keymap_add_by_string("q", "x"); +grub_keymap_add_by_string("Q", "X"); +grub_keymap_add_by_string("j", "c"); +grub_keymap_add_by_string("J", "C"); +grub_keymap_add_by_string("k", "v"); +grub_keymap_add_by_string("K", "V"); +grub_keymap_add_by_string("x", "b"); +grub_keymap_add_by_string("X", "B"); +grub_keymap_add_by_string("b", "n"); +grub_keymap_add_by_string("B", "N"); +grub_keymap_add_by_string("w", "comma"); +grub_keymap_add_by_string("W", "less"); +grub_keymap_add_by_string("v", "period"); +grub_keymap_add_by_string("V", "greater"); +grub_keymap_add_by_string("z", "slash"); +grub_keymap_add_by_string("Z", "question"); +grub_keymap_add_by_string("slash", "bracketleft"); +grub_keymap_add_by_string("question", "braceleft"); +grub_keymap_add_by_string("equal", "bracketright"); +grub_keymap_add_by_string("plus", "braceright"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_FRENCH(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("less", "backquote"); +grub_keymap_add_by_string("greater", "tilde"); +grub_keymap_add_by_string("ampersand", "1"); +grub_keymap_add_by_string("1", "exclam"); +grub_keymap_add_by_string("tilde", "2"); +grub_keymap_add_by_string("2", "at"); +grub_keymap_add_by_string("doublequote", "3"); +grub_keymap_add_by_string("3", "numbersign"); +grub_keymap_add_by_string("quote", "4"); +grub_keymap_add_by_string("4", "dollar"); +grub_keymap_add_by_string("parenleft", "5"); +grub_keymap_add_by_string("5", "percent"); +grub_keymap_add_by_string("minus", "6"); +grub_keymap_add_by_string("6", "caret"); +grub_keymap_add_by_string("backquote", "7"); +grub_keymap_add_by_string("7", "ampersand"); +grub_keymap_add_by_string("underscore", "8"); +grub_keymap_add_by_string("8", "asterisk"); +grub_keymap_add_by_string("backslash", "9"); +grub_keymap_add_by_string("9", "parenleft"); +grub_keymap_add_by_string("at", "0"); +grub_keymap_add_by_string("0", "parenright"); +grub_keymap_add_by_string("parenright", "minus"); +grub_keymap_add_by_string("numbersign", "underscore"); +grub_keymap_add_by_string("a", "q"); +grub_keymap_add_by_string("A", "Q"); +grub_keymap_add_by_string("z", "w"); +grub_keymap_add_by_string("Z", "W"); +grub_keymap_add_by_string("caret", "bracketleft"); +grub_keymap_add_by_string("dollar", "bracketright"); +grub_keymap_add_by_string("q", "a"); +grub_keymap_add_by_string("Q", "A"); +grub_keymap_add_by_string("m", "semicolon"); +grub_keymap_add_by_string("M", "colon"); +grub_keymap_add_by_string("bracketleft", "quote"); +grub_keymap_add_by_string("percent", "doublequote"); +grub_keymap_add_by_string("asterisk", "backslash"); +grub_keymap_add_by_string("bracketright", "bar"); +grub_keymap_add_by_string("w", "z"); +grub_keymap_add_by_string("W", "Z"); +grub_keymap_add_by_string("comma", "m"); +grub_keymap_add_by_string("question", "M"); +grub_keymap_add_by_string("semicolon", "comma"); +grub_keymap_add_by_string("period", "less"); +grub_keymap_add_by_string("colon", "period"); +grub_keymap_add_by_string("slash", "greater"); +grub_keymap_add_by_string("exclam", "slash"); +grub_keymap_add_by_string("bar", "question"); +grub_keymap_add_by_string("tilde", "A2"); +grub_keymap_add_by_string("numbersign", "A3"); +grub_keymap_add_by_string("braceleft", "A4"); +grub_keymap_add_by_string("bracketleft", "A5"); +grub_keymap_add_by_string("bar", "A6"); +grub_keymap_add_by_string("quote", "A7"); +grub_keymap_add_by_string("backslash", "A8"); +grub_keymap_add_by_string("caret", "A9"); +grub_keymap_add_by_string("at", "A0"); +grub_keymap_add_by_string("bracketright", "Aminus"); +grub_keymap_add_by_string("braceright", "Aequal"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_GERMAN(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("ampersand", "caret"); +grub_keymap_add_by_string("slash", "ampersand"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("equal", "parenright"); +grub_keymap_add_by_string("question", "underscore"); +grub_keymap_add_by_string("backslash", "minus"); +grub_keymap_add_by_string("z", "y"); +grub_keymap_add_by_string("Z", "Y"); +grub_keymap_add_by_string("y", "z"); +grub_keymap_add_by_string("Y", "Z"); +grub_keymap_add_by_string("plus", "bracketright"); +grub_keymap_add_by_string("asterisk", "braceright"); +grub_keymap_add_by_string("semicolon", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("backslash", "Aminus"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("caret", "backquote"); +grub_keymap_add_by_string("quote", "equal"); +grub_keymap_add_by_string("backquote", "plus"); +grub_keymap_add_by_string("braceright", "doublequote"); +grub_keymap_add_by_string("bar", "bracketleft"); +grub_keymap_add_by_string("at", "braceleft"); +grub_keymap_add_by_string("numbersign", "backslash"); +grub_keymap_add_by_string("at", "Aq"); +grub_keymap_add_by_string("less", "backquote"); +grub_keymap_add_by_string("greater", "tilde"); +grub_keymap_add_by_string("braceleft", "A7"); +grub_keymap_add_by_string("bracketleft", "A8"); +grub_keymap_add_by_string("bracketright", "A9"); +grub_keymap_add_by_string("braceright", "A0"); +grub_keymap_add_by_string("tilde", "Abracketright"); +grub_keymap_add_by_string("backslash", "Aminus"); +grub_keymap_add_by_string("quote", "bar"); +grub_keymap_add_by_string("greater", "semicolon"); +grub_keymap_add_by_string("less", "colon"); +grub_keymap_add_by_string("bar", "quote"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_ITALIANO(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("backslash", "backquote"); +grub_keymap_add_by_string("bar", "tilde"); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("tilde", "numbersign"); +grub_keymap_add_by_string("ampersand", "caret"); +grub_keymap_add_by_string("slash", "ampersand"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("equal", "parenright"); +grub_keymap_add_by_string("quote", "minus"); +grub_keymap_add_by_string("question", "underscore"); +grub_keymap_add_by_string("caret", "plus"); +grub_keymap_add_by_string("bracketleft", "bracketleft"); +grub_keymap_add_by_string("bracketright", "braceleft"); +grub_keymap_add_by_string("plus", "bracketright"); +grub_keymap_add_by_string("asterisk", "braceright"); +grub_keymap_add_by_string("at", "semicolon"); +grub_keymap_add_by_string("braceleft", "colon"); +grub_keymap_add_by_string("numbersign", "quote"); +grub_keymap_add_by_string("braceright", "doublequote"); +grub_keymap_add_by_string("less", "backslash"); +grub_keymap_add_by_string("greater", "bar"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("semicolon", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("bracketleft", "Abracketleft"); +grub_keymap_add_by_string("bracketright", "Abracketright"); +grub_keymap_add_by_string("at", "Asemicolon"); +grub_keymap_add_by_string("numbersign", "Aquote"); +grub_keymap_add_by_string("braceright", "Abraceright"); +grub_keymap_add_by_string("braceleft", "Abraceleft"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_JAPAN_106(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("at", "bracketleft"); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("ampersand", "caret"); +grub_keymap_add_by_string("quote", "ampersand"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("underscore", "parenright"); +grub_keymap_add_by_string("equal", "underscore"); +grub_keymap_add_by_string("plus", "colon"); +grub_keymap_add_by_string("colon", "quote"); +grub_keymap_add_by_string("asterisk", "doublequote"); +grub_keymap_add_by_string("bracketleft", "bracketright"); +grub_keymap_add_by_string("braceleft", "braceright"); +grub_keymap_add_by_string("bracketright", "backslash"); +grub_keymap_add_by_string("braceright", "bar"); +grub_keymap_add_by_string("backslash", "backquote"); +grub_keymap_add_by_string("tilde", "plus"); +grub_keymap_add_by_string("caret", "equal"); +grub_keymap_add_by_string("backquote", "braceleft"); +grub_keymap_add_by_string("bar", "tilde"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_LATIN_USA(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("bar", "backquote"); +grub_keymap_add_by_string("quote", "minus"); +grub_keymap_add_by_string("question", "underscore"); +grub_keymap_add_by_string("backquote", "bracketleft"); +grub_keymap_add_by_string("plus", "bracketright"); +grub_keymap_add_by_string("braceleft", "quote"); +grub_keymap_add_by_string("braceright", "backslash"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("ampersand", "caret"); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("slash", "ampersand"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("equal", "parenright"); +grub_keymap_add_by_string("asterisk", "braceright"); +grub_keymap_add_by_string("bracketleft", "doublequote"); +grub_keymap_add_by_string("bracketright", "bar"); +grub_keymap_add_by_string("semicolon", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("caret", "Aquote"); +grub_keymap_add_by_string("doublequote", "braceleft"); +grub_keymap_add_by_string("at", "Aq"); +grub_keymap_add_by_string("backquote", "Abackslash"); +grub_keymap_add_by_string("backslash", "Aminus"); +grub_keymap_add_by_string("greater", "plus"); +grub_keymap_add_by_string("less", "equal"); +grub_keymap_add_by_string("backslash", "Aminus"); +grub_keymap_add_by_string("backquote", "Abackslash"); +grub_keymap_add_by_string("tilde", "Abracketright"); +grub_keymap_add_by_string("caret", "Aquote"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_PORTU_BRAZIL(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("quote", "backquote"); +grub_keymap_add_by_string("quote", "bracketleft"); +grub_keymap_add_by_string("bracketleft", "bracketright"); +grub_keymap_add_by_string("tilde", "quote"); +grub_keymap_add_by_string("bracketright", "backslash"); +grub_keymap_add_by_string("semicolon", "slash"); +grub_keymap_add_by_string("bar", "colon"); +grub_keymap_add_by_string("doublequote", "tilde"); +grub_keymap_add_by_string("backquote", "braceleft"); +grub_keymap_add_by_string("braceleft", "braceright"); +grub_keymap_add_by_string("caret", "doublequote"); +grub_keymap_add_by_string("braceright", "bar"); +grub_keymap_add_by_string("colon", "question"); +grub_keymap_add_by_string("backslash", "semicolon"); +grub_keymap_add_by_string("bar", "Atilde"); +grub_keymap_add_by_string("backslash", "Abackquote"); +grub_keymap_add_by_string("slash", "Aq"); +grub_keymap_add_by_string("question", "Aw"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_QWERTY_UK(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("at", "doublequote"); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("tilde", "bar"); +grub_keymap_add_by_string("numbersign", "backslash"); +grub_keymap_add_by_string("backslash", "numbersign"); +grub_keymap_add_by_string("bar", "tilde"); +grub_keymap_add_by_string("backslash", "Atilde"); +grub_keymap_add_by_string("backslash", "Abackquote"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_QWERTZ(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("ampersand", "percent"); +grub_keymap_add_by_string("slash", "ampersand"); +grub_keymap_add_by_string("equal", "parenright"); +grub_keymap_add_by_string("question", "underscore"); +grub_keymap_add_by_string("backslash", "minus"); +grub_keymap_add_by_string("z", "y"); +grub_keymap_add_by_string("Z", "Y"); +grub_keymap_add_by_string("y", "z"); +grub_keymap_add_by_string("Y", "Z"); +grub_keymap_add_by_string("plus", "bracketright"); +grub_keymap_add_by_string("asterisk", "braceright"); +grub_keymap_add_by_string("semicolon", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("caret", "backquote"); +grub_keymap_add_by_string("backquote", "equal"); +grub_keymap_add_by_string("numbersign", "backslash"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("percent", "caret"); +grub_keymap_add_by_string("less", "numbersign"); +grub_keymap_add_by_string("greater", "bar"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_QWERTZ_HUN(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("y", "z"); +grub_keymap_add_by_string("z", "y"); +grub_keymap_add_by_string("Y", "Z"); +grub_keymap_add_by_string("Z", "Y"); +grub_keymap_add_by_string("0", "backquote"); +grub_keymap_add_by_string("quote", "exclam"); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("plus", "numbersign"); +grub_keymap_add_by_string("exclam", "dollar"); +grub_keymap_add_by_string("slash", "caret"); +grub_keymap_add_by_string("equal", "ampersand"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("backslash", "Aq"); +grub_keymap_add_by_string("bar", "Aw"); +grub_keymap_add_by_string("bracketleft", "Af"); +grub_keymap_add_by_string("bracketright", "Ag"); +grub_keymap_add_by_string("greater", "Az"); +grub_keymap_add_by_string("numbersign", "Ax"); +grub_keymap_add_by_string("ampersand", "Ac"); +grub_keymap_add_by_string("at", "Av"); +grub_keymap_add_by_string("braceleft", "Ab"); +grub_keymap_add_by_string("braceright", "An"); +grub_keymap_add_by_string("less", "Am"); +grub_keymap_add_by_string("dollar", "colon"); +grub_keymap_add_by_string("question", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("at", "doublequote"); +grub_keymap_add_by_string("tilde", "A1"); +grub_keymap_add_by_string("caret", "A3"); +grub_keymap_add_by_string("backquote", "A7"); +grub_keymap_add_by_string("asterisk", "0"); +grub_keymap_add_by_string("dollar", "Asemicolon"); +grub_keymap_add_by_string("semicolon", "Acomma"); +grub_keymap_add_by_string("greater", "Aperiod"); +grub_keymap_add_by_string("asterisk", "Aslash"); +grub_keymap_add_by_string("backquote", "A9"); +grub_keymap_add_by_string("doublequote", "A0"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_QWERTZ_SLOV_CROAT(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("quote", "minus"); +grub_keymap_add_by_string("plus", "equal"); +grub_keymap_add_by_string("y", "z"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("doublequote", "tilde"); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("ampersand", "caret"); +grub_keymap_add_by_string("slash", "ampersand"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("equal", "parenright"); +grub_keymap_add_by_string("question", "underscore"); +grub_keymap_add_by_string("asterisk", "plus"); +grub_keymap_add_by_string("Y", "Z"); +grub_keymap_add_by_string("semicolon", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("tilde", "A1"); +grub_keymap_add_by_string("caret", "A3"); +grub_keymap_add_by_string("backquote", "A7"); +grub_keymap_add_by_string("backslash", "Aq"); +grub_keymap_add_by_string("bar", "Aw"); +grub_keymap_add_by_string("bracketleft", "Af"); +grub_keymap_add_by_string("bracketright", "Ag"); +grub_keymap_add_by_string("at", "Av"); +grub_keymap_add_by_string("braceleft", "Ab"); +grub_keymap_add_by_string("braceright", "An"); +grub_keymap_add_by_string("less", "Acomma"); +grub_keymap_add_by_string("greater", "Aperiod"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_SPANISH(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("slash", "ampersand"); +grub_keymap_add_by_string("ampersand", "caret"); +grub_keymap_add_by_string("caret", "braceleft"); +grub_keymap_add_by_string("asterisk", "braceright"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("equal", "parenright"); +grub_keymap_add_by_string("quote", "minus"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("question", "underscore"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("greater", "bar"); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("backslash", "backquote"); +grub_keymap_add_by_string("less", "backslash"); +grub_keymap_add_by_string("semicolon", "less"); +grub_keymap_add_by_string("backquote", "bracketleft"); +grub_keymap_add_by_string("plus", "bracketright"); +grub_keymap_add_by_string("plus", "colon"); +grub_keymap_add_by_string("at", "semicolon"); +grub_keymap_add_by_string("bar", "A1"); +grub_keymap_add_by_string("at", "A2"); +grub_keymap_add_by_string("numbersign", "A3"); +grub_keymap_add_by_string("tilde", "A4"); +grub_keymap_add_by_string("bracketleft", "Abracketleft"); +grub_keymap_add_by_string("bracketright", "Abracketright"); +grub_keymap_add_by_string("braceleft", "Aquote"); +grub_keymap_add_by_string("braceright", "Abackslash"); +grub_keymap_add_by_string("greater", "bar"); +grub_keymap_add_by_string("less", "backslash"); +grub_keymap_add_by_string("backslash", "Abackquote"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_SWEDISH(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("plus", "minus"); +grub_keymap_add_by_string("quote", "equal"); +grub_keymap_add_by_string("doublequote", "bracketright"); +grub_keymap_add_by_string("quote", "backslash"); +grub_keymap_add_by_string("minus", "slash"); +grub_keymap_add_by_string("doublequote", "at"); +grub_keymap_add_by_string("ampersand", "caret"); +grub_keymap_add_by_string("slash", "ampersand"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("equal", "parenright"); +grub_keymap_add_by_string("question", "underscore"); +grub_keymap_add_by_string("caret", "braceright"); +grub_keymap_add_by_string("asterisk", "bar"); +grub_keymap_add_by_string("backquote", "plus"); +grub_keymap_add_by_string("semicolon", "less"); +grub_keymap_add_by_string("colon", "greater"); +grub_keymap_add_by_string("underscore", "question"); +grub_keymap_add_by_string("bar", "Atilde"); +grub_keymap_add_by_string("backslash", "Abackquote"); +grub_keymap_add_by_string("greater", "tilde"); +grub_keymap_add_by_string("at", "A2"); +grub_keymap_add_by_string("dollar", "A4"); +grub_keymap_add_by_string("braceleft", "A7"); +grub_keymap_add_by_string("bracketleft", "A8"); +grub_keymap_add_by_string("bracketright", "A9"); +grub_keymap_add_by_string("braceright", "A0"); +grub_keymap_add_by_string("backslash", "Aminus"); +grub_keymap_add_by_string("less", "quote"); +grub_keymap_add_by_string("greater", "doublequote"); +grub_keymap_add_by_string("tilde", "Abracketright"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_TURKISH_Q(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("doublequote", "backquote"); +grub_keymap_add_by_string("asterisk", "minus"); +grub_keymap_add_by_string("minus", "equal"); +grub_keymap_add_by_string("comma", "backslash"); +grub_keymap_add_by_string("period", "slash"); +grub_keymap_add_by_string("quote", "at"); +grub_keymap_add_by_string("caret", "numbersign"); +grub_keymap_add_by_string("plus", "dollar"); +grub_keymap_add_by_string("ampersand", "caret"); +grub_keymap_add_by_string("slash", "ampersand"); +grub_keymap_add_by_string("parenleft", "asterisk"); +grub_keymap_add_by_string("parenright", "parenleft"); +grub_keymap_add_by_string("equal", "parenright"); +grub_keymap_add_by_string("question", "underscore"); +grub_keymap_add_by_string("underscore", "plus"); +grub_keymap_add_by_string("semicolon", "bar"); +grub_keymap_add_by_string("colon", "question"); +grub_keymap_add_by_string("less", "Abackquote"); +grub_keymap_add_by_string("greater", "A1"); +grub_keymap_add_by_string("numbersign", "A3"); +grub_keymap_add_by_string("dollar", "A4"); +grub_keymap_add_by_string("braceleft", "A7"); +grub_keymap_add_by_string("bracketleft", "A8"); +grub_keymap_add_by_string("bracketright", "A9"); +grub_keymap_add_by_string("braceright", "A0"); +grub_keymap_add_by_string("backslash", "Aminus"); +grub_keymap_add_by_string("bar", "Aequal"); +grub_keymap_add_by_string("at", "Aq"); +grub_keymap_add_by_string("doublequote", "Abracketleft"); +grub_keymap_add_by_string("tilde", "Abracketright"); +grub_keymap_enable(); +} +static void ventoy_keyboard_layout_VIETNAMESE(void) { +grub_keymap_reset(); +grub_keymap_add_by_string("exclam", "A1"); +grub_keymap_add_by_string("at", "A2"); +grub_keymap_add_by_string("numbersign", "A3"); +grub_keymap_add_by_string("dollar", "A4"); +grub_keymap_add_by_string("percent", "A5"); +grub_keymap_add_by_string("caret", "A6"); +grub_keymap_add_by_string("ampersand", "A7"); +grub_keymap_add_by_string("asterisk", "A8"); +grub_keymap_add_by_string("parenleft", "A9"); +grub_keymap_add_by_string("parenright", "A0"); +grub_keymap_add_by_string("plus", "Aplus"); +grub_keymap_add_by_string("equal", "Aequal"); +grub_keymap_add_by_string("braceleft", "Abraceleft"); +grub_keymap_add_by_string("braceright", "Abraceright"); +grub_keymap_add_by_string("colon", "Acolon"); +grub_keymap_add_by_string("semicolon", "Asemicolon"); +grub_keymap_add_by_string("quote", "Aquote"); +grub_keymap_add_by_string("backslash", "Abackslash"); +grub_keymap_add_by_string("less", "Aless"); +grub_keymap_add_by_string("greater", "Agreater"); +grub_keymap_add_by_string("comma", "Acomma"); +grub_keymap_add_by_string("period", "Aperiod"); +grub_keymap_add_by_string("question", "Aquestion"); +grub_keymap_add_by_string("slash", "Aslash"); +grub_keymap_add_by_string("tilde", "Atilde"); +grub_keymap_add_by_string("backquote", "Abackquote"); +grub_keymap_add_by_string("bracketright", "Abracketright"); +grub_keymap_add_by_string("bracketleft", "Abracketleft"); +grub_keymap_add_by_string("bar", "Abar"); +grub_keymap_add_by_string("doublequote", "Adoublequote"); +grub_keymap_add_by_string("colon", "Acolon"); +grub_keymap_add_by_string("minus", "Aminus"); +grub_keymap_add_by_string("underscore", "Aunderscore"); +grub_keymap_enable(); +} +void ventoy_set_keyboard_layout(const char *layout); +void ventoy_set_keyboard_layout(const char *layout) { +ventoy_keyboard_set_layout(QWERTY_USA); +ventoy_keyboard_set_layout(AZERTY); +ventoy_keyboard_set_layout(CZECH_QWERTY); +ventoy_keyboard_set_layout(CZECH_QWERTZ); +ventoy_keyboard_set_layout(DANISH); +ventoy_keyboard_set_layout(DVORAK_USA); +ventoy_keyboard_set_layout(FRENCH); +ventoy_keyboard_set_layout(GERMAN); +ventoy_keyboard_set_layout(ITALIANO); +ventoy_keyboard_set_layout(JAPAN_106); +ventoy_keyboard_set_layout(LATIN_USA); +ventoy_keyboard_set_layout(PORTU_BRAZIL); +ventoy_keyboard_set_layout(QWERTY_UK); +ventoy_keyboard_set_layout(QWERTZ); +ventoy_keyboard_set_layout(QWERTZ_HUN); +ventoy_keyboard_set_layout(QWERTZ_SLOV_CROAT); +ventoy_keyboard_set_layout(SPANISH); +ventoy_keyboard_set_layout(SWEDISH); +ventoy_keyboard_set_layout(TURKISH_Q); +ventoy_keyboard_set_layout(VIETNAMESE); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/serial.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/serial.c new file mode 100644 index 0000000..d94da3e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/serial.c @@ -0,0 +1,463 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#if !defined (GRUB_MACHINE_EMU) && ((defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__)) +#include +#endif +#include +#include +#include +#ifdef GRUB_MACHINE_MIPS_LOONGSON +#include +#endif +#ifdef GRUB_MACHINE_IEEE1275 +#include +#endif + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define FOR_SERIAL_PORTS(var) FOR_LIST_ELEMENTS((var), (grub_serial_ports)) + +enum + { + OPTION_UNIT, + OPTION_PORT, + OPTION_SPEED, + OPTION_WORD, + OPTION_PARITY, + OPTION_STOP, + OPTION_BASE_CLOCK, + OPTION_RTSCTS + }; + +/* Argument options. */ +static const struct grub_arg_option options[] = +{ + {"unit", 'u', 0, N_("Set the serial unit."), 0, ARG_TYPE_INT}, + {"port", 'p', 0, N_("Set the serial port address."), 0, ARG_TYPE_STRING}, + {"speed", 's', 0, N_("Set the serial port speed."), 0, ARG_TYPE_INT}, + {"word", 'w', 0, N_("Set the serial port word length."), 0, ARG_TYPE_INT}, + {"parity", 'r', 0, N_("Set the serial port parity."), 0, ARG_TYPE_STRING}, + {"stop", 't', 0, N_("Set the serial port stop bits."), 0, ARG_TYPE_INT}, + {"base-clock", 'b', 0, N_("Set the base frequency."), 0, ARG_TYPE_STRING}, + {"rtscts", 'f', 0, N_("Enable/disable RTS/CTS."), "on|off", ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} +}; + +static struct grub_serial_port *grub_serial_ports; + +struct grub_serial_output_state +{ + struct grub_terminfo_output_state tinfo; + struct grub_serial_port *port; +}; + +struct grub_serial_input_state +{ + struct grub_terminfo_input_state tinfo; + struct grub_serial_port *port; +}; + +static void +serial_put (grub_term_output_t term, const int c) +{ + struct grub_serial_output_state *data = term->data; + data->port->driver->put (data->port, c); +} + +static int +serial_fetch (grub_term_input_t term) +{ + struct grub_serial_input_state *data = term->data; + return data->port->driver->fetch (data->port); +} + +static const struct grub_serial_input_state grub_serial_terminfo_input_template = + { + .tinfo = + { + .readkey = serial_fetch + } + }; + +static const struct grub_serial_output_state grub_serial_terminfo_output_template = + { + .tinfo = + { + .put = serial_put, + .size = { 80, 24 } + } + }; + +static struct grub_serial_input_state grub_serial_terminfo_input; + +static struct grub_serial_output_state grub_serial_terminfo_output; + +static int registered = 0; + +static struct grub_term_input grub_serial_term_input = +{ + .name = "serial", + .init = grub_terminfo_input_init, + .getkey = grub_terminfo_getkey, + .data = &grub_serial_terminfo_input +}; + +static struct grub_term_output grub_serial_term_output = +{ + .name = "serial", + .init = grub_terminfo_output_init, + .putchar = grub_terminfo_putchar, + .getwh = grub_terminfo_getwh, + .getxy = grub_terminfo_getxy, + .gotoxy = grub_terminfo_gotoxy, + .cls = grub_terminfo_cls, + .setcolorstate = grub_terminfo_setcolorstate, + .setcursor = grub_terminfo_setcursor, + .flags = GRUB_TERM_CODE_TYPE_ASCII, + .data = &grub_serial_terminfo_output, + .progress_update_divisor = GRUB_PROGRESS_SLOW +}; + + + +struct grub_serial_port * +grub_serial_find (const char *name) +{ + struct grub_serial_port *port; + + FOR_SERIAL_PORTS (port) + if (grub_strcmp (port->name, name) == 0) + break; + +#if ((defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__)) && !defined(GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC) + if (!port && grub_memcmp (name, "port", sizeof ("port") - 1) == 0 + && grub_isxdigit (name [sizeof ("port") - 1])) + { + name = grub_serial_ns8250_add_port (grub_strtoul (&name[sizeof ("port") - 1], + 0, 16)); + if (!name) + return NULL; + + FOR_SERIAL_PORTS (port) + if (grub_strcmp (port->name, name) == 0) + break; + } +#endif + +#ifdef GRUB_MACHINE_IEEE1275 + if (!port && grub_memcmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) == 0) + { + name = grub_ofserial_add_port (&name[sizeof ("ieee1275/") - 1]); + if (!name) + return NULL; + + FOR_SERIAL_PORTS (port) + if (grub_strcmp (port->name, name) == 0) + break; + } +#endif + + return port; +} + +static grub_err_t +grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + char pname[40]; + const char *name = NULL; + struct grub_serial_port *port; + struct grub_serial_config config; + grub_err_t err; + + if (state[OPTION_UNIT].set) + { + grub_snprintf (pname, sizeof (pname), "com%ld", + grub_strtoul (state[0].arg, 0, 0)); + name = pname; + } + + if (state[OPTION_PORT].set) + { + grub_snprintf (pname, sizeof (pname), "port%lx", + grub_strtoul (state[1].arg, 0, 0)); + name = pname; + } + + if (argc >= 1) + name = args[0]; + + if (!name) + name = "com0"; + + port = grub_serial_find (name); + if (!port) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("serial port `%s' isn't found"), + name); + + config = port->config; + + if (state[OPTION_SPEED].set) { + config.speed = grub_strtoul (state[OPTION_SPEED].arg, 0, 0); + if (config.speed == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("unsupported serial port parity")); + } + + if (state[OPTION_WORD].set) + config.word_len = grub_strtoul (state[OPTION_WORD].arg, 0, 0); + + if (state[OPTION_PARITY].set) + { + if (! grub_strcmp (state[OPTION_PARITY].arg, "no")) + config.parity = GRUB_SERIAL_PARITY_NONE; + else if (! grub_strcmp (state[OPTION_PARITY].arg, "odd")) + config.parity = GRUB_SERIAL_PARITY_ODD; + else if (! grub_strcmp (state[OPTION_PARITY].arg, "even")) + config.parity = GRUB_SERIAL_PARITY_EVEN; + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("unsupported serial port parity")); + } + + if (state[OPTION_RTSCTS].set) + { + if (grub_strcmp (state[OPTION_RTSCTS].arg, "on") == 0) + config.rtscts = 1; + else if (grub_strcmp (state[OPTION_RTSCTS].arg, "off") == 0) + config.rtscts = 0; + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("unsupported serial port flow control")); + } + + if (state[OPTION_STOP].set) + { + if (! grub_strcmp (state[OPTION_STOP].arg, "1")) + config.stop_bits = GRUB_SERIAL_STOP_BITS_1; + else if (! grub_strcmp (state[OPTION_STOP].arg, "2")) + config.stop_bits = GRUB_SERIAL_STOP_BITS_2; + else if (! grub_strcmp (state[OPTION_STOP].arg, "1.5")) + config.stop_bits = GRUB_SERIAL_STOP_BITS_1_5; + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("unsupported serial port stop bits number")); + } + + if (state[OPTION_BASE_CLOCK].set) + { + char *ptr; + config.base_clock = grub_strtoull (state[OPTION_BASE_CLOCK].arg, &ptr, 0); + if (grub_errno) + return grub_errno; + if (ptr && *ptr == 'M') + config.base_clock *= 1000000; + if (ptr && (*ptr == 'k' || *ptr == 'K')) + config.base_clock *= 1000; + } + + if (config.speed == 0) + config.speed = 9600; + + /* Initialize with new settings. */ + err = port->driver->configure (port, &config); + if (err) + return err; +#if !defined (GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC) && ((defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__)) + + /* Compatibility kludge. */ + if (port->driver == &grub_ns8250_driver) + { + if (!registered) + { + grub_terminfo_output_register (&grub_serial_term_output, "vt100"); + + grub_term_register_input ("serial", &grub_serial_term_input); + grub_term_register_output ("serial", &grub_serial_term_output); + } + grub_serial_terminfo_output.port = port; + grub_serial_terminfo_input.port = port; + registered = 1; + } +#endif + return GRUB_ERR_NONE; +} + +#ifdef GRUB_MACHINE_MIPS_LOONGSON +const char loongson_defserial[][6] = + { + [GRUB_ARCH_MACHINE_YEELOONG] = "com0", + [GRUB_ARCH_MACHINE_FULOONG2F] = "com2", + [GRUB_ARCH_MACHINE_FULOONG2E] = "com1" + }; +#endif + +grub_err_t +grub_serial_register (struct grub_serial_port *port) +{ + struct grub_term_input *in; + struct grub_term_output *out; + struct grub_serial_input_state *indata; + struct grub_serial_output_state *outdata; + + in = grub_malloc (sizeof (*in)); + if (!in) + return grub_errno; + + indata = grub_malloc (sizeof (*indata)); + if (!indata) + { + grub_free (in); + return grub_errno; + } + + grub_memcpy (in, &grub_serial_term_input, sizeof (*in)); + in->data = indata; + in->name = grub_xasprintf ("serial_%s", port->name); + grub_memcpy (indata, &grub_serial_terminfo_input, sizeof (*indata)); + + if (!in->name) + { + grub_free (in); + grub_free (indata); + return grub_errno; + } + + out = grub_zalloc (sizeof (*out)); + if (!out) + { + grub_free (indata); + grub_free ((char *) in->name); + grub_free (in); + return grub_errno; + } + + outdata = grub_malloc (sizeof (*outdata)); + if (!outdata) + { + grub_free (indata); + grub_free ((char *) in->name); + grub_free (out); + grub_free (in); + return grub_errno; + } + + grub_memcpy (out, &grub_serial_term_output, sizeof (*out)); + out->data = outdata; + out->name = in->name; + grub_memcpy (outdata, &grub_serial_terminfo_output, sizeof (*outdata)); + + grub_list_push (GRUB_AS_LIST_P (&grub_serial_ports), GRUB_AS_LIST (port)); + ((struct grub_serial_input_state *) in->data)->port = port; + ((struct grub_serial_output_state *) out->data)->port = port; + port->term_in = in; + port->term_out = out; + grub_terminfo_output_register (out, "vt100"); +#ifdef GRUB_MACHINE_MIPS_LOONGSON + if (grub_strcmp (port->name, loongson_defserial[grub_arch_machine]) == 0) + { + grub_term_register_input_active ("serial_*", in); + grub_term_register_output_active ("serial_*", out); + } + else + { + grub_term_register_input_inactive ("serial_*", in); + grub_term_register_output_inactive ("serial_*", out); + } +#else + grub_term_register_input ("serial_*", in); + grub_term_register_output ("serial_*", out); +#endif + + return GRUB_ERR_NONE; +} + +void +grub_serial_unregister (struct grub_serial_port *port) +{ + if (port->driver->fini) + port->driver->fini (port); + + if (port->term_in) + grub_term_unregister_input (port->term_in); + if (port->term_out) + grub_term_unregister_output (port->term_out); + + grub_list_remove (GRUB_AS_LIST (port)); +} + +void +grub_serial_unregister_driver (struct grub_serial_driver *driver) +{ + struct grub_serial_port *port, *next; + for (port = grub_serial_ports; port; port = next) + { + next = port->next; + if (port->driver == driver) + grub_serial_unregister (port); + } +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(serial) +{ + cmd = grub_register_extcmd ("serial", grub_cmd_serial, 0, + N_("[OPTIONS...]"), + N_("Configure serial port."), options); + grub_memcpy (&grub_serial_terminfo_output, + &grub_serial_terminfo_output_template, + sizeof (grub_serial_terminfo_output)); + + grub_memcpy (&grub_serial_terminfo_input, + &grub_serial_terminfo_input_template, + sizeof (grub_serial_terminfo_input)); + +#if !defined (GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC) && ((defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__)) + grub_ns8250_init (); +#endif +#ifdef GRUB_MACHINE_IEEE1275 + grub_ofserial_init (); +#endif +#ifdef GRUB_MACHINE_EFI + grub_efiserial_init (); +#endif +#ifdef GRUB_MACHINE_ARC + grub_arcserial_init (); +#endif +} + +GRUB_MOD_FINI(serial) +{ + while (grub_serial_ports) + grub_serial_unregister (grub_serial_ports); + if (registered) + { + grub_term_unregister_input (&grub_serial_term_input); + grub_term_unregister_output (&grub_serial_term_output); + } + grub_unregister_extcmd (cmd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/setkey.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/setkey.c new file mode 100644 index 0000000..e11de1e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/term/setkey.c @@ -0,0 +1,388 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define MAX_KEYMAP 255 + +struct keymap +{ + int cnt; + int in[MAX_KEYMAP]; + int out[MAX_KEYMAP]; +}; + +static struct keymap setkey_keymap; + +struct keysym +{ + const char *name; /* the name in unshifted state */ + int code; /* scan code */ +}; + +/* The table for key symbols. (from GRUB4DOS) */ +static struct keysym keysym_table[] = +{ + {"escape", GRUB_TERM_ESC}, // ESC + {"exclam", 0x21}, // '!' + {"at", 0x40}, // '@' + {"numbersign", 0x23}, // '#' + {"dollar", 0x24}, // '$' + {"percent", 0x25}, // '%' + {"caret", 0x5E}, // '^' + {"ampersand", 0x26}, // '&' + {"asterisk", 0x2A}, // '*' + {"parenleft", 0x28}, // '(' + {"parenright", 0x29}, // ')' + {"minus", 0x2D}, // '-' + {"underscore", 0x5F}, // '_' + {"equal", 0x3D}, // '=' + {"plus", 0x2B}, // '+' + {"backspace", GRUB_TERM_BACKSPACE}, // BS + {"ctrlbackspace", GRUB_TERM_CTRL | GRUB_TERM_BACKSPACE}, // (DEL) + {"tab", GRUB_TERM_TAB}, // Tab + {"bracketleft", 0x5B}, // '[' + {"braceleft", 0x7B}, // '{' + {"bracketright", 0x5D}, // ']' + {"braceright", 0x7D}, // '}' + {"enter", 0x0D}, // Enter + {"semicolon", 0x3B}, // ';' + {"colon", 0x3A}, // ':' + {"quote", 0x27}, // '\'' + {"doublequote", 0x22}, // '"' + {"backquote", 0x60}, // '`' + {"tilde", 0x7E}, // '~' + {"backslash", 0x5C}, // '\\' + {"bar", 0x7C}, // '|' + {"comma", 0x2C}, // ',' + {"less", 0x3C}, // '<' + {"period", 0x2E}, // '.' + {"greater", 0x3E}, // '>' + {"slash", 0x2F}, // '/' + {"question", 0x3F}, // '?' + {"space", 0x20}, // Space + {"F1", GRUB_TERM_KEY_F1}, + {"F2", GRUB_TERM_KEY_F2}, + {"F3", GRUB_TERM_KEY_F3}, + {"F4", GRUB_TERM_KEY_F4}, + {"F5", GRUB_TERM_KEY_F5}, + {"F6", GRUB_TERM_KEY_F6}, + {"F7", GRUB_TERM_KEY_F7}, + {"F8", GRUB_TERM_KEY_F8}, + {"F9", GRUB_TERM_KEY_F9}, + {"F10", GRUB_TERM_KEY_F10}, + {"F11", GRUB_TERM_KEY_F11}, + {"F12", GRUB_TERM_KEY_F12}, + {"home", GRUB_TERM_KEY_HOME}, + {"uparrow", GRUB_TERM_KEY_UP}, + {"pageup", GRUB_TERM_KEY_NPAGE}, // PgUp + {"leftarrow", GRUB_TERM_KEY_LEFT}, + {"center", GRUB_TERM_KEY_CENTER}, // keypad center key + {"rightarrow", GRUB_TERM_KEY_RIGHT}, + {"end", GRUB_TERM_KEY_END}, + {"downarrow", GRUB_TERM_KEY_DOWN}, + {"pagedown", GRUB_TERM_KEY_PPAGE}, // PgDn + {"insert", GRUB_TERM_KEY_INSERT}, // Insert + {"delete", GRUB_TERM_KEY_DC}, // Delete + {"shiftF1", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F1}, + {"shiftF2", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F2}, + {"shiftF3", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F3}, + {"shiftF4", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F4}, + {"shiftF5", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F5}, + {"shiftF6", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F6}, + {"shiftF7", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F7}, + {"shiftF8", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F8}, + {"shiftF9", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F9}, + {"shiftF10", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F10}, + {"shiftF11", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F11}, + {"shiftF12", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F12}, + {"ctrlF1", GRUB_TERM_CTRL | GRUB_TERM_KEY_F1}, + {"ctrlF2", GRUB_TERM_CTRL | GRUB_TERM_KEY_F2}, + {"ctrlF3", GRUB_TERM_CTRL | GRUB_TERM_KEY_F3}, + {"ctrlF4", GRUB_TERM_CTRL | GRUB_TERM_KEY_F4}, + {"ctrlF5", GRUB_TERM_CTRL | GRUB_TERM_KEY_F5}, + {"ctrlF6", GRUB_TERM_CTRL | GRUB_TERM_KEY_F6}, + {"ctrlF7", GRUB_TERM_CTRL | GRUB_TERM_KEY_F7}, + {"ctrlF8", GRUB_TERM_CTRL | GRUB_TERM_KEY_F8}, + {"ctrlF9", GRUB_TERM_CTRL | GRUB_TERM_KEY_F9}, + {"ctrlF10", GRUB_TERM_CTRL | GRUB_TERM_KEY_F10}, + {"ctrlF11", GRUB_TERM_CTRL | GRUB_TERM_KEY_F11}, + {"ctrlF12", GRUB_TERM_CTRL | GRUB_TERM_KEY_F12}, + // A=Alt or AltGr. Provided by steve. + {"Aq", GRUB_TERM_ALT | 0x71}, + {"Aw", GRUB_TERM_ALT | 0x77}, + {"Ae", GRUB_TERM_ALT | 0x65}, + {"Ar", GRUB_TERM_ALT | 0x72}, + {"At", GRUB_TERM_ALT | 0x74}, + {"Ay", GRUB_TERM_ALT | 0x79}, + {"Au", GRUB_TERM_ALT | 0x75}, + {"Ai", GRUB_TERM_ALT | 0x69}, + {"Ao", GRUB_TERM_ALT | 0x6F}, + {"Ap", GRUB_TERM_ALT | 0x70}, + {"Aa", GRUB_TERM_ALT | 0x61}, + {"As", GRUB_TERM_ALT | 0x73}, + {"Ad", GRUB_TERM_ALT | 0x64}, + {"Af", GRUB_TERM_ALT | 0x66}, + {"Ag", GRUB_TERM_ALT | 0x67}, + {"Ah", GRUB_TERM_ALT | 0x68}, + {"Aj", GRUB_TERM_ALT | 0x6A}, + {"Ak", GRUB_TERM_ALT | 0x6B}, + {"Al", GRUB_TERM_ALT | 0x6C}, + {"Az", GRUB_TERM_ALT | 0x7A}, + {"Ax", GRUB_TERM_ALT | 0x78}, + {"Ac", GRUB_TERM_ALT | 0x63}, + {"Av", GRUB_TERM_ALT | 0x76}, + {"Ab", GRUB_TERM_ALT | 0x62}, + {"An", GRUB_TERM_ALT | 0x6E}, + {"Am", GRUB_TERM_ALT | 0x6D}, + {"A1", GRUB_TERM_ALT | 0x31}, + {"A2", GRUB_TERM_ALT | 0x32}, + {"A3", GRUB_TERM_ALT | 0x33}, + {"A4", GRUB_TERM_ALT | 0x34}, + {"A5", GRUB_TERM_ALT | 0x35}, + {"A6", GRUB_TERM_ALT | 0x36}, + {"A7", GRUB_TERM_ALT | 0x37}, + {"A8", GRUB_TERM_ALT | 0x38}, + {"A9", GRUB_TERM_ALT | 0x39}, + {"A0", GRUB_TERM_ALT | 0x30}, + //{"oem102", 0x5c}, + //{"shiftoem102", 0x7c}, + {"Aminus", GRUB_TERM_ALT | 0x2D}, + {"Aequal", GRUB_TERM_ALT | 0x3D}, + {"Abracketleft", GRUB_TERM_ALT | 0x5B}, + {"Abracketright", GRUB_TERM_ALT | 0x5D}, + {"Asemicolon", GRUB_TERM_ALT | 0x3B}, + {"Aquote", GRUB_TERM_ALT | 0x27}, + {"Abackquote", GRUB_TERM_ALT | 0x60}, + {"Abackslash", GRUB_TERM_ALT | 0x5C}, + {"Acomma", GRUB_TERM_ALT | 0x2C}, + {"Aperiod", GRUB_TERM_ALT | 0x2E}, + {"Aslash", GRUB_TERM_ALT | 0x2F}, + {"Acolon", GRUB_TERM_ALT | 0x3A}, + {"Aplus", GRUB_TERM_ALT | 0x2B}, + {"Aless", GRUB_TERM_ALT | 0x3C}, + {"Aunderscore", GRUB_TERM_ALT | 0x5F}, + {"Agreater", GRUB_TERM_ALT | 0x3E}, + {"Aquestion", GRUB_TERM_ALT | 0x3F}, + {"Atilde", GRUB_TERM_ALT | 0x7E}, + {"Abraceleft", GRUB_TERM_ALT | 0x7B}, + {"Abar", GRUB_TERM_ALT | 0x7C}, + {"Abraceright", GRUB_TERM_ALT | 0x7D}, + {"Adoublequote", GRUB_TERM_ALT | 0x22}, +}; + +static int grub_keymap_getkey (int key) +{ + int i; + if (key == GRUB_TERM_NO_KEY) + return key; + if (setkey_keymap.cnt > MAX_KEYMAP) + setkey_keymap.cnt = MAX_KEYMAP; + for (i = 0; i < setkey_keymap.cnt; i++) + { + if (key == setkey_keymap.in[i]) + { + key = setkey_keymap.out[i]; + break; + } + } + return key; +} + +static void +grub_keymap_reset (void) +{ + grub_memset (&setkey_keymap, 0, sizeof (struct keymap)); +} + +static grub_err_t +grub_keymap_add (int in, int out) +{ + if (in == GRUB_TERM_NO_KEY || out == GRUB_TERM_NO_KEY) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid key: %d -> %d", in, out); + if (setkey_keymap.cnt >= MAX_KEYMAP) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "keymap FULL %d", setkey_keymap.cnt); + setkey_keymap.in[setkey_keymap.cnt] = in; + setkey_keymap.out[setkey_keymap.cnt] = out; + setkey_keymap.cnt++; + return GRUB_ERR_NONE; +} + +static void +grub_keymap_enable (void) +{ + grub_key_remap = grub_keymap_getkey; +} + +static void +grub_keymap_disable (void) +{ + grub_key_remap = NULL; +} + +static void +grub_keymap_status (void) +{ + int i; + if (setkey_keymap.cnt > MAX_KEYMAP) + setkey_keymap.cnt = MAX_KEYMAP; + for (i = 0; i < setkey_keymap.cnt; i++) + { + grub_printf ("0x%x -> 0x%x\n", setkey_keymap.in[i], setkey_keymap.out[i]); + } +} + +static const struct grub_arg_option options[] = +{ + {"reset", 'r', 0, N_("Reset keymap."), 0, 0}, + {"enable", 'e', 0, N_("Enable keymap."), 0, 0}, + {"disable", 'd', 0, N_("Disable keymap."), 0, 0}, + {"status", 's', 0, N_("Display keymap."), 0, 0}, + {0, 0, 0, 0, 0, 0} +}; + +enum options +{ + SETKEY_RESET, + SETKEY_ENABLE, + SETKEY_DISABLE, + SETKEY_STATUS, +}; + +static int +ishex (const char *str) +{ + if (grub_strlen (str) < 3 || str[0] != '0') + return 0; + if (str[1] != 'x' && str[1] != 'X') + return 0; + return 1; +} + +static int +parse_key (const char *str) +{ + int i; + if (ishex (str)) + return grub_strtol (str, NULL, 16); + if (grub_strlen (str) == 1) + return (int) str[0]; + for (i = 0; i < (int) (sizeof (keysym_table) / sizeof (keysym_table[0])); i++) + { + if (grub_strcmp (str, keysym_table[i].name) == 0) + return keysym_table[i].code; + } + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid key %s", str); + return 0; +} + +static grub_err_t +grub_cmd_setkey (grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + int in, out; + if (state[SETKEY_ENABLE].set) + { + grub_keymap_enable (); + goto out; + } + if (state[SETKEY_DISABLE].set) + { + grub_keymap_disable (); + goto out; + } + if (state[SETKEY_RESET].set) + { + grub_keymap_reset (); + goto out; + } + if (state[SETKEY_STATUS].set) + { + grub_keymap_status (); + goto out; + } + if (argc != 2) + { + grub_printf + ("Key names: 0-9, A-Z, a-z or escape, exclam, at, numbersign, dollar," + "percent, caret, ampersand, asterisk, parenleft, parenright, minus," + "underscore, equal, plus, backspace, tab, bracketleft, braceleft," + "bracketright, braceright, enter, semicolon, colon, quote, doublequote," + "backquote, tilde, backslash, bar, comma, less, period, greater," + "slash, question, alt, space, delete, [ctrl|shift]F1-12." + "For Alt+ prefix with A, e.g. \'setkey at Aequal\'."); + goto out; + } + in = parse_key (args[1]); + out = parse_key (args[0]); + if (!in || !out) + goto out; + grub_keymap_add (in, out); +out: + return grub_errno; +} + +static void grub_keymap_add_by_string(const char *src, const char *dst) +{ + int in = 0; + int out = 0; + + in = parse_key(dst); + out = parse_key(src); + + if (in && out) + { + grub_keymap_add (in, out); + } +} + +#include "keyboard_layout.c" + +static grub_err_t grub_cmd_set_keylayout (grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + ventoy_set_keyboard_layout(args[0]); + return 0; +} + +static grub_extcmd_t cmd, setcmd; + +GRUB_MOD_INIT(setkey) +{ + cmd = grub_register_extcmd ("setkey", grub_cmd_setkey, 0, N_("NEW_KEY USA_KEY"), + N_("Map default USA_KEY to NEW_KEY."), options); + setcmd = grub_register_extcmd ("set_keyboard_layout", grub_cmd_set_keylayout, 0, N_("layout"), + N_("Set keyboard layout."), NULL); +} + +GRUB_MOD_FINI(setkey) +{ + grub_unregister_extcmd (cmd); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.c new file mode 100644 index 0000000..1277a78 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2014 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * @file + * + * Huffman alphabets + * + */ + +#include "wimboot.h" +#include "huffman.h" + +/** + * Transcribe binary value (for debugging) + * + * @v value Value + * @v bits Length of value (in bits) + * @ret string Transcribed value + */ +const char * huffman_bin ( unsigned long value, unsigned int bits ) { + static char buf[ ( 8 * sizeof ( value ) ) + 1 /* NUL */ ]; + char *out = buf; + + /* Sanity check */ + assert ( bits < sizeof ( buf ) ); + + /* Transcribe value */ + while ( bits-- ) + *(out++) = ( ( value & ( 1 << bits ) ) ? '1' : '0' ); + *out = '\0'; + + return buf; +} + +/** + * Dump Huffman alphabet (for debugging) + * + * @v alphabet Huffman alphabet + */ +static void __attribute__ (( unused )) +huffman_dump_alphabet ( struct huffman_alphabet *alphabet ) { + struct huffman_symbols *sym; + unsigned int bits; + unsigned int huf; + unsigned int i; + + (void)huf; + + /* Dump symbol table for each utilised length */ + for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) / + sizeof ( alphabet->huf[0] ) ) ; bits++ ) { + sym = &alphabet->huf[ bits - 1 ]; + if ( sym->freq == 0 ) + continue; + huf = ( sym->start >> sym->shift ); + DBG ( "Huffman length %d start \"%s\" freq %d:", bits, + huffman_bin ( huf, sym->bits ), sym->freq ); + for ( i = 0 ; i < sym->freq ; i++ ) { + DBG ( " %03x", sym->raw[ huf + i ] ); + } + DBG ( "\n" ); + } + + /* Dump quick lookup table */ + DBG ( "Huffman quick lookup:" ); + for ( i = 0 ; i < ( sizeof ( alphabet->lookup ) / + sizeof ( alphabet->lookup[0] ) ) ; i++ ) { + DBG ( " %d", ( alphabet->lookup[i] + 1 ) ); + } + DBG ( "\n" ); +} + +/** + * Construct Huffman alphabet + * + * @v alphabet Huffman alphabet + * @v lengths Symbol length table + * @v count Number of symbols + * @ret rc Return status code + */ +int huffman_alphabet ( struct huffman_alphabet *alphabet, + uint8_t *lengths, unsigned int count ) { + struct huffman_symbols *sym; + unsigned int huf; + unsigned int cum_freq; + unsigned int bits; + unsigned int raw; + unsigned int adjustment; + unsigned int prefix; + int empty; + int complete; + + /* Clear symbol table */ + memset ( alphabet->huf, 0, sizeof ( alphabet->huf ) ); + + /* Count number of symbols with each Huffman-coded length */ + empty = 1; + for ( raw = 0 ; raw < count ; raw++ ) { + bits = lengths[raw]; + if ( bits ) { + alphabet->huf[ bits - 1 ].freq++; + empty = 0; + } + } + + /* In the degenerate case of having no symbols (i.e. an unused + * alphabet), generate a trivial alphabet with exactly two + * single-bit codes. This allows callers to avoid having to + * check for this special case. + */ + if ( empty ) + alphabet->huf[0].freq = 2; + + /* Populate Huffman-coded symbol table */ + huf = 0; + cum_freq = 0; + for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) / + sizeof ( alphabet->huf[0] ) ) ; bits++ ) { + sym = &alphabet->huf[ bits - 1 ]; + sym->bits = bits; + sym->shift = ( HUFFMAN_BITS - bits ); + sym->start = ( huf << sym->shift ); + sym->raw = &alphabet->raw[cum_freq]; + huf += sym->freq; + if ( huf > ( 1U << bits ) ) { + DBG ( "Huffman alphabet has too many symbols with " + "lengths <=%d\n", bits ); + return -1; + } + huf <<= 1; + cum_freq += sym->freq; + } + complete = ( huf == ( 1U << bits ) ); + + /* Populate raw symbol table */ + for ( raw = 0 ; raw < count ; raw++ ) { + bits = lengths[raw]; + if ( bits ) { + sym = &alphabet->huf[ bits - 1 ]; + *(sym->raw++) = raw; + } + } + + /* Adjust Huffman-coded symbol table raw pointers and populate + * quick lookup table. + */ + for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) / + sizeof ( alphabet->huf[0] ) ) ; bits++ ) { + sym = &alphabet->huf[ bits - 1 ]; + + /* Adjust raw pointer */ + sym->raw -= sym->freq; /* Reset to first symbol */ + adjustment = ( sym->start >> sym->shift ); + sym->raw -= adjustment; /* Adjust for quick indexing */ + + /* Populate quick lookup table */ + for ( prefix = ( sym->start >> HUFFMAN_QL_SHIFT ) ; + prefix < ( 1 << HUFFMAN_QL_BITS ) ; prefix++ ) { + alphabet->lookup[prefix] = ( bits - 1 ); + } + } + + /* Check that there are no invalid codes */ + if ( ! complete ) { + DBG ( "Huffman alphabet is incomplete\n" ); + return -1; + } + + return 0; +} + +/** + * Get Huffman symbol set + * + * @v alphabet Huffman alphabet + * @v huf Raw input value (normalised to HUFFMAN_BITS bits) + * @ret sym Huffman symbol set + */ +struct huffman_symbols * huffman_sym ( struct huffman_alphabet *alphabet, + unsigned int huf ) { + struct huffman_symbols *sym; + unsigned int lookup_index; + + /* Find symbol set for this length */ + lookup_index = ( huf >> HUFFMAN_QL_SHIFT ); + sym = &alphabet->huf[ alphabet->lookup[ lookup_index ] ]; + while ( huf < sym->start ) + sym--; + return sym; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.h new file mode 100644 index 0000000..d98cc09 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/huffman.h @@ -0,0 +1,108 @@ +#ifndef _HUFFMAN_H +#define _HUFFMAN_H + +/* + * Copyright (C) 2014 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * @file + * + * Huffman alphabets + * + */ + +/** Maximum length of a Huffman symbol (in bits) */ +#define HUFFMAN_BITS 16 + +/** Raw huffman symbol */ +typedef uint16_t huffman_raw_symbol_t; + +/** Quick lookup length for a Huffman symbol (in bits) + * + * This is a policy decision. + */ +#define HUFFMAN_QL_BITS 7 + +/** Quick lookup shift */ +#define HUFFMAN_QL_SHIFT ( HUFFMAN_BITS - HUFFMAN_QL_BITS ) + +/** A Huffman-coded set of symbols of a given length */ +struct huffman_symbols { + /** Length of Huffman-coded symbols (in bits) */ + uint8_t bits; + /** Shift to normalise symbols of this length to HUFFMAN_BITS bits */ + uint8_t shift; + /** Number of Huffman-coded symbols having this length */ + uint16_t freq; + /** First symbol of this length (normalised to HUFFMAN_BITS bits) + * + * Stored as a 32-bit value to allow the value + * (1<bits; +} + +/** + * Get Huffman symbol value + * + * @v sym Huffman symbol set + * @v huf Raw input value (normalised to HUFFMAN_BITS bits) + * @ret raw Raw symbol value + */ +static inline __attribute__ (( always_inline )) huffman_raw_symbol_t +huffman_raw ( struct huffman_symbols *sym, unsigned int huf ) { + + return sym->raw[ huf >> sym->shift ]; +} + +extern int huffman_alphabet ( struct huffman_alphabet *alphabet, + uint8_t *lengths, unsigned int count ); +extern struct huffman_symbols * +huffman_sym ( struct huffman_alphabet *alphabet, unsigned int huf ); + +#endif /* _HUFFMAN_H */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.c new file mode 100644 index 0000000..6dc6507 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.c @@ -0,0 +1,668 @@ +/* + * Copyright (C) 2014 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * @file + * + * LZX decompression + * + * This algorithm is derived jointly from the document "[MS-PATCH]: + * LZX DELTA Compression and Decompression", available from + * + * http://msdn.microsoft.com/en-us/library/cc483133.aspx + * + * and from the file lzx-decompress.c in the wimlib source code. + * + */ + +#include "wimboot.h" +#include "huffman.h" +#include "lzx.h" + +/** Base positions, indexed by position slot */ +static unsigned int lzx_position_base[LZX_POSITION_SLOTS]; + +/** + * Attempt to accumulate bits from LZX bitstream + * + * @v lzx Decompressor + * @v bits Number of bits to accumulate + * @v norm_value Accumulated value (normalised to 16 bits) + * + * Note that there may not be sufficient accumulated bits in the + * bitstream; callers must check that sufficient bits are available + * before using the value. + */ +static int lzx_accumulate ( struct lzx *lzx, unsigned int bits ) { + const uint16_t *src16; + + /* Accumulate more bits if required */ + if ( ( lzx->bits < bits ) && + ( lzx->input.offset < lzx->input.len ) ) { + src16 = (const uint16_t *)( ( char * ) lzx->input.data + lzx->input.offset ); + lzx->input.offset += sizeof ( *src16 ); + lzx->accumulator |= ( *src16 << ( 16 - lzx->bits ) ); + lzx->bits += 16; + } + + return ( lzx->accumulator >> 16 ); +} + +/** + * Consume accumulated bits from LZX bitstream + * + * @v lzx Decompressor + * @v bits Number of bits to consume + * @ret rc Return status code + */ +static int lzx_consume ( struct lzx *lzx, unsigned int bits ) { + + /* Fail if insufficient bits are available */ + if ( lzx->bits < bits ) { + DBG ( "LZX input overrun in %#zx/%#zx out %#zx)\n", + lzx->input.offset, lzx->input.len, lzx->output.offset ); + return -1; + } + + /* Consume bits */ + lzx->accumulator <<= bits; + lzx->bits -= bits; + + return 0; +} + +/** + * Get bits from LZX bitstream + * + * @v lzx Decompressor + * @v bits Number of bits to fetch + * @ret value Value, or negative error + */ +static int lzx_getbits ( struct lzx *lzx, unsigned int bits ) { + int norm_value; + int rc; + + /* Accumulate more bits if required */ + norm_value = lzx_accumulate ( lzx, bits ); + + /* Consume bits */ + if ( ( rc = lzx_consume ( lzx, bits ) ) != 0 ) + return rc; + + return ( norm_value >> ( 16 - bits ) ); +} + +/** + * Align LZX bitstream for byte access + * + * @v lzx Decompressor + * @v bits Minimum number of padding bits + * @ret rc Return status code + */ +static int lzx_align ( struct lzx *lzx, unsigned int bits ) { + int pad; + + /* Get padding bits */ + pad = lzx_getbits ( lzx, bits ); + if ( pad < 0 ) + return pad; + + /* Consume all accumulated bits */ + lzx_consume ( lzx, lzx->bits ); + + return 0; +} + +/** + * Get bytes from LZX bitstream + * + * @v lzx Decompressor + * @v data Data buffer, or NULL + * @v len Length of data buffer + * @ret rc Return status code + */ +static int lzx_getbytes ( struct lzx *lzx, void *data, size_t len ) { + + /* Sanity check */ + if ( ( lzx->input.offset + len ) > lzx->input.len ) { + DBG ( "LZX input overrun in %#zx/%#zx out %#zx)\n", + lzx->input.offset, lzx->input.len, lzx->output.offset ); + return -1; + } + + /* Copy data */ + if ( data ) + memcpy ( data, ( lzx->input.data + lzx->input.offset ), len ); + lzx->input.offset += len; + + return 0; +} + +/** + * Decode LZX Huffman-coded symbol + * + * @v lzx Decompressor + * @v alphabet Huffman alphabet + * @ret raw Raw symbol, or negative error + */ +static int lzx_decode ( struct lzx *lzx, struct huffman_alphabet *alphabet ) { + struct huffman_symbols *sym; + int huf; + int rc; + + /* Accumulate sufficient bits */ + huf = lzx_accumulate ( lzx, HUFFMAN_BITS ); + if ( huf < 0 ) + return huf; + + /* Decode symbol */ + sym = huffman_sym ( alphabet, huf ); + + /* Consume bits */ + if ( ( rc = lzx_consume ( lzx, huffman_len ( sym ) ) ) != 0 ) + return rc; + + return huffman_raw ( sym, huf ); +} + +/** + * Generate Huffman alphabet from raw length table + * + * @v lzx Decompressor + * @v count Number of symbols + * @v bits Length of each length (in bits) + * @v lengths Lengths table to fill in + * @v alphabet Huffman alphabet to fill in + * @ret rc Return status code + */ +static int lzx_raw_alphabet ( struct lzx *lzx, unsigned int count, + unsigned int bits, uint8_t *lengths, + struct huffman_alphabet *alphabet ) { + unsigned int i; + int len; + int rc; + + /* Read lengths */ + for ( i = 0 ; i < count ; i++ ) { + len = lzx_getbits ( lzx, bits ); + if ( len < 0 ) + return len; + lengths[i] = len; + } + + /* Generate Huffman alphabet */ + if ( ( rc = huffman_alphabet ( alphabet, lengths, count ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Generate pretree + * + * @v lzx Decompressor + * @v count Number of symbols + * @v lengths Lengths table to fill in + * @ret rc Return status code + */ +static int lzx_pretree ( struct lzx *lzx, unsigned int count, + uint8_t *lengths ) { + unsigned int i; + unsigned int length; + int dup = 0; + int code; + int rc; + + /* Generate pretree alphabet */ + if ( ( rc = lzx_raw_alphabet ( lzx, LZX_PRETREE_CODES, + LZX_PRETREE_BITS, lzx->pretree_lengths, + &lzx->pretree ) ) != 0 ) + return rc; + + /* Read lengths */ + for ( i = 0 ; i < count ; i++ ) { + + if ( dup ) { + + /* Duplicate previous length */ + lengths[i] = lengths[ i - 1 ]; + dup--; + + } else { + + /* Get next code */ + code = lzx_decode ( lzx, &lzx->pretree ); + if ( code < 0 ) + return code; + + /* Interpret code */ + if ( code <= 16 ) { + length = ( ( lengths[i] - code + 17 ) % 17 ); + } else if ( code == 17 ) { + length = 0; + dup = lzx_getbits ( lzx, 4 ); + if ( dup < 0 ) + return dup; + dup += 3; + } else if ( code == 18 ) { + length = 0; + dup = lzx_getbits ( lzx, 5 ); + if ( dup < 0 ) + return dup; + dup += 19; + } else if ( code == 19 ) { + length = 0; + dup = lzx_getbits ( lzx, 1 ); + if ( dup < 0 ) + return dup; + dup += 3; + code = lzx_decode ( lzx, &lzx->pretree ); + if ( code < 0 ) + return code; + length = ( ( lengths[i] - code + 17 ) % 17 ); + } else { + DBG ( "Unrecognised pretree code %d\n", code ); + return -1; + } + lengths[i] = length; + } + } + + /* Sanity check */ + if ( dup ) { + DBG ( "Pretree duplicate overrun\n" ); + return -1; + } + + return 0; +} + +/** + * Generate aligned offset Huffman alphabet + * + * @v lzx Decompressor + * @ret rc Return status code + */ +static int lzx_alignoffset_alphabet ( struct lzx *lzx ) { + int rc; + + /* Generate aligned offset alphabet */ + if ( ( rc = lzx_raw_alphabet ( lzx, LZX_ALIGNOFFSET_CODES, + LZX_ALIGNOFFSET_BITS, + lzx->alignoffset_lengths, + &lzx->alignoffset ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Generate main Huffman alphabet + * + * @v lzx Decompressor + * @ret rc Return status code + */ +static int lzx_main_alphabet ( struct lzx *lzx ) { + int rc; + + /* Generate literal symbols pretree */ + if ( ( rc = lzx_pretree ( lzx, LZX_MAIN_LIT_CODES, + lzx->main_lengths.literals ) ) != 0 ) { + DBG ( "Could not construct main literal pretree\n" ); + return rc; + } + + /* Generate remaining symbols pretree */ + if ( ( rc = lzx_pretree ( lzx, ( LZX_MAIN_CODES - LZX_MAIN_LIT_CODES ), + lzx->main_lengths.remainder ) ) != 0 ) { + DBG ( "Could not construct main remainder pretree\n" ); + return rc; + } + + /* Generate Huffman alphabet */ + if ( ( rc = huffman_alphabet ( &lzx->main, lzx->main_lengths.literals, + LZX_MAIN_CODES ) ) != 0 ) { + DBG ( "Could not generate main alphabet\n" ); + return rc; + } + + return 0; +} + +/** + * Generate length Huffman alphabet + * + * @v lzx Decompressor + * @ret rc Return status code + */ +static int lzx_length_alphabet ( struct lzx *lzx ) { + int rc; + + /* Generate pretree */ + if ( ( rc = lzx_pretree ( lzx, LZX_LENGTH_CODES, + lzx->length_lengths ) ) != 0 ) { + DBG ( "Could not generate length pretree\n" ); + return rc; + } + + /* Generate Huffman alphabet */ + if ( ( rc = huffman_alphabet ( &lzx->length, lzx->length_lengths, + LZX_LENGTH_CODES ) ) != 0 ) { + DBG ( "Could not generate length alphabet\n" ); + return rc; + } + + return 0; +} + +/** + * Process LZX block header + * + * @v lzx Decompressor + * @ret rc Return status code + */ +static int lzx_block_header ( struct lzx *lzx ) { + size_t block_len; + int block_type; + int default_len; + int len_high; + int len_low; + int rc; + + /* Get block type */ + block_type = lzx_getbits ( lzx, LZX_BLOCK_TYPE_BITS ); + if ( block_type < 0 ) + return block_type; + lzx->block_type = block_type; + + /* Check block length */ + default_len = lzx_getbits ( lzx, 1 ); + if ( default_len < 0 ) + return default_len; + if ( default_len ) { + block_len = LZX_DEFAULT_BLOCK_LEN; + } else { + len_high = lzx_getbits ( lzx, 8 ); + if ( len_high < 0 ) + return len_high; + len_low = lzx_getbits ( lzx, 8 ); + if ( len_low < 0 ) + return len_low; + block_len = ( ( len_high << 8 ) | len_low ); + } + lzx->output.threshold = ( lzx->output.offset + block_len ); + + /* Handle block type */ + switch ( block_type ) { + case LZX_BLOCK_ALIGNOFFSET : + /* Generated aligned offset alphabet */ + if ( ( rc = lzx_alignoffset_alphabet ( lzx ) ) != 0 ) + return rc; + /* Fall through */ + case LZX_BLOCK_VERBATIM : + /* Generate main alphabet */ + if ( ( rc = lzx_main_alphabet ( lzx ) ) != 0 ) + return rc; + /* Generate lengths alphabet */ + if ( ( rc = lzx_length_alphabet ( lzx ) ) != 0 ) + return rc; + break; + case LZX_BLOCK_UNCOMPRESSED : + /* Align input stream */ + if ( ( rc = lzx_align ( lzx, 1 ) ) != 0 ) + return rc; + /* Read new repeated offsets */ + if ( ( rc = lzx_getbytes ( lzx, &lzx->repeated_offset, + sizeof ( lzx->repeated_offset )))!=0) + return rc; + break; + default: + DBG ( "Unrecognised block type %d\n", block_type ); + return -1; + } + + return 0; +} + +/** + * Process uncompressed data + * + * @v lzx Decompressor + * @ret rc Return status code + */ +static int lzx_uncompressed ( struct lzx *lzx ) { + void *data; + size_t len; + int rc; + + /* Copy bytes */ + data = ( lzx->output.data ? + ( lzx->output.data + lzx->output.offset ) : NULL ); + len = ( lzx->output.threshold - lzx->output.offset ); + if ( ( rc = lzx_getbytes ( lzx, data, len ) ) != 0 ) + return rc; + + /* Align input stream */ + if ( len % 2 ) + lzx->input.offset++; + + lzx->output.offset += len; + + return 0; +} + +/** + * Process an LZX token + * + * @v lzx Decompressor + * @ret rc Return status code + * + * Variable names are chosen to match the LZX specification + * pseudo-code. + */ +static int lzx_token ( struct lzx *lzx ) { + unsigned int length_header; + unsigned int position_slot; + unsigned int offset_bits; + unsigned int i; + size_t match_offset; + size_t match_length; + int verbatim_bits; + int aligned_bits; + int maindata; + int length; + uint8_t *copy; + + /* Get maindata symelse*/ + maindata = lzx_decode ( lzx, &lzx->main ); + if ( maindata < 0 ) + return maindata; + + /* Check for literals */ + if ( maindata < LZX_MAIN_LIT_CODES ) { + if ( lzx->output.data ) + lzx->output.data[lzx->output.offset] = maindata; + lzx->output.offset++; + return 0; + } + maindata -= LZX_MAIN_LIT_CODES; + + /* Calculate the match length */ + length_header = ( maindata & 7 ); + if ( length_header == 7 ) { + length = lzx_decode ( lzx, &lzx->length ); + if ( length < 0 ) + return length; + } else { + length = 0; + } + match_length = ( length_header + 2 + length ); + + /* Calculate the position slot */ + position_slot = ( maindata >> 3 ); + if ( position_slot < LZX_REPEATED_OFFSETS ) { + + /* Repeated offset */ + match_offset = lzx->repeated_offset[position_slot]; + lzx->repeated_offset[position_slot] = lzx->repeated_offset[0]; + lzx->repeated_offset[0] = match_offset; + + } else { + + /* Non-repeated offset */ + offset_bits = lzx_footer_bits ( position_slot ); + if ( ( lzx->block_type == LZX_BLOCK_ALIGNOFFSET ) && + ( offset_bits >= 3 ) ) { + verbatim_bits = lzx_getbits ( lzx, ( offset_bits - 3 )); + if ( verbatim_bits < 0 ) + return verbatim_bits; + verbatim_bits <<= 3; + aligned_bits = lzx_decode ( lzx, &lzx->alignoffset ); + if ( aligned_bits < 0 ) + return aligned_bits; + } else { + verbatim_bits = lzx_getbits ( lzx, offset_bits ); + if ( verbatim_bits < 0 ) + return verbatim_bits; + aligned_bits = 0; + } + match_offset = ( lzx_position_base[position_slot] + + verbatim_bits + aligned_bits - 2 ); + + /* Update repeated offset list */ + for ( i = ( LZX_REPEATED_OFFSETS - 1 ) ; i > 0 ; i-- ) + lzx->repeated_offset[i] = lzx->repeated_offset[ i - 1 ]; + lzx->repeated_offset[0] = match_offset; + } + + /* Copy data */ + if ( match_offset > lzx->output.offset ) { + DBG ( "LZX match underrun out 0x%x offset 0x%x len 0x%x\n", + lzx->output.offset, match_offset, match_length ); + return -1; + } + if ( lzx->output.data ) { + copy = &lzx->output.data[lzx->output.offset]; + for ( i = 0 ; i < match_length ; i++ ) + copy[i] = copy[ i - match_offset ]; + } + lzx->output.offset += match_length; + + return 0; +} + +/** + * Translate E8 jump addresses + * + * @v lzx Decompressor + */ +static void lzx_translate_jumps ( struct lzx *lzx ) { + size_t offset; + int32_t *target; + + /* Sanity check */ + if ( lzx->output.offset < 10 ) + return; + + /* Scan for jump instructions */ + for ( offset = 0 ; offset < ( lzx->output.offset - 10 ) ; offset++ ) { + + /* Check for jump instruction */ + if ( lzx->output.data[offset] != 0xe8 ) + continue; + + /* Translate jump target */ + target = ( ( int32_t * ) &lzx->output.data[ offset + 1 ] ); + if ( *target >= 0 ) { + if ( *target < LZX_WIM_MAGIC_FILESIZE ) + *target -= offset; + } else { + if ( *target >= -( ( int32_t ) offset ) ) + *target += LZX_WIM_MAGIC_FILESIZE; + } + offset += sizeof ( *target ); + } +} + +/** + * Decompress LZX-compressed data + * + * @v data Compressed data + * @v len Length of compressed data + * @v buf Decompression buffer, or NULL + * @ret out_len Length of decompressed data, or negative error + */ +ssize_t lzx_decompress ( const void *data, size_t len, void *buf ) { + struct lzx lzx; + unsigned int i; + int rc; + + /* Sanity check */ + if ( len % 2 ) { + DBG ( "LZX cannot handle odd-length input data\n" ); + //return -1; + } + + /* Initialise global state, if required */ + if ( ! lzx_position_base[ LZX_POSITION_SLOTS - 1 ] ) { + for ( i = 1 ; i < LZX_POSITION_SLOTS ; i++ ) { + lzx_position_base[i] = + ( lzx_position_base[i-1] + + ( 1 << lzx_footer_bits ( i - 1 ) ) ); + } + } + + /* Initialise decompressor */ + memset ( &lzx, 0, sizeof ( lzx ) ); + lzx.input.data = data; + lzx.input.len = len; + lzx.output.data = buf; + for ( i = 0 ; i < LZX_REPEATED_OFFSETS ; i++ ) + lzx.repeated_offset[i] = 1; + + /* Process blocks */ + while ( lzx.input.offset < lzx.input.len ) { + + /* Process block header */ + if ( ( rc = lzx_block_header ( &lzx ) ) != 0 ) + return rc; + + /* Process block contents */ + if ( lzx.block_type == LZX_BLOCK_UNCOMPRESSED ) { + + /* Copy uncompressed data */ + if ( ( rc = lzx_uncompressed ( &lzx ) ) != 0 ) + return rc; + + } else { + + /* Process token stream */ + while ( lzx.output.offset < lzx.output.threshold ) { + if ( ( rc = lzx_token ( &lzx ) ) != 0 ) + return rc; + } + } + } + + /* Postprocess to undo E8 jump compression */ + if ( lzx.output.data ) + lzx_translate_jumps ( &lzx ); + + return lzx.output.offset; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.h new file mode 100644 index 0000000..d6a7dcd --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/lzx.h @@ -0,0 +1,179 @@ +#ifndef _LZX_H +#define _LZX_H + +/* + * Copyright (C) 2014 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * @file + * + * LZX decompression + * + */ + +#include "huffman.h" + +/** Number of aligned offset codes */ +#define LZX_ALIGNOFFSET_CODES 8 + +/** Aligned offset code length (in bits) */ +#define LZX_ALIGNOFFSET_BITS 3 + +/** Number of pretree codes */ +#define LZX_PRETREE_CODES 20 + +/** Pretree code length (in bits) */ +#define LZX_PRETREE_BITS 4 + +/** Number of literal main codes */ +#define LZX_MAIN_LIT_CODES 256 + +/** Number of position slots */ +#define LZX_POSITION_SLOTS 30 + +/** Number of main codes */ +#define LZX_MAIN_CODES ( LZX_MAIN_LIT_CODES + ( 8 * LZX_POSITION_SLOTS ) ) + +/** Number of length codes */ +#define LZX_LENGTH_CODES 249 + +/** Block type length (in bits) */ +#define LZX_BLOCK_TYPE_BITS 3 + +/** Default block length */ +#define LZX_DEFAULT_BLOCK_LEN 32768 + +/** Number of repeated offsets */ +#define LZX_REPEATED_OFFSETS 3 + +/** Don't ask */ +#define LZX_WIM_MAGIC_FILESIZE 12000000 + +/** Block types */ +enum lzx_block_type { + /** Verbatim block */ + LZX_BLOCK_VERBATIM = 1, + /** Aligned offset block */ + LZX_BLOCK_ALIGNOFFSET = 2, + /** Uncompressed block */ + LZX_BLOCK_UNCOMPRESSED = 3, +}; + +/** An LZX input stream */ +struct lzx_input_stream { + /** Data */ + const uint8_t *data; + /** Length */ + size_t len; + /** Offset within stream */ + size_t offset; +}; + +/** An LZX output stream */ +struct lzx_output_stream { + /** Data, or NULL */ + uint8_t *data; + /** Offset within stream */ + size_t offset; + /** End of current block within stream */ + size_t threshold; +}; + +/** LZX decompressor */ +struct lzx { + /** Input stream */ + struct lzx_input_stream input; + /** Output stream */ + struct lzx_output_stream output; + /** Accumulator */ + uint32_t accumulator; + /** Number of bits in accumulator */ + unsigned int bits; + /** Block type */ + enum lzx_block_type block_type; + /** Repeated offsets */ + unsigned int repeated_offset[LZX_REPEATED_OFFSETS]; + + /** Aligned offset Huffman alphabet */ + struct huffman_alphabet alignoffset; + /** Aligned offset raw symbols + * + * Must immediately follow the aligned offset Huffman + * alphabet. + */ + huffman_raw_symbol_t alignoffset_raw[LZX_ALIGNOFFSET_CODES]; + /** Aligned offset code lengths */ + uint8_t alignoffset_lengths[LZX_ALIGNOFFSET_CODES]; + + /** Pretree Huffman alphabet */ + struct huffman_alphabet pretree; + /** Pretree raw symbols + * + * Must immediately follow the pretree Huffman alphabet. + */ + huffman_raw_symbol_t pretree_raw[LZX_PRETREE_CODES]; + /** Preetree code lengths */ + uint8_t pretree_lengths[LZX_PRETREE_CODES]; + + /** Main Huffman alphabet */ + struct huffman_alphabet main; + /** Main raw symbols + * + * Must immediately follow the main Huffman alphabet. + */ + huffman_raw_symbol_t main_raw[LZX_MAIN_CODES]; + /** Main code lengths */ + struct { + /** Literals */ + uint8_t literals[LZX_MAIN_LIT_CODES]; + /** Remaining symbols */ + uint8_t remainder[ LZX_MAIN_CODES - LZX_MAIN_LIT_CODES ]; + } __attribute__ (( packed )) main_lengths; + + /** Length Huffman alphabet */ + struct huffman_alphabet length; + /** Length raw symbols + * + * Must immediately follow the length Huffman alphabet. + */ + huffman_raw_symbol_t length_raw[LZX_LENGTH_CODES]; + /** Length code lengths */ + uint8_t length_lengths[LZX_LENGTH_CODES]; +}; + +/** + * Calculate number of footer bits for a given position slot + * + * @v position_slot Position slot + * @ret footer_bits Number of footer bits + */ +static inline unsigned int lzx_footer_bits ( unsigned int position_slot ) { + + if ( position_slot < 2 ) { + return 0; + } else if ( position_slot < 38 ) { + return ( ( position_slot / 2 ) - 1 ); + } else { + return 17; + } +} + +extern ssize_t lzx_decompress ( const void *data, size_t len, void *buf ); + +#endif /* _LZX_H */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/miniz.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/miniz.c new file mode 100644 index 0000000..60312a9 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/miniz.c @@ -0,0 +1,2587 @@ +/* miniz.c v1.12 - public domain deflate/inflate + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated April 12, 2012 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + * Change History + 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. + level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson for the feedback/bug report. + 5/28/11 v1.11 - Added statement from unlicense.org + 5/27/11 v1.10 - Substantial compressor optimizations: + Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a + Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). + Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. + Refactored the compression code for better readability and maintainability. + Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large + drop in throughput on some files). + 5/15/11 v1.09 - Initial stable release. + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 +*/ + +#ifndef MINIZ_HEADER_INCLUDED +#define MINIZ_HEADER_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wundef" + +#define size_t grub_size_t +#define uint8_t grub_uint8_t +#define uint16_t grub_uint16_t +#define uint32_t grub_uint32_t +#define uint64_t grub_uint64_t + +#define assert(a) + +#define memset grub_memset +#define memcpy grub_memcpy +#define memcmp grub_memcmp + +// Defines to completely disable specific portions of miniz.c: +// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. + +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. +//#define MINIZ_NO_ZLIB_APIS + +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. +//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc +// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user +// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. +//#define MINIZ_NO_MALLOC + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#else +#error ("Not little endian") +#endif + +#if MINIZ_X86_OR_X64_CPU +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#endif + +#define MINIZ_HAS_64BIT_REGISTERS 1 + +// ------------------- zlib-style API Definitions. + +// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. +typedef unsigned long mz_ulong; + +// Heap allocation callbacks. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); + +#define MZ_ADLER32_INIT (1) +// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. +mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +// Compression strategies. +enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; + +// Method +#define MZ_DEFLATED 8 + +#ifndef MINIZ_NO_ZLIB_APIS + +#define MZ_VERSION "9.1.12" +#define MZ_VERNUM 0x91C0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 12 +#define MZ_VER_SUBREVISION 0 + +// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). +enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; + +// Return status codes. MZ_PARAM_ERROR is non-standard. +enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; + +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; + +// Window bits +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +// Compression/decompression stream struct. +typedef struct mz_stream_s +{ + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far + + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far + + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + + mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer + + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong crc32; // crc32 of the source or uncompressed data + mz_ulong reserved; +} mz_stream; + +typedef mz_stream *mz_streamp; + +// Returns the version string of miniz.c. +const char *mz_version(void); + +// mz_deflateInit() initializes a compressor with default options: +// Parameters: +// pStream must point to an initialized mz_stream struct. +// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. +// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. +// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if the input parameters are bogus. +// MZ_MEM_ERROR on out of memory. +int mz_deflateInit(mz_streamp pStream, int level); + +// mz_deflateInit2() is like mz_deflate(), except with more control: +// Additional parameters: +// method must be MZ_DEFLATED +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) +// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); + +// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). +int mz_deflateReset(mz_streamp pStream); + +// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. +// Return values: +// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). +// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) +int mz_deflate(mz_streamp pStream, int flush); + +// mz_deflateEnd() deinitializes a compressor: +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +int mz_deflateEnd(mz_streamp pStream); + +// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +// Single-call compression functions mz_compress() and mz_compress2(): +// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); + +// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). +mz_ulong mz_compressBound(mz_ulong source_len); + +// Initializes a decompressor. +int mz_inflateInit(mz_streamp pStream); + +// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. +// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). +// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. +// Return values: +// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. +// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_DATA_ERROR if the deflate stream is invalid. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again +// with more input data, or with more room in the output buffer (except when using single call decompression, described above). +int mz_inflate(mz_streamp pStream, int flush); + +// Deinitializes a decompressor. +int mz_inflateEnd(mz_streamp pStream); + +// Single-call decompression. +// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); + +// Returns a string description of the specified error code, or NULL if the error code is invalid. +const char *mz_error(int err); + +// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + typedef unsigned char Byte; + typedef unsigned int uInt; + typedef mz_ulong uLong; + typedef Byte Bytef; + typedef uInt uIntf; + typedef char charf; + typedef int intf; + typedef void *voidpf; + typedef uLong uLongf; + typedef void *voidp; + typedef void *const voidpc; + #define Z_NULL 0 + #define Z_NO_FLUSH MZ_NO_FLUSH + #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH + #define Z_SYNC_FLUSH MZ_SYNC_FLUSH + #define Z_FULL_FLUSH MZ_FULL_FLUSH + #define Z_FINISH MZ_FINISH + #define Z_BLOCK MZ_BLOCK + #define Z_OK MZ_OK + #define Z_STREAM_END MZ_STREAM_END + #define Z_NEED_DICT MZ_NEED_DICT + #define Z_ERRNO MZ_ERRNO + #define Z_STREAM_ERROR MZ_STREAM_ERROR + #define Z_DATA_ERROR MZ_DATA_ERROR + #define Z_MEM_ERROR MZ_MEM_ERROR + #define Z_BUF_ERROR MZ_BUF_ERROR + #define Z_VERSION_ERROR MZ_VERSION_ERROR + #define Z_PARAM_ERROR MZ_PARAM_ERROR + #define Z_NO_COMPRESSION MZ_NO_COMPRESSION + #define Z_BEST_SPEED MZ_BEST_SPEED + #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION + #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION + #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY + #define Z_FILTERED MZ_FILTERED + #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY + #define Z_RLE MZ_RLE + #define Z_FIXED MZ_FIXED + #define Z_DEFLATED MZ_DEFLATED + #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS + #define alloc_func mz_alloc_func + #define free_func mz_free_func + #define internal_state mz_internal_state + #define z_stream mz_stream + #define deflateInit mz_deflateInit + #define deflateInit2 mz_deflateInit2 + #define deflateReset mz_deflateReset + #define deflate mz_deflate + #define deflateEnd mz_deflateEnd + #define deflateBound mz_deflateBound + #define compress mz_compress + #define compress2 mz_compress2 + #define compressBound mz_compressBound + #define inflateInit mz_inflateInit + #define inflateInit2 mz_inflateInit2 + #define inflate mz_inflate + #define inflateEnd mz_inflateEnd + #define uncompress mz_uncompress + #define z_crc32 mz_crc32 + #define z_adler32 mz_adler32 + #define MAX_WBITS 15 + #define MAX_MEM_LEVEL 9 + #define zError mz_error + #define ZLIB_VERSION MZ_VERSION + #define ZLIB_VERNUM MZ_VERNUM + #define ZLIB_VER_MAJOR MZ_VER_MAJOR + #define ZLIB_VER_MINOR MZ_VER_MINOR + #define ZLIB_VER_REVISION MZ_VER_REVISION + #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION + #define zlibVersion mz_version + #define zlib_version mz_version() +#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Types and macros + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef long long mz_int64; +typedef unsigned long long mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +#ifndef __WIN__ +#define MZ_MACRO_END while (0) +#else +// Works around MSVC's spammy "warning C4127: conditional expression is constant" message. +#define MZ_MACRO_END while (0, 0) +#endif + +// ------------------- Low-level Decompression API Definitions + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +// High level decompression functions: +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. +// On return: +// Function returns a pointer to the decompressed data, or NULL on failure. +// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. +// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. +// Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum +{ + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 +#define tinfl_get_crc32(r) (r)->m_check_crc32 + +// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum +{ + TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS + #define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF + typedef mz_uint64 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (64) +#else + typedef mz_uint32 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_z_crc32, m_final, m_type, m_check_adler32, m_check_crc32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +// ------------------- Low-level Compression API Definitions + +// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). +#define TDEFL_LESS_MEMORY 0 + +// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): +// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). +enum +{ + TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. +// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). +// TDEFL_COMPUTE_CRC32: Always compute the crc-32 of the input data. +// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. +// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). +// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) +// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. +// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. +// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. +enum +{ + TDEFL_WRITE_ZLIB_HEADER = 0x001000, + TDEFL_COMPUTE_ADLER32 = 0x002000, + TDEFL_COMPUTE_CRC32 = 0x004000, + TDEFL_GREEDY_PARSING_FLAG = 0x008000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x010000, + TDEFL_RLE_MATCHES = 0x020000, + TDEFL_FILTER_MATCHES = 0x040000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x080000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x100000, +}; + +// High level compression functions: +// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of source block to compress. +// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. +// Returns 0 on failure. +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// Compresses an image to a compressed PNG file in memory. +// On entry: +// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pLen_out will be set to the size of the PNG image file. +// The caller must free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); + +// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); + +// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; + +// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). +#if TDEFL_LESS_MEMORY +enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#else +enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +#endif + +// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. +typedef enum +{ + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1, +} tdefl_status; + +// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums +typedef enum +{ + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +// tdefl's compression state structure. +typedef struct +{ + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_crc32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +// Initializes the compressor. +// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. +// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. +// If pBut_buf_func is NULL the user should always call the tdefl_compress() API. +// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); + +// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. +// tdefl_compress_buffer() always consumes the entire input buffer. +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); +mz_uint32 tdefl_get_crc32(tdefl_compressor *d); + +// Create tdefl_compress() flags given zlib-style compression parameters. +// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) +// window_bits may be -15 (raw deflate) or 15 (zlib) +// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); + +#endif // MINIZ_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef MINIZ_HEADER_FILE_ONLY + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC + #define MZ_MALLOC(x) NULL + #define MZ_FREE(x) x, ((void)0) + #define MZ_REALLOC(p, x) NULL +#else + #define MZ_MALLOC(x) grub_malloc(x) + #define MZ_FREE(x) grub_free(x) + #define MZ_REALLOC(p, x) grub_realloc(p, x) +#endif + +#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) +#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) + #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else + #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) + #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__MINGW64__) && !defined(__forceinline) + #define __forceinline +#endif + +// ------------------- zlib-style API's + +static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque; return MZ_MALLOC(items * size); } +static void def_free_func(void *opaque, void *address) { (void)opaque, MZ_FREE(address); } + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) +{ + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; + if (!ptr) return MZ_ADLER32_INIT; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + return (s2 << 16) + s1; +} + +// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) +{ + static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; + if (!ptr) return MZ_CRC32_INIT; + crc = ~crc; while (buf_len--) { mz_uint8 b = *ptr++; crc = (crc >> 4) ^ s_crc32[(crc & 0xF) ^ (b & 0xF)]; crc = (crc >> 4) ^ s_crc32[(crc & 0xF) ^ (b >> 4)]; } return ~crc; +} + +#ifndef MINIZ_NO_ZLIB_APIS + +const char *mz_version(void) +{ + return MZ_VERSION; +} + +int mz_deflateInit(mz_streamp pStream, int level) +{ + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) +{ + tdefl_compressor *pComp; + mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | TDEFL_COMPUTE_CRC32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->crc32 = MZ_CRC32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) + return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) + { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) +{ + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) +{ + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; + if (!pStream->avail_out) return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; + for ( ; ; ) + { + tdefl_status defl_status; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); pStream->crc32 = tdefl_get_crc32((tdefl_compressor*)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) + { + mz_status = MZ_STREAM_ERROR; + break; + } + else if (defl_status == TDEFL_STATUS_DONE) + { + mz_status = MZ_STREAM_END; + break; + } + else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) + { + if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) +{ + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) +{ + (void)pStream; + // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) +{ + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) +{ + return mz_deflateBound(NULL, source_len); +} + +typedef struct +{ + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) +{ + inflate_state *pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->crc32 = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) +{ + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) +{ + inflate_state* pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + + pState = (inflate_state*)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) + { + // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->crc32 = tinfl_get_crc32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) + { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) + { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + } + + for ( ; ; ) + { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pStream->crc32 = tinfl_get_crc32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; + pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. + else if (flush == MZ_FINISH) + { + // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } + else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) +{ + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) + { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) +{ + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) + return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) + { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +const char *mz_error(int err) +{ + static struct { int m_err; const char *m_pDesc; } s_error_descs[] = + { + { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, + { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } + }; + mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif //MINIZ_NO_ZLIB_APIS + +// ------------------- Low-level Decompression (completely independent from all compression API's) + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN switch(r->m_state) { case 0: +#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for ( ; ; ) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else c = *pIn_buf_cur++; } MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a +// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ + } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read +// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully +// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ + int temp; mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ + } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END + +#if defined(__aarch64__) || defined(__arm__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmisleading-indentation" +#endif + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; + static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } + + num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pIn_buf_cur >= pIn_buf_end) + { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) + { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } + else + { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; + r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } + r->m_table_sizes[2] = 19; + } + for ( ; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; + cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) + { + mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for ( ; ; ) + { + mz_uint8 *pSrc; + for ( ; ; ) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } +#else + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + counter = sym2; bit_buf >>= code_len; num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + bit_buf >>= code_len; num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +#if defined(__aarch64__) || defined(__arm__) +#pragma GCC diagnostic pop +#endif + +// Higher level helper functions. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +// ------------------- Low-level Compression (independent from all decompression API's) + +// Purposely making these tables static for faster init and thread safety. +static const mz_uint16 s_tdefl_len_sym[256] = { + 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, + 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, + 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, + 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, + 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, + 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, + 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, + 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; + +static const mz_uint8 s_tdefl_len_extra[256] = { + 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = { + 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = { + 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7 }; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = { + 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, + 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = { + 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; + +// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. +typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; +static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) +{ + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) + { + const mz_uint32* pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } + for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; + { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } + } + return pCur_syms; +} + +// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) +{ + int root, leaf, next, avbl, used, dpth; + if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } + A[0].m_key += A[1].m_key; root = 0; leaf = 2; + for (next=1; next < n-1; next++) + { + if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; + avbl = 1; used = dpth = 0; root = n-2; next = n-1; + while (avbl>0) + { + while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } + while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } + avbl = 2*used; dpth++; used = 0; + } +} + +// Limits canonical Huffman code table's max code size. +enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) +{ + int i; mz_uint32 total = 0; if (code_list_len <= 1) return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) + { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) +{ + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); + if (static_table) + { + for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; + } + else + { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) + { + mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; + code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) do { \ + mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ + while (d->m_bits_in >= 8) { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ +} MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ + if (rle_repeat_count < 3) { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } else { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ +} rle_repeat_count = 0; } } + +#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ + if (rle_z_count < 3) { \ + d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ + } else if (rle_z_count <= 10) { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ + } else { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ +} rle_z_count = 0; } } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) +{ + int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; + mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) + { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } + } + else + { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) + { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; + } + else if (++rle_repeat_count == 6) + { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) + { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) +{ + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) *p++ = 8; + for ( ; i <= 255; ++i) *p++ = 9; + for ( ; i <= 279; ++i) *p++ = 7; + for ( ; i <= 287; ++i) *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + + if (flags & 1) + { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) + { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) + return MZ_FALSE; + + *(mz_uint64*)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) + { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) +{ + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) + { + if (flags == 1) + flags = *pLZ_codes++ | 0x100; + if (flags & 1) + { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + + if (match_dist < 512) + { + sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } + else + { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } + else + { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) +{ + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) +{ + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) + { + TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + + // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. + if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) + { + mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) + { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) + { + TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) + { + d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) + { + if (flush == TDEFL_FINISH) + { + if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } + } + else + { + mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) + { + if (d->m_pPut_buf_func) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } + else if (pOutput_buf_start == d->m_output_buf) + { + int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) + { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } + else + { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" + +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) +static __forceinline void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) + +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + if (!probe_len) + { + *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; + } + else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} + +#pragma GCC diagnostic pop + +#else + +#if defined(__aarch64__) || defined(__arm__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmisleading-indentation" +#endif + +static __forceinline void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) +{ + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; + for ( ; ; ) + { + for ( ; ; ) + { + if (--num_probes_left == 0) return; + #define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; + TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + } + if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; + if (probe_len > match_len) + { + *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; + c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; + } + } +} + +#if defined(__aarch64__) || defined(__arm__) +#pragma GCC diagnostic pop +#endif + +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +static mz_bool tdefl_compress_fast(tdefl_compressor *d) +{ + // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) + { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) + { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; + + while (lookahead_size >= 4) + { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) + { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) + { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + else + { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + } + } + else + { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) + { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) + { + int n; + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#pragma GCC diagnostic pop +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + +static __forceinline void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) +{ + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + d->m_huff_count[0][lit]++; +} + +static __forceinline void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) +{ + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) +{ + const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) + { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) + { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) + { + mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; + } + } + else + { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) + { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) + break; + + // Simple lazy/greedy parsing state machine. + len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) + { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) + { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; + } + } + else + { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) + { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) + { + if (cur_match_len > d->m_saved_match_len) + { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + } + else + { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; + } + } + else if (!cur_match_dist) + tdefl_record_literal(d, d->m_dict[cur_pos]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) + { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } + else + { + d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output buffer. + if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) + { + int n; + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) +{ + if (d->m_pIn_buf_size) + { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) + { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) +{ + if (!d) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) + { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) + { + if (!tdefl_compress_fast(d)) + return d->m_prev_return_status; + } + else +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + { + if (!tdefl_compress_normal(d)) + return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) + d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if (d->m_flags & TDEFL_COMPUTE_CRC32) + d->m_crc32 = (mz_uint32)mz_crc32(d->m_crc32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) + { + if (tdefl_flush_block(d, flush) < 0) + return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) +{ + MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; d->m_crc32 = 1; + d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) +{ + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) +{ + return d->m_adler32; +} + +mz_uint32 tdefl_get_crc32(tdefl_compressor *d) +{ + return d->m_crc32; +} + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; + pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); + succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); + MZ_FREE(pComp); return succeeded; +} + +typedef struct +{ + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) +{ + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) + { + size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; + do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); + pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; + p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; + } + memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; + *pOut_len = out_buf.m_size; return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) return 0; + out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; + return out_buf.m_size; +} + +static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; + +// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) +{ + mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) +#endif + +// Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at +// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) +{ + tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; + if (!pComp) return NULL; + MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } + // write dummy header + for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); + // compress image data + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, TDEFL_DEFAULT_MAX_PROBES | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + y * bpl, bpl, TDEFL_NO_FLUSH); } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } + // write real header + *pLen_out = out_buf.m_size-41; + { + mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, + 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,"\0\0\04\02\06"[num_chans],0,0,0,0,0,0,0, + (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54}; + c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + // write footer (IDAT CRC-32, followed by IEND chunk) + if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24); + // compute final size of file, grab compressed data buffer and return + *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; +} + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +#pragma GCC diagnostic pop + +#endif // MINIZ_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/miniz.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/miniz.h new file mode 100644 index 0000000..c27ecc6 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/miniz.h @@ -0,0 +1,2 @@ +#define MINIZ_HEADER_FILE_ONLY +#include "miniz.c" diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c new file mode 100644 index 0000000..2e1cc3c --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy.c @@ -0,0 +1,693 @@ +/****************************************************************************** + * ventoy.c + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GRUB_MACHINE_EFI +#include +#include +#endif +#include +#include "ventoy_def.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +int g_ventoy_debug = 0; +static int g_efi_os = 0xFF; +grub_uint32_t g_ventoy_plat_data; + +static grub_uint8_t g_timeout_lock = 0; +static grub_uint8_t g_theme_lock = 0; +static char *g_lock_theme = NULL; + +#ifdef GRUB_MACHINE_EFI +static VTOY_SHIM *g_vtoy_shim = NULL; +#endif + +void ventoy_debug(const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + grub_vprintf (fmt, args); + va_end (args); +} + +void ventoy_str_tolower(char *str) +{ + while (*str) + { + *str = grub_tolower(*str); + str++; + } +} + +void ventoy_str_toupper(char *str) +{ + while (*str) + { + *str = grub_toupper(*str); + str++; + } +} + +char *ventoy_str_last(char *str, char ch) +{ + char *pos = NULL; + char *last = NULL; + + if (!str) + { + return NULL; + } + + for (pos = str; *pos; pos++) + { + if (*pos == ch) + { + last = pos; + } + } + + return last; +} + +int ventoy_str_all_digit(const char *str) +{ + if (NULL == str || 0 == *str) + { + return 0; + } + + while (*str) + { + if (*str < '0' || *str > '9') + { + return 0; + } + } + + return 1; +} + +int ventoy_str_all_alnum(const char *str) +{ + if (NULL == str || 0 == *str) + { + return 0; + } + + while (*str) + { + if (!grub_isalnum(*str)) + { + return 0; + } + } + + return 1; +} + +int ventoy_str_len_alnum(const char *str, int len) +{ + int i; + int slen; + + if (NULL == str || 0 == *str) + { + return 0; + } + + slen = grub_strlen(str); + if (slen <= len) + { + return 0; + } + + for (i = 0; i < len; i++) + { + if (!grub_isalnum(str[i])) + { + return 0; + } + } + + if (str[len] == 0 || grub_isspace(str[len])) + { + return 1; + } + + return 0; +} + +char * ventoy_str_basename(char *path) +{ + char *pos = NULL; + + pos = grub_strrchr(path, '/'); + if (pos) + { + pos++; + } + else + { + pos = path; + } + + return pos; +} + +int ventoy_str_chrcnt(const char *str, char c) +{ + int n = 0; + + if (str) + { + while (*str) + { + if (*str == c) + { + n++; + } + str++; + } + } + + return n; +} + +int ventoy_strcmp(const char *pattern, const char *str) +{ + while (*pattern && *str) + { + if ((*pattern != *str) && (*pattern != '*')) + break; + + pattern++; + str++; + } + + return (int)(grub_uint8_t)*pattern - (int)(grub_uint8_t)*str; +} + +int ventoy_strncmp (const char *pattern, const char *str, grub_size_t n) +{ + if (n == 0) + return 0; + + while (*pattern && *str && --n) + { + if ((*pattern != *str) && (*pattern != '*')) + break; + + pattern++; + str++; + } + + return (int)(grub_uint8_t)*pattern - (int)(grub_uint8_t)*str; +} + +void ventoy_timeout_lock(int lock) +{ + g_timeout_lock = lock ? 1 : 0; +} + +void ventoy_theme_lock(int lock) +{ + const char *env = NULL; + + g_theme_lock = 0; + grub_check_free(g_lock_theme); + + if (lock) + { + env = grub_env_get("theme"); + if (env) + { + g_lock_theme = grub_strdup(env); + g_theme_lock = 1; + } + } +} + +grub_err_t ventoy_env_int_set(const char *name, int value) +{ + char buf[16]; + + grub_snprintf(buf, sizeof(buf), "%d", value); + return grub_env_set(name, buf); +} + +void ventoy_debug_dump_guid(const char *prefix, grub_uint8_t *guid) +{ + int i; + + if (!g_ventoy_debug) + { + return; + } + + debug("%s", prefix); + for (i = 0; i < 16; i++) + { + grub_printf("%02x ", guid[i]); + } + grub_printf("\n"); +} + +int ventoy_is_efi_os(void) +{ + if (g_efi_os > 1) + { + g_efi_os = (grub_strstr(GRUB_PLATFORM, "efi")) ? 1 : 0; + } + + return g_efi_os; +} + +void * ventoy_alloc_chain(grub_size_t size) +{ + void *p = NULL; + + p = grub_malloc(size); +#ifdef GRUB_MACHINE_EFI + if (!p) + { + p = grub_efi_allocate_any_pages(GRUB_EFI_BYTES_TO_PAGES(size)); + } +#endif + + return p; +} + +void ventoy_memfile_env_set(const char *prefix, const void *buf, unsigned long long len) +{ + char name[128]; + char val[64]; + + grub_snprintf(name, sizeof(name), "%s_addr", prefix); + grub_snprintf(val, sizeof(val), "0x%llx", (ulonglong)(ulong)buf); + grub_env_set(name, val); + + grub_snprintf(name, sizeof(name), "%s_size", prefix); + grub_snprintf(val, sizeof(val), "%llu", len); + grub_env_set(name, val); + + return; +} + +#ifdef GRUB_MACHINE_EFI +static void ventoy_get_uefi_version(char *str, grub_size_t len) +{ + grub_efi_uint8_t uefi_minor_1, uefi_minor_2; + + uefi_minor_1 = (grub_efi_system_table->hdr.revision & 0xffff) / 10; + uefi_minor_2 = (grub_efi_system_table->hdr.revision & 0xffff) % 10; + grub_snprintf(str, len, "%d.%d", (grub_efi_system_table->hdr.revision >> 16), uefi_minor_1); + if (uefi_minor_2) + grub_snprintf(str, len, "%s.%d", str, uefi_minor_2); +} + +static void ventoy_get_pi_version(char *str, grub_size_t len) +{ + grub_uint32_t data = 0; + grub_efi_uintn_t i = 0; + grub_efi_guid_t dxest = + { 0x05ad34ba, 0x6f02, 0x4214, {0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9 } }; + + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) + { + if (grub_memcmp(&dxest, &grub_efi_system_table->configuration_table[i].vendor_guid, 16) == 0) + { + grub_memcpy(&data, (char *)grub_efi_system_table->configuration_table[i].vendor_table + 8, 4); + break; + } + } + + grub_snprintf(str, len, "%d.%d", (data >> 16) & 0xFFFF, (data & 0xFFFF) / 10); +} + +int ventoy_set_sb_policy(void) +{ + const char *env = NULL; + static int set_once = 0; + + /* no need when SecureBoot is disabled */ + if (g_sys_sb == 0) + { + return 0; + } + + /* can only set once */ + if (set_once > 0) + { + return 0; + } + set_once = 1; + + /* VTOY_SECURE_BOOT_POLICY only take affect once during init */ + env = grub_env_get("VTOY_SECURE_BOOT_POLICY"); + if (env) + { + g_sb_policy = (grub_uint8_t)(env[0] - '0'); + } + + if (g_sb_policy == VTOY_SB_POLICY_BYPASS) + { + if (g_vtoy_shim && g_vtoy_shim->ByPassSB) + { + g_vtoy_shim->ByPassSB(); + } + } + else if (g_sb_policy == VTOY_SB_POLICY_CHECK) + { + if (g_vtoy_shim && g_vtoy_shim->CheckSB) + { + g_vtoy_shim->CheckSB(); + } + } + + return 0; +} + +static void ventoy_get_uefi_sb(void) +{ + grub_uint8_t secure_boot = 0; + grub_uint8_t setup_mode = 0; + grub_uint8_t *var = NULL; + grub_size_t size = 0; + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; + + var = grub_efi_get_variable("SecureBoot", &global, &size); + if (var && size == 1 && *var == 1) + { + secure_boot = 1; + } + grub_check_free(var); + + size = 0; + var = grub_efi_get_variable("SetupMode", &global, &size); + if (var && size == 1 && *var == 1) + { + setup_mode = 1; + } + + if (secure_boot == 1 && setup_mode == 0) + { + g_sys_sb = 1; + } + + grub_check_free(var); +} + +static int ventoy_secure_boot_init(void) +{ + grub_efi_guid_t ProtGuid = VTOY_SHIM_POLICY_GUID; + + ventoy_get_uefi_sb(); + + if (g_sys_sb == 0) + { + return 0; + } + + + if (g_ventoy_plat_data == VTOY_PLAT_X86_64_UEFI) + { + g_vtoy_shim = grub_efi_locate_protocol(&ProtGuid, NULL); + if (g_vtoy_shim == NULL || g_vtoy_shim->ByPassSB == NULL || + g_vtoy_shim->CheckSB == NULL || g_vtoy_shim->Launched == NULL) + { + /* + * Generally when SecureBoot enabled, Ventoy grub must be launched by Ventoy Shim. + * But there are some exceptions: + * 1. Ventoy key was enrolled directly to the UEFI DB + * 2. Some UEFI firmware (MSI) has Image Execution Policy as Always Execute which + * means Secure Boot is effectively disabled. + */ + } + else + { + g_vtoy_shim->Launched(); + } + } + + return 0; +} + + +#endif + +static int ventoy_arch_mode_init(void) +{ + #ifdef GRUB_MACHINE_EFI + + if (grub_strcmp(GRUB_TARGET_CPU, "i386") == 0) + { + g_ventoy_plat_data = VTOY_PLAT_I386_UEFI; + grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "ia32"); + } + else if (grub_strcmp(GRUB_TARGET_CPU, "arm64") == 0) + { + g_ventoy_plat_data = VTOY_PLAT_ARM64_UEFI; + grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "aa64"); + } + else if (grub_strcmp(GRUB_TARGET_CPU, "mips64el") == 0) + { + g_ventoy_plat_data = VTOY_PLAT_MIPS_UEFI; + grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "mips"); + } + else + { + g_ventoy_plat_data = VTOY_PLAT_X86_64_UEFI; + grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "uefi"); + } +#else + g_ventoy_plat_data = VTOY_PLAT_X86_LEGACY; + grub_snprintf(g_arch_mode_suffix, sizeof(g_arch_mode_suffix), "%s", "legacy"); +#endif + + return 0; +} + +static int ventoy_calc_totalmem(grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type, void *data) +{ + grub_uint64_t *total_mem = (grub_uint64_t *)data; + + (void)addr; + (void)type; + + *total_mem += size; + + return 0; +} + +static int ventoy_hwinfo_init(void) +{ + char str[256]; + grub_uint64_t total_mem = 0; + + grub_machine_mmap_iterate(ventoy_calc_totalmem, &total_mem); + + grub_snprintf(str, sizeof(str), "%ld", (long)(total_mem / VTOY_SIZE_1MB)); + ventoy_env_export("grub_total_ram", str); + +#ifdef GRUB_MACHINE_EFI + ventoy_get_uefi_version(str, sizeof(str)); + ventoy_env_export("grub_uefi_version", str); + + ventoy_get_pi_version(str, sizeof(str)); + ventoy_env_export("grub_pi_version", str); +#else + ventoy_env_export("grub_uefi_version", "NA"); + ventoy_env_export("grub_pi_version", "NA"); +#endif + + return 0; +} + +static global_var_cfg g_global_vars[] = +{ + { "gfxmode", "1024x768", NULL }, + { ventoy_left_key, "5%", NULL }, + { ventoy_top_key, "95%", NULL }, + { ventoy_color_key, "#0000ff", NULL }, + { NULL, NULL, NULL } +}; + +static const char * ventoy_global_var_read_hook(struct grub_env_var *var, const char *val) +{ + int i; + + for (i = 0; g_global_vars[i].name; i++) + { + if (grub_strcmp(g_global_vars[i].name, var->name) == 0) + { + return g_global_vars[i].value; + } + } + + return val; +} + +static char * ventoy_global_var_write_hook(struct grub_env_var *var, const char *val) +{ + int i; + + for (i = 0; g_global_vars[i].name; i++) + { + if (grub_strcmp(g_global_vars[i].name, var->name) == 0) + { + grub_check_free(g_global_vars[i].value); + g_global_vars[i].value = grub_strdup(val); + break; + } + } + + return grub_strdup(val); +} + +static char * ventoy_timeout_write_hook(struct grub_env_var *var, const char *val) +{ + (void)var; + return grub_strdup(g_timeout_lock ? "-1" : val); +} + +static char * ventoy_theme_write_hook(struct grub_env_var *var, const char *val) +{ + (void)var; + return grub_strdup(g_theme_lock ? g_lock_theme : val); +} + + +int ventoy_global_var_init(void) +{ + int i; + + for (i = 0; g_global_vars[i].name; i++) + { + g_global_vars[i].value = grub_strdup(g_global_vars[i].defval); + ventoy_env_export(g_global_vars[i].name, g_global_vars[i].defval); + grub_register_variable_hook(g_global_vars[i].name, ventoy_global_var_read_hook, ventoy_global_var_write_hook); + } + + grub_register_variable_hook("timeout", NULL, ventoy_timeout_write_hook); + grub_register_variable_hook("theme", NULL, ventoy_theme_write_hook); + + return 0; +} + +static ctrl_var_cfg g_ctrl_vars[] = +{ + { "VTOY_WIN11_BYPASS_CHECK", "1" }, + { "VTOY_WIN11_BYPASS_NRO", "1" }, + { "VTOY_LINUX_REMOUNT", "0" }, + { "VTOY_SECONDARY_BOOT_MENU", "1" }, + { "VTOY_WIN_UEFI_RES_LOCK", "3" }, + { NULL, "" } +}; + +static const char * ventoy_ctrl_var_read_hook(struct grub_env_var *var, const char *val) +{ + int i; + + for (i = 0; g_ctrl_vars[i].name; i++) + { + if (grub_strcmp(g_ctrl_vars[i].name, var->name) == 0) + { + return g_ctrl_vars[i].szval; + } + } + + return val; +} + +static char * ventoy_ctrl_var_write_hook(struct grub_env_var *var, const char *val) +{ + int i; + + for (i = 0; g_ctrl_vars[i].name; i++) + { + if (grub_strcmp(g_ctrl_vars[i].name, var->name) == 0) + { + if (val && grub_isdigit(val[0]) && val[1] == 0) + { + g_ctrl_vars[i].szval[0] = val[0]; + return grub_strdup(val); + } + else + { + g_ctrl_vars[i].szval[0] = '0'; + return grub_strdup("0"); + } + } + } + + return grub_strdup(val); +} + +int ventoy_ctrl_var_init(void) +{ + ctrl_var_cfg *cfg = g_ctrl_vars; + + while (cfg->name) + { + ventoy_env_export(cfg->name, cfg->szval); + grub_register_variable_hook(cfg->name, ventoy_ctrl_var_read_hook, ventoy_ctrl_var_write_hook); + cfg++; + } + + return 0; +} + +GRUB_MOD_INIT(ventoy) +{ + ventoy_hwinfo_init(); + ventoy_env_init(); + ventoy_arch_mode_init(); + +#ifdef GRUB_MACHINE_EFI + ventoy_secure_boot_init(); +#endif + + ventoy_register_all_cmd(); +} + +GRUB_MOD_FINI(ventoy) +{ + ventoy_unregister_all_cmd(); +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_browser.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_browser.c new file mode 100644 index 0000000..ca6b0bf --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_browser.c @@ -0,0 +1,652 @@ +/****************************************************************************** + * ventoy_browser.c + * + * Copyright (c) 2022, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ventoy_def.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define BROWSER_MENU_BUF 65536 + +static const char *g_vtoy_dev = NULL; +static grub_fs_t g_menu_fs = NULL; +static char *g_menu_device = NULL; +static grub_device_t g_menu_dev = NULL; +static char g_menu_path_buf[1024]; +static int g_menu_path_len = 0; +static browser_node *g_browser_list = NULL; + +static int ventoy_browser_strcmp(char *str1, char *str2) +{ + char *s1, *s2; + int c1 = 0; + int c2 = 0; + + for (s1 = str1, s2 = str2; *s1 && *s2; s1++, s2++) + { + c1 = *s1; + c2 = *s2; + + if (0 == g_sort_case_sensitive) + { + if (grub_islower(c1)) + { + c1 = c1 - 'a' + 'A'; + } + + if (grub_islower(c2)) + { + c2 = c2 - 'a' + 'A'; + } + } + + if (c1 != c2) + { + break; + } + } + + return (c1 - c2); +} + +static int ventoy_browser_mbuf_alloc(browser_mbuf *mbuf) +{ + grub_memset(mbuf, 0, sizeof(browser_mbuf)); + mbuf->buf = grub_malloc(BROWSER_MENU_BUF); + if (!mbuf->buf) + { + return 0; + } + + mbuf->pos = 0; + mbuf->max = BROWSER_MENU_BUF; + return 1; +} + +static inline void ventoy_browser_mbuf_free(browser_mbuf *mbuf) +{ + if (mbuf) + grub_check_free(mbuf->buf) +} + +static inline int ventoy_browser_mbuf_extend(browser_mbuf *mbuf) +{ + if (mbuf->max - mbuf->pos <= VTOY_SIZE_1KB) + { + mbuf->max += BROWSER_MENU_BUF; + mbuf->buf = grub_realloc(mbuf->buf, mbuf->max); + } + + return 0; +} + +static browser_node * ventoy_browser_find_top_node(int dir) +{ + browser_node *node = NULL; + browser_node *sel = NULL; + + for (node = g_browser_list; node; node = node->next) + { + if (node->dir == dir) + { + if (sel) + { + if (ventoy_browser_strcmp(sel->filename, node->filename) > 0) + { + sel = node; + } + } + else + { + sel = node; + } + } + } + + return sel; +} + +static int ventoy_browser_iterate_partition(struct grub_disk *disk, const grub_partition_t partition, void *data) +{ + char partname[64]; + char title[256]; + grub_device_t dev; + grub_fs_t fs; + char *Label = NULL; + browser_mbuf *mbuf = (browser_mbuf *)data; + + (void)data; + + if (partition->number == 1 && g_vtoy_dev && grub_strcmp(disk->name, g_vtoy_dev) == 0) + { + return 0; + } + + grub_snprintf(partname, sizeof(partname) - 1, "%s,%d", disk->name, partition->number + 1); + + dev = grub_device_open(partname); + if (!dev) + { + return 0; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + grub_device_close(dev); + return 0; + } + + fs->fs_label(dev, &Label); + + if (ventoy_check_file_exist("(%s)/.ventoyignore", partname)) + { + return 0; + } + + if (g_tree_view_menu_style == 0) + { + grub_snprintf(title, sizeof(title), "%-10s (%s,%s%d) [%s] %s %s", + "DISK", disk->name, partition->msdostype == 0xee ? "gpt" : "msdos", + partition->number + 1, (Label ? Label : ""), fs->name, + grub_get_human_size(partition->len << disk->log_sector_size, GRUB_HUMAN_SIZE_SHORT)); + } + else + { + grub_snprintf(title, sizeof(title), "(%s,%s%d) [%s] %s %s", + disk->name, partition->msdostype == 0xee ? "gpt" : "msdos", + partition->number + 1, (Label ? Label : ""), fs->name, + grub_get_human_size(partition->len << disk->log_sector_size, GRUB_HUMAN_SIZE_SHORT)); + } + + if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max) + { + browser_ssprintf(mbuf, "menuentry \"%s\" --class=vtoydisk {\n" + " echo \"unsupported file system type!\" \n" + " ventoy_pause\n" + "}\n", + title); + } + else + { + browser_ssprintf(mbuf, "menuentry \"%s\" --class=vtoydisk {\n" + " vt_browser_dir %s,%d 0x%lx /\n" + "}\n", + title, disk->name, partition->number + 1, (ulong)fs); + } + + ventoy_browser_mbuf_extend(mbuf); + + return 0; +} + +static int ventoy_browser_iterate_disk(const char *name, void *data) +{ + grub_disk_t disk; + + if (name[0] != 'h') + { + return 0; + } + + disk = grub_disk_open(name); + if (disk) + { + grub_partition_iterate(disk, ventoy_browser_iterate_partition, data); + grub_disk_close(disk); + } + + return 0; +} + +static int ventoy_browser_valid_dirname(const char *name, int len) +{ + if ((len == 1 && name[0] == '.') || + (len == 2 && name[0] == '.' && name[1] == '.')) + { + return 0; + } + + if (!ventoy_img_name_valid(name, len)) + { + return 0; + } + + if (g_filt_trash_dir) + { + if (0 == grub_strncmp(name, ".trash-", 7) || + 0 == grub_strcmp(name, ".Trashes")) + { + return 0; + } + } + + if (name[0] == '$') + { + if (0 == grub_strncmp(name, "$RECYCLE.BIN", 12) || + 0 == grub_strncasecmp(name, "$Extend", 7)) + { + return 0; + } + } + + if (len == 25 && grub_strncmp(name, "System Volume Information", 25) == 0) + { + return 0; + } + + return 1; +} + +static int ventoy_browser_valid_filename(const char *filename, int len, int *type) +{ + if (len < 4) + { + return 0; + } + + if (FILE_FLT(ISO) && 0 == grub_strcasecmp(filename + len - 4, ".iso")) + { + *type = img_type_iso; + } + else if (FILE_FLT(WIM) && g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim"))) + { + *type = img_type_wim; + } + else if (FILE_FLT(VHD) && g_vhdboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".vhd") || + (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vhdx")))) + { + *type = img_type_vhd; + } + #ifdef GRUB_MACHINE_EFI + else if (FILE_FLT(EFI) && 0 == grub_strcasecmp(filename + len - 4, ".efi")) + { + *type = img_type_efi; + } + #endif + else if (FILE_FLT(IMG) && 0 == grub_strcasecmp(filename + len - 4, ".img")) + { + if (len == 18 && grub_strncmp(filename, "ventoy_", 7) == 0) + { + if (grub_strncmp(filename + 7, "wimboot", 7) == 0 || + grub_strncmp(filename + 7, "vhdboot", 7) == 0) + { + return 0; + } + } + *type = img_type_img; + } + else if (FILE_FLT(VTOY) && len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vtoy")) + { + *type = img_type_vtoy; + } + else + { + return 0; + } + + if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_') + { + return 0; + } + + return 1; +} + +static int ventoy_browser_check_ignore(const char *device, const char *root, const char *dir) +{ + grub_file_t file; + char fullpath[1024] = {0}; + + grub_snprintf(fullpath, 1023, "(%s)%s/%s/.ventoyignore", device, root, dir); + file = grub_file_open(fullpath, GRUB_FILE_TYPE_NONE); + if (!file) + { + grub_errno = 0; + return 0; + } + else + { + grub_file_close(file); + return 1; + } +} + +static int ventoy_browser_iterate_dir(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + int type; + int len; + browser_node *node; + + (void)data; + + len = grub_strlen(filename); + + if (info->dir) + { + if (!ventoy_browser_valid_dirname(filename, len)) + { + return 0; + } + + if (ventoy_browser_check_ignore(g_menu_device, g_menu_path_buf, filename)) + { + return 0; + } + + node = grub_zalloc(sizeof(browser_node)); + if (!node) + { + return 0; + } + + node->dir = 1; + grub_strncpy(node->filename, filename, sizeof(node->filename)); + + if (g_tree_view_menu_style == 0) + { + grub_snprintf(node->menuentry, sizeof(node->menuentry), + "menuentry \"%-10s [%s]\" --class=vtoydir {\n" + " vt_browser_dir %s 0x%lx \"%s/%s\"\n" + "}\n", + "DIR", filename, g_menu_device, (ulong)g_menu_fs, g_menu_path_buf, filename); + } + else + { + grub_snprintf(node->menuentry, sizeof(node->menuentry), + "menuentry \"[%s]\" --class=vtoydir {\n" + " vt_browser_dir %s 0x%lx \"%s/%s\"\n" + "}\n", + filename, g_menu_device, (ulong)g_menu_fs, g_menu_path_buf, filename); + } + } + else + { + grub_uint64_t fsize = info->size; + + if (!ventoy_browser_valid_filename(filename, len, &type)) + { + return 0; + } + + if (grub_file_is_vlnk_suffix(filename, len)) + { + return 0; + } + + node = grub_zalloc(sizeof(browser_node)); + if (!node) + { + return 0; + } + + if (fsize == 0) + { + struct grub_file file; + + grub_memset(&file, 0, sizeof(file)); + file.device = g_menu_dev; + grub_snprintf(node->menuentry, sizeof(node->menuentry), "%s/%s", g_menu_path_buf, filename); + if (g_menu_fs->fs_open(&file, node->menuentry) == GRUB_ERR_NONE) + { + fsize = file.size; + g_menu_fs->fs_close(&file); + } + } + + node->dir = 0; + grub_strncpy(node->filename, filename, sizeof(node->filename)); + + if (g_tree_view_menu_style == 0) + { + grub_snprintf(node->menuentry, sizeof(node->menuentry), + "menuentry \"%-10s %s\" --class=%s {\n" + " vt_set_fake_vlnk \"(%s)%s/%s\" %s %llu\n" + " %s_common_menuentry\n" + " vt_reset_fake_vlnk\n" + "}\n", + grub_get_human_size(fsize, GRUB_HUMAN_SIZE_SHORT), filename, g_menu_class[type], + g_menu_device, g_menu_path_buf, filename, g_menu_prefix[type], (ulonglong)fsize, + g_menu_prefix[type]); + } + else + { + grub_snprintf(node->menuentry, sizeof(node->menuentry), + "menuentry \"%s\" --class=%s {\n" + " vt_set_fake_vlnk \"(%s)%s/%s\" %s %llu\n" + " %s_common_menuentry\n" + " vt_reset_fake_vlnk\n" + "}\n", + filename, g_menu_class[type], + g_menu_device, g_menu_path_buf, filename, g_menu_prefix[type], (ulonglong)fsize, + g_menu_prefix[type]); + } + } + + node->prev = NULL; + node->next = g_browser_list; + if (g_browser_list) + { + g_browser_list->prev = node; + } + g_browser_list = node; + + return 0; +} + +static grub_err_t ventoy_browser_iso_part(void) +{ + char cfgfile[64]; + char *buffer = NULL; + int pos = 0; + int buflen = 0; + int cfglen = 0; + + cfglen = g_tree_script_pos - g_tree_script_pre; + buflen = cfglen + 512; + buffer = grub_malloc(buflen); + if (!buffer) + { + return 1; + } + + if (g_tree_view_menu_style == 0) + { + pos = grub_snprintf(buffer, buflen, "menuentry \"%-10s [../]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n}\n", "<--"); + } + else + { + pos = grub_snprintf(buffer, buflen, "menuentry \"[../]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n}\n"); + } + + grub_memcpy(buffer + pos, g_tree_script_buf + g_tree_script_pre, cfglen); + pos += cfglen; + + grub_snprintf(cfgfile, sizeof(cfgfile), "configfile mem:0x%lx:size:%d", (ulong)buffer, pos); + grub_script_execute_sourcecode(cfgfile); + + grub_free(buffer); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_browser_dir(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + grub_fs_t fs; + grub_device_t dev; + char cfgfile[64]; + browser_node *node; + browser_mbuf mbuf; + + (void)ctxt; + (void)argc; + + if (args[2][0] == '/' && args[2][1] == 0) + { + grub_snprintf(cfgfile, sizeof(cfgfile), "(%s)", args[0]); + if (grub_strcmp(cfgfile, g_iso_path) == 0) + { + return ventoy_browser_iso_part(); + } + } + + if (!ventoy_browser_mbuf_alloc(&mbuf)) + { + return 1; + } + + fs = (grub_fs_t)grub_strtoul(args[1], NULL, 16); + if (!fs) + { + debug("Invalid fs %s\n", args[1]); + return 1; + } + + dev = grub_device_open(args[0]); + if (!dev) + { + debug("Failed to open device %s\n", args[0]); + return 1; + } + + g_menu_fs = fs; + g_menu_device = args[0]; + g_menu_dev = dev; + g_browser_list = NULL; + + if (args[2][0] == '/' && args[2][1] == 0) + { + g_menu_path_len = 0; + g_menu_path_buf[0] = 0; + fs->fs_dir(dev, "/", ventoy_browser_iterate_dir, NULL); + } + else + { + g_menu_path_len = grub_snprintf(g_menu_path_buf, sizeof(g_menu_path_buf), "%s", args[2]); + fs->fs_dir(dev, g_menu_path_buf, ventoy_browser_iterate_dir, NULL); + } + grub_device_close(dev); + + if (g_tree_view_menu_style == 0) + { + browser_ssprintf(&mbuf, "menuentry \"%-10s [(%s)%s/..]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n}\n", "<--", args[0], g_menu_path_buf); + } + else + { + browser_ssprintf(&mbuf, "menuentry \"[(%s)%s/..]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n}\n", args[0], g_menu_path_buf); + } + + for (i = 1; i >= 0; i--) + { + while (1) + { + node = ventoy_browser_find_top_node(i); + if (node) + { + browser_ssprintf(&mbuf, "%s", node->menuentry); + ventoy_browser_mbuf_extend(&mbuf); + + if (node->prev) + { + node->prev->next = node->next; + } + if (node->next) + { + node->next->prev = node->prev; + } + + if (node == g_browser_list) + { + g_browser_list = node->next; + } + grub_free(node); + } + else + { + break; + } + } + } + g_browser_list = NULL; + + grub_snprintf(cfgfile, sizeof(cfgfile), "configfile mem:0x%lx:size:%d", (ulong)mbuf.buf, mbuf.pos); + grub_script_execute_sourcecode(cfgfile); + + ventoy_browser_mbuf_free(&mbuf); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_browser_disk(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char cfgfile[64]; + browser_mbuf mbuf; + + (void)ctxt; + (void)argc; + (void)args; + + if (!ventoy_browser_mbuf_alloc(&mbuf)) + { + return 1; + } + + g_vtoy_dev = grub_env_get("vtoydev"); + + if (g_tree_view_menu_style == 0) + { + browser_ssprintf(&mbuf, "menuentry \"%-10s [%s]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n}\n", "<--", + ventoy_get_vmenu_title("VTLANG_BROWER_RETURN")); + } + else + { + browser_ssprintf(&mbuf, "menuentry \"[%s]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n}\n", + ventoy_get_vmenu_title("VTLANG_BROWER_RETURN")); + } + + grub_disk_dev_iterate(ventoy_browser_iterate_disk, &mbuf); + + grub_snprintf(cfgfile, sizeof(cfgfile), "configfile mem:0x%lx:size:%d", (ulong)mbuf.buf, mbuf.pos); + grub_script_execute_sourcecode(cfgfile); + + ventoy_browser_mbuf_free(&mbuf); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c new file mode 100644 index 0000000..114216c --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_cmd.c @@ -0,0 +1,7209 @@ +/****************************************************************************** + * ventoy_cmd.c + * + * Copyright (c) 2021, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GRUB_MACHINE_EFI +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include "ventoy_def.h" +#include "miniz.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +static grub_uint8_t g_check_mbr_data[] = { + 0xEB, 0x63, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x54, 0x00, 0x47, 0x65, 0x00, 0x48, 0x44, 0x00, 0x52, 0x64, 0x00, 0x20, 0x45, 0x72, 0x0D, +}; + +initrd_info *g_initrd_img_list = NULL; +initrd_info *g_initrd_img_tail = NULL; +int g_initrd_img_count = 0; +int g_valid_initrd_count = 0; +int g_default_menu_mode = 0; +int g_filt_dot_underscore_file = 0; +int g_filt_trash_dir = 1; +int g_sort_case_sensitive = 0; +int g_tree_view_menu_style = 0; +static grub_file_t g_old_file; +static int g_ventoy_last_entry_back; + +char g_iso_path[256]; +char g_img_swap_tmp_buf[1024]; +img_info g_img_swap_tmp; +img_info *g_ventoy_img_list = NULL; + +int g_ventoy_img_count = 0; + +grub_device_t g_enum_dev = NULL; +grub_fs_t g_enum_fs = NULL; +int g_img_max_search_level = -1; +img_iterator_node g_img_iterator_head; +img_iterator_node *g_img_iterator_tail = NULL; + +grub_uint8_t g_ventoy_break_level = 0; +grub_uint8_t g_ventoy_debug_level = 0; +grub_uint8_t g_ventoy_chain_type = 0; + +grub_uint8_t *g_ventoy_cpio_buf = NULL; +grub_uint32_t g_ventoy_cpio_size = 0; +cpio_newc_header *g_ventoy_initrd_head = NULL; +grub_uint8_t *g_ventoy_runtime_buf = NULL; + +int g_plugin_image_list = 0; + +ventoy_grub_param *g_grub_param = NULL; + +ventoy_guid g_ventoy_guid = VENTOY_GUID; + +ventoy_img_chunk_list g_img_chunk_list; + +int g_wimboot_enable = 0; +ventoy_img_chunk_list g_wimiso_chunk_list; +char *g_wimiso_path = NULL; +grub_uint32_t g_wimiso_size = 0; + +int g_vhdboot_enable = 0; + +grub_uint64_t g_svd_replace_offset = 0; + +int g_conf_replace_count = 0; +grub_uint64_t g_conf_replace_offset[VTOY_MAX_CONF_REPLACE] = { 0 }; +conf_replace *g_conf_replace_node[VTOY_MAX_CONF_REPLACE] = { NULL }; +grub_uint8_t *g_conf_replace_new_buf[VTOY_MAX_CONF_REPLACE] = { NULL }; +int g_conf_replace_new_len[VTOY_MAX_CONF_REPLACE] = { 0 }; +int g_conf_replace_new_len_align[VTOY_MAX_CONF_REPLACE] = { 0 }; + +int g_ventoy_disk_bios_id = 0; +ventoy_gpt_info *g_ventoy_part_info = NULL; +grub_uint64_t g_ventoy_disk_size = 0; +grub_uint64_t g_ventoy_disk_part_size[2]; + +char *g_tree_script_buf = NULL; +int g_tree_script_pos = 0; +int g_tree_script_pre = 0; + +static char *g_list_script_buf = NULL; +static int g_list_script_pos = 0; + +static char *g_part_list_buf = NULL; +static int g_part_list_pos = 0; +static grub_uint64_t g_part_end_max = 0; + +static int g_video_mode_max = 0; +static int g_video_mode_num = 0; +static ventoy_video_mode *g_video_mode_list = NULL; + +static int g_enumerate_time_checked = 0; +static grub_uint64_t g_enumerate_start_time_ms; +static grub_uint64_t g_enumerate_finish_time_ms; +int g_vtoy_file_flt[VTOY_FILE_FLT_BUTT] = {0}; + +static char g_iso_vd_id_publisher[130]; +static char g_iso_vd_id_prepare[130]; +static char g_iso_vd_id_application[130]; + +static int g_pager_flag = 0; +static char g_old_pager[32]; + +const char *g_menu_class[img_type_max] = +{ + "vtoyiso", "vtoywim", "vtoyefi", "vtoyimg", "vtoyvhd", "vtoyvtoy" +}; + +const char *g_menu_prefix[img_type_max] = +{ + "iso", "wim", "efi", "img", "vhd", "vtoy" +}; + +static const char *g_lower_chksum_name[VTOY_CHKSUM_NUM] = { "md5", "sha1", "sha256", "sha512" }; +static int g_lower_chksum_namelen[VTOY_CHKSUM_NUM] = { 3, 4, 6, 6 }; +static int g_chksum_retlen[VTOY_CHKSUM_NUM] = { 32, 40, 64, 128 }; + +static int g_vtoy_secondary_need_recover = 0; + +static int g_vtoy_load_prompt = 0; +static char g_vtoy_prompt_msg[64]; + +static char g_json_case_mis_path[32]; + +static ventoy_vlnk_part *g_vlnk_part_list = NULL; + +int ventoy_get_fs_type(const char *fs) +{ + if (NULL == fs) + { + return ventoy_fs_max; + } + else if (grub_strncmp(fs, "exfat", 5) == 0) + { + return ventoy_fs_exfat; + } + else if (grub_strncmp(fs, "ntfs", 4) == 0) + { + return ventoy_fs_ntfs; + } + else if (grub_strncmp(fs, "ext", 3) == 0) + { + return ventoy_fs_ext; + } + else if (grub_strncmp(fs, "xfs", 3) == 0) + { + return ventoy_fs_xfs; + } + else if (grub_strncmp(fs, "udf", 3) == 0) + { + return ventoy_fs_udf; + } + else if (grub_strncmp(fs, "fat", 3) == 0) + { + return ventoy_fs_fat; + } + else if (grub_strncmp(fs, "btrfs", 5) == 0) + { + return ventoy_fs_btrfs; + } + + return ventoy_fs_max; +} + +static int ventoy_string_check(const char *str, grub_char_check_func check) +{ + if (!str) + { + return 0; + } + + for ( ; *str; str++) + { + if (!check(*str)) + { + return 0; + } + } + + return 1; +} + + +static grub_ssize_t ventoy_fs_read(grub_file_t file, char *buf, grub_size_t len) +{ + grub_memcpy(buf, (char *)file->data + file->offset, len); + return len; +} + +static int ventoy_control_get_flag(const char *key) +{ + const char *val = ventoy_get_env(key); + + if (val && val[0] == '1' && val[1] == 0) + { + return 1; + } + return 0; +} + +static grub_err_t ventoy_fs_close(grub_file_t file) +{ + grub_file_close(g_old_file); + grub_free(file->data); + + file->device = 0; + file->name = 0; + + return 0; +} + +static int ventoy_video_hook(const struct grub_video_mode_info *info, void *hook_arg) +{ + int i; + + (void)hook_arg; + + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT) + { + return 0; + } + + for (i = 0; i < g_video_mode_num; i++) + { + if (g_video_mode_list[i].width == info->width && + g_video_mode_list[i].height == info->height && + g_video_mode_list[i].bpp == info->bpp) + { + return 0; + } + } + + g_video_mode_list[g_video_mode_num].width = info->width; + g_video_mode_list[g_video_mode_num].height = info->height; + g_video_mode_list[g_video_mode_num].bpp = info->bpp; + g_video_mode_num++; + + if (g_video_mode_num == g_video_mode_max) + { + g_video_mode_max *= 2; + g_video_mode_list = grub_realloc(g_video_mode_list, g_video_mode_max * sizeof(ventoy_video_mode)); + } + + return 0; +} + +static int ventoy_video_mode_cmp(ventoy_video_mode *v1, ventoy_video_mode *v2) +{ + if (v1->bpp == v2->bpp) + { + if (v1->width == v2->width) + { + if (v1->height == v2->height) + { + return 0; + } + else + { + return (v1->height < v2->height) ? -1 : 1; + } + } + else + { + return (v1->width < v2->width) ? -1 : 1; + } + } + else + { + return (v1->bpp < v2->bpp) ? -1 : 1; + } +} + +static int ventoy_enum_video_mode(void) +{ + int i, j; + grub_video_adapter_t adapter; + grub_video_driver_id_t id; + ventoy_video_mode mode; + + g_video_mode_num = 0; + g_video_mode_max = 1024; + g_video_mode_list = grub_malloc(sizeof(ventoy_video_mode) * g_video_mode_max); + if (!g_video_mode_list) + { + return 0; + } + + #ifdef GRUB_MACHINE_PCBIOS + grub_dl_load ("vbe"); + #endif + + id = grub_video_get_driver_id (); + + FOR_VIDEO_ADAPTERS (adapter) + { + if (!adapter->iterate || + (adapter->id != id && (id != GRUB_VIDEO_DRIVER_NONE || + adapter->init() != GRUB_ERR_NONE))) + { + continue; + } + + adapter->iterate(ventoy_video_hook, NULL); + + if (adapter->id != id) + { + adapter->fini(); + } + } + + /* sort video mode */ + for (i = 0; i < g_video_mode_num; i++) + for (j = i + 1; j < g_video_mode_num; j++) + { + if (ventoy_video_mode_cmp(g_video_mode_list + i, g_video_mode_list + j) < 0) + { + grub_memcpy(&mode, g_video_mode_list + i, sizeof(ventoy_video_mode)); + grub_memcpy(g_video_mode_list + i, g_video_mode_list + j, sizeof(ventoy_video_mode)); + grub_memcpy(g_video_mode_list + j, &mode, sizeof(ventoy_video_mode)); + } + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_pre_parse_data(char *src, int size) +{ + char c; + char *pos = NULL; + char buf[256]; + + if (size < 20 || grub_strncmp(src, "ventoy_left_top_color", 21)) + { + return 0; + } + + pos = src + 21; + while (*pos && *pos != '\r' && *pos != '\n') + { + pos++; + } + + c = *pos; + *pos = 0; + + if (grub_strlen(src) > 200) + { + goto end; + } + + grub_snprintf(buf, sizeof(buf), + "regexp -s 1:%s -s 2:%s -s 3:%s \"@([^@]*)@([^@]*)@([^@]*)@\" \"%s\"", + ventoy_left_key, ventoy_top_key, ventoy_color_key, src); + + grub_script_execute_sourcecode(buf); + +end: + *pos = c; + return 0; +} + +static grub_file_t ventoy_wrapper_open(grub_file_t rawFile, enum grub_file_type type) +{ + int len; + grub_file_t file; + static struct grub_fs vtoy_fs = + { + .name = "vtoy", + .fs_dir = 0, + .fs_open = 0, + .fs_read = ventoy_fs_read, + .fs_close = ventoy_fs_close, + .fs_label = 0, + .next = 0 + }; + + if (type != 52) + { + return rawFile; + } + + file = (grub_file_t)grub_zalloc(sizeof (*file)); + if (!file) + { + return 0; + } + + file->data = grub_malloc(rawFile->size + 4096); + if (!file->data) + { + return 0; + } + + grub_file_read(rawFile, file->data, rawFile->size); + ventoy_pre_parse_data((char *)file->data, (int)rawFile->size); + len = ventoy_fill_data(4096, (char *)file->data + rawFile->size); + + g_old_file = rawFile; + + file->size = rawFile->size + len; + file->device = rawFile->device; + file->fs = &vtoy_fs; + file->not_easily_seekable = 1; + + return file; +} + +static int ventoy_check_decimal_var(const char *name, long *value) +{ + const char *value_str = NULL; + + value_str = grub_env_get(name); + if (NULL == value_str) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s not found", name); + } + + if (!ventoy_is_decimal(value_str)) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Variable %s value '%s' is not an integer", name, value_str); + } + + *value = grub_strtol(value_str, NULL, 10); + + return GRUB_ERR_NONE; +} + +grub_uint64_t ventoy_get_vtoy_partsize(int part) +{ + grub_uint64_t sectors; + + if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0) + { + sectors = g_ventoy_part_info->PartTbl[part].LastLBA + 1 - g_ventoy_part_info->PartTbl[part].StartLBA; + } + else + { + sectors = g_ventoy_part_info->MBR.PartTbl[part].SectorCount; + } + + return sectors * 512; +} + +static int ventoy_load_efiboot_template(char **buf, int *datalen, int *direntoff) +{ + int len; + grub_file_t file; + char exec[128]; + char *data = NULL; + grub_uint32_t offset; + + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part")); + if (file == NULL) + { + debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz"); + return 1; + } + + len = (int)file->size; + + data = (char *)grub_malloc(file->size); + if (!data) + { + return 1; + } + + grub_file_read(file, data, file->size); + grub_file_close(file); + + grub_snprintf(exec, sizeof(exec), "loopback efiboot mem:0x%llx:size:%d", (ulonglong)(ulong)data, len); + grub_script_execute_sourcecode(exec); + + file = grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD); + offset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file); + grub_file_close(file); + + grub_script_execute_sourcecode("loopback -d efiboot"); + + *buf = data; + *datalen = len; + *direntoff = offset + 2; + + return 0; +} + +static int ventoy_set_check_result(int ret, const char *msg) +{ + char buf[32]; + + grub_snprintf(buf, sizeof(buf), "%d", (ret & 0x7FFF)); + grub_env_set("VTOY_CHKDEV_RESULT_STRING", buf); + grub_env_export("VTOY_CHKDEV_RESULT_STRING"); + + if (ret) + { + grub_cls(); + grub_printf(VTOY_WARNING"\n"); + grub_printf(VTOY_WARNING"\n"); + grub_printf(VTOY_WARNING"\n\n\n"); + + grub_printf("This is NOT a standard Ventoy device and is NOT supported (%d).\n", ret); + grub_printf("Error message: <%s>\n\n", msg); + grub_printf("You should follow the instructions in https://www.ventoy.net to use Ventoy.\n"); + grub_refresh(); + } + + return ret; +} + +static int ventoy_check_official_device(grub_device_t dev) +{ + int workaround = 0; + grub_file_t file; + grub_uint64_t offset; + char devname[64]; + grub_fs_t fs; + grub_uint8_t mbr[512]; + grub_disk_t disk; + grub_device_t dev2; + char *label = NULL; + struct grub_partition *partition; + + if (dev->disk == NULL || dev->disk->partition == NULL) + { + return ventoy_set_check_result(1 | 0x1000, "Internal Error"); + } + + if (0 == ventoy_check_file_exist("(%s,2)/ventoy/ventoy.cpio", dev->disk->name) || + 0 == ventoy_check_file_exist("(%s,2)/grub/localboot.cfg", dev->disk->name) || + 0 == ventoy_check_file_exist("(%s,2)/tool/mount.exfat-fuse_aarch64", dev->disk->name)) + { + #ifndef GRUB_MACHINE_EFI + if (0 == ventoy_check_file_exist("(ventoydisk)/ventoy/ventoy.cpio", dev->disk->name)) + { + return ventoy_set_check_result(2 | 0x1000, "File ventoy/ventoy.cpio missing in VTOYEFI partition"); + } + else if (0 == ventoy_check_file_exist("(ventoydisk)/grub/localboot.cfg", dev->disk->name)) + { + return ventoy_set_check_result(2 | 0x1000, "File grub/localboot.cfg missing in VTOYEFI partition"); + } + else if (0 == ventoy_check_file_exist("(ventoydisk)/tool/mount.exfat-fuse_aarch64", dev->disk->name)) + { + return ventoy_set_check_result(2 | 0x1000, "File tool/mount.exfat-fuse_aarch64 missing in VTOYEFI partition"); + } + else + { + workaround = 1; + } + #endif + } + + /* We must have partition 2 */ + if (workaround) + { + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(ventoydisk)/ventoy/ventoy.cpio"); + } + else + { + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(%s,2)/ventoy/ventoy.cpio", dev->disk->name); + } + if (!file) + { + return ventoy_set_check_result(3 | 0x1000, "File ventoy/ventoy.cpio open failed in VTOYEFI partition"); + } + + if (NULL == grub_strstr(file->fs->name, "fat")) + { + grub_file_close(file); + return ventoy_set_check_result(4 | 0x1000, "VTOYEFI partition is not FAT filesystem"); + } + + partition = dev->disk->partition; + if (partition->number != 0 || partition->start != 2048) + { + return ventoy_set_check_result(5, "Ventoy partition is not start at 1MB"); + } + + if (workaround) + { + if (grub_strncmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0) + { + ventoy_gpt_part_tbl *PartTbl = g_ventoy_part_info->PartTbl; + if (PartTbl[1].StartLBA != PartTbl[0].LastLBA + 1 || + (PartTbl[1].LastLBA + 1 - PartTbl[1].StartLBA) != 65536) + { + grub_file_close(file); + return ventoy_set_check_result(6, "Disk partition layout check failed."); + } + } + else + { + ventoy_part_table *PartTbl = g_ventoy_part_info->MBR.PartTbl; + if (PartTbl[1].StartSectorId != PartTbl[0].StartSectorId + PartTbl[0].SectorCount || + PartTbl[1].SectorCount != 65536) + { + grub_file_close(file); + return ventoy_set_check_result(6, "Disk partition layout check failed."); + } + } + } + else + { + offset = partition->start + partition->len; + partition = file->device->disk->partition; + if ((partition->number != 1) || (partition->len != 65536) || (offset != partition->start)) + { + grub_file_close(file); + return ventoy_set_check_result(7, "Disk partition layout check failed."); + } + } + + grub_file_close(file); + + if (workaround == 0) + { + grub_snprintf(devname, sizeof(devname), "%s,2", dev->disk->name); + dev2 = grub_device_open(devname); + if (!dev2) + { + return ventoy_set_check_result(8, "Disk open failed"); + } + + fs = grub_fs_probe(dev2); + if (!fs) + { + grub_device_close(dev2); + return ventoy_set_check_result(9, "FS probe failed"); + } + + fs->fs_label(dev2, &label); + if ((!label) || grub_strncmp("VTOYEFI", label, 7)) + { + grub_device_close(dev2); + return ventoy_set_check_result(10, "Partition name is not VTOYEFI"); + } + + grub_device_close(dev2); + } + + /* MBR check */ + disk = grub_disk_open(dev->disk->name); + if (!disk) + { + return ventoy_set_check_result(11, "Disk open failed"); + } + + grub_memset(mbr, 0, 512); + grub_disk_read(disk, 0, 0, 512, mbr); + grub_disk_close(disk); + + if (grub_memcmp(g_check_mbr_data, mbr, 0x30) || grub_memcmp(g_check_mbr_data + 0x30, mbr + 0x190, 16)) + { + return ventoy_set_check_result(12, "MBR check failed"); + } + + return ventoy_set_check_result(0, NULL); +} + +static int ventoy_check_ignore_flag(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + if (0 == info->dir) + { + if (filename && filename[0] == '.' && 0 == grub_strncmp(filename, ".ventoyignore", 13)) + { + *((int *)data) = 1; + return 0; + } + } + + return 0; +} + +grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...) +{ + grub_uint64_t size = 0; + grub_file_t file; + va_list ap; + char fullpath[256] = {0}; + + va_start (ap, fmt); + grub_vsnprintf(fullpath, 255, fmt, ap); + va_end (ap); + + file = grub_file_open(fullpath, VENTOY_FILE_TYPE); + if (!file) + { + debug("grub_file_open failed <%s>\n", fullpath); + grub_errno = 0; + return 0; + } + + size = file->size; + grub_file_close(file); + return size; +} + +grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...) +{ + va_list ap; + grub_file_t file; + char fullpath[512] = {0}; + + va_start (ap, fmt); + grub_vsnprintf(fullpath, 511, fmt, ap); + va_end (ap); + + file = grub_file_open(fullpath, type); + if (!file) + { + debug("grub_file_open failed <%s> %d\n", fullpath, grub_errno); + grub_errno = 0; + } + + return file; +} + +int ventoy_is_dir_exist(const char *fmt, ...) +{ + va_list ap; + int len; + char *pos = NULL; + char buf[512] = {0}; + + grub_snprintf(buf, sizeof(buf), "%s", "[ -d \""); + pos = buf + 6; + + va_start (ap, fmt); + len = grub_vsnprintf(pos, 511, fmt, ap); + va_end (ap); + + grub_strncpy(pos + len, "\" ]", 3); + + debug("script exec %s\n", buf); + + if (0 == grub_script_execute_sourcecode(buf)) + { + return 1; + } + + return 0; +} + +int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len) +{ + mz_stream s; + grub_uint8_t *outbuf; + grub_uint8_t gzHdr[10] = + { + 0x1F, 0x8B, /* magic */ + 8, /* z method */ + 0, /* flags */ + 0,0,0,0, /* mtime */ + 4, /* xfl */ + 3, /* OS */ + }; + + grub_memset(&s, 0, sizeof(mz_stream)); + + mz_deflateInit2(&s, 1, MZ_DEFLATED, -MZ_DEFAULT_WINDOW_BITS, 6, MZ_DEFAULT_STRATEGY); + + outbuf = (grub_uint8_t *)mem_out; + + mem_out_len -= sizeof(gzHdr) + 8; + grub_memcpy(outbuf, gzHdr, sizeof(gzHdr)); + outbuf += sizeof(gzHdr); + + s.avail_in = mem_in_len; + s.next_in = mem_in; + + s.avail_out = mem_out_len; + s.next_out = outbuf; + + mz_deflate(&s, MZ_FINISH); + + mz_deflateEnd(&s); + + outbuf += s.total_out; + *(grub_uint32_t *)outbuf = grub_getcrc32c(0, outbuf, s.total_out); + *(grub_uint32_t *)(outbuf + 4) = (grub_uint32_t)(s.total_out); + + return s.total_out + sizeof(gzHdr) + 8; +} + + +#if 0 +ventoy grub cmds +#endif + +static grub_err_t ventoy_cmd_debug(grub_extcmd_context_t ctxt, int argc, char **args) +{ + if (argc != 1) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {on|off}", cmd_raw_name); + } + + if (0 == grub_strcmp(args[0], "on")) + { + g_ventoy_debug = 1; + grub_env_set("vtdebug_flag", "debug"); + } + else + { + g_ventoy_debug = 0; + grub_env_set("vtdebug_flag", ""); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_break(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + + if (argc < 1 || (args[0][0] != '0' && args[0][0] != '1')) + { + grub_printf("Usage: %s {level} [debug]\r\n", cmd_raw_name); + grub_printf(" level:\r\n"); + grub_printf(" 01/11: busybox / (+cat log)\r\n"); + grub_printf(" 02/12: initrd / (+cat log)\r\n"); + grub_printf(" 03/13: hook / (+cat log)\r\n"); + grub_printf("\r\n"); + grub_printf(" debug:\r\n"); + grub_printf(" 0: debug is off\r\n"); + grub_printf(" 1: debug is on\r\n"); + grub_printf("\r\n"); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); + } + + g_ventoy_break_level = (grub_uint8_t)grub_strtoul(args[0], NULL, 16); + + if (argc > 1 && grub_strtoul(args[1], NULL, 10) > 0) + { + g_ventoy_debug_level = 1; + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_strstr(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + + if (argc != 2) + { + return 1; + } + + return (grub_strstr(args[0], args[1])) ? 0 : 1; +} + +static grub_err_t ventoy_cmd_istrstr(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_err_t ret = 1; + char *s1 = NULL; + char *s2 = NULL; + + (void)ctxt; + + if (argc != 2) + { + return 1; + } + + s1 = grub_strdup(args[0]); + s2 = grub_strdup(args[1]); + if (s1 == NULL || s2 == NULL) + { + goto end; + } + + ventoy_str_toupper(s1); + ventoy_str_toupper(s2); + ret = (grub_strstr(s1, s2)) ? 0 : 1; + +end: + grub_check_free(s1); + grub_check_free(s2); + return ret; +} + +static grub_err_t ventoy_cmd_strbegin(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char *c0, *c1; + + (void)ctxt; + + if (argc != 2) + { + return 1; + } + + c0 = args[0]; + c1 = args[1]; + + while (*c0 && *c1) + { + if (*c0 != *c1) + { + return 1; + } + c0++; + c1++; + } + + if (*c1) + { + return 1; + } + + return 0; +} + +static grub_err_t ventoy_cmd_strcasebegin(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char *c0, *c1; + + (void)ctxt; + + if (argc != 2) + { + return 1; + } + + c0 = args[0]; + c1 = args[1]; + + while (*c0 && *c1) + { + if ((*c0 != *c1) && (*c0 != grub_toupper(*c1))) + { + return 1; + } + c0++; + c1++; + } + + if (*c1) + { + return 1; + } + + return 0; +} + +static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args) +{ + long value_long = 0; + char buf[32]; + + if ((argc != 2) || (!ventoy_is_decimal(args[1]))) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Variable} {Int}", cmd_raw_name); + } + + if (GRUB_ERR_NONE != ventoy_check_decimal_var(args[0], &value_long)) + { + return grub_errno; + } + + value_long += grub_strtol(args[1], NULL, 10); + + grub_snprintf(buf, sizeof(buf), "%ld", value_long); + grub_env_set(args[0], buf); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_mod(grub_extcmd_context_t ctxt, int argc, char **args) +{ + ulonglong value1 = 0; + ulonglong value2 = 0; + char buf[32]; + + if (argc != 3) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int} {Int} {Variable}", cmd_raw_name); + } + + value1 = grub_strtoull(args[0], NULL, 10); + value2 = grub_strtoull(args[1], NULL, 10); + + grub_snprintf(buf, sizeof(buf), "%llu", (value1 & (value2 - 1))); + grub_env_set(args[2], buf); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_file_size(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int rc = 1; + char buf[32]; + grub_file_t file; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc != 2) + { + return rc; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (file == NULL) + { + debug("failed to open file <%s> for udf check\n", args[0]); + return 1; + } + + grub_snprintf(buf, sizeof(buf), "%llu", (unsigned long long)file->size); + + grub_env_set(args[1], buf); + + grub_file_close(file); + rc = 0; + + return rc; +} + +static grub_err_t ventoy_cmd_load_wimboot(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_file_t file; + + (void)ctxt; + (void)argc; + (void)args; + + g_wimboot_enable = 0; + g_wimiso_size = 0; + grub_check_free(g_wimiso_path); + grub_check_free(g_wimiso_chunk_list.chunk); + + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (!file) + { + return 0; + } + + grub_memset(&g_wimiso_chunk_list, 0, sizeof(g_wimiso_chunk_list)); + g_wimiso_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM); + if (NULL == g_wimiso_chunk_list.chunk) + { + return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n"); + } + + g_wimiso_chunk_list.max_chunk = DEFAULT_CHUNK_NUM; + g_wimiso_chunk_list.cur_chunk = 0; + + ventoy_get_block_list(file, &g_wimiso_chunk_list, file->device->disk->partition->start); + + g_wimboot_enable = 1; + g_wimiso_path = grub_strdup(args[0]); + g_wimiso_size = (grub_uint32_t)(file->size); + grub_file_close(file); + + return 0; +} + +static grub_err_t ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int len = 0; + int totlen = 0; + int offset = 0; + grub_file_t file; + char *buf = NULL; + char *data = NULL; + ventoy_iso9660_override *dirent; + + (void)ctxt; + + if (argc != 2) + { + return 1; + } + + totlen = sizeof(ventoy_chain_head); + + if (ventoy_load_efiboot_template(&buf, &len, &offset)) + { + debug("failed to load efiboot template %d\n", len); + return 1; + } + + totlen += len; + + debug("efiboot template len:%d offset:%d\n", len, offset); + + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]); + if (file == NULL) + { + debug("failed to open file <%s>\n", args[0]); + return 1; + } + + if (grub_strncmp(args[0], g_iso_path, grub_strlen(g_iso_path))) + { + file->vlnk = 1; + } + + totlen += ventoy_align_2k(file->size); + + dirent = (ventoy_iso9660_override *)(buf + offset); + dirent->first_sector = len / 2048; + dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector); + dirent->size = (grub_uint32_t)file->size; + dirent->size_be = grub_swap_bytes32(dirent->size); + + debug("rawiso len:%d efilen:%d total:%d\n", len, (int)file->size, totlen); + +#ifdef GRUB_MACHINE_EFI + data = (char *)grub_efi_allocate_iso_buf(totlen); +#else + data = (char *)grub_malloc(totlen); +#endif + + ventoy_fill_os_param(file, (ventoy_os_param *)data); + + grub_memcpy(data + sizeof(ventoy_chain_head), buf, len); + grub_check_free(buf); + + grub_file_read(file, data + sizeof(ventoy_chain_head) + len, file->size); + grub_file_close(file); + + ventoy_memfile_env_set(args[1], data, (ulonglong)totlen); + + return 0; +} + +grub_err_t ventoy_cmd_set_wim_prompt(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + g_vtoy_load_prompt = 0; + grub_memset(g_vtoy_prompt_msg, 0, sizeof(g_vtoy_prompt_msg)); + + if (argc == 2 && args[0][0] == '1') + { + g_vtoy_load_prompt = 1; + grub_snprintf(g_vtoy_prompt_msg, sizeof(g_vtoy_prompt_msg), "%s", args[1]); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +int ventoy_need_prompt_load_file(void) +{ + return g_vtoy_load_prompt; +} + +grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size) +{ + grub_uint64_t ro = 0; + grub_uint64_t div = 0; + grub_ssize_t left = size; + char *cur = (char *)buf; + + grub_printf("\r%s 1%% ", g_vtoy_prompt_msg); + grub_refresh(); + + while (left >= VTOY_SIZE_2MB) + { + grub_file_read(file, cur, VTOY_SIZE_2MB); + cur += VTOY_SIZE_2MB; + left -= VTOY_SIZE_2MB; + + div = grub_divmod64((grub_uint64_t)((size - left) * 100), (grub_uint64_t)size, &ro); + if (div < 1) + { + div = 1; + } + grub_printf("\r%s %d%% ", g_vtoy_prompt_msg, (int)div); + grub_refresh(); + } + + if (left > 0) + { + grub_file_read(file, cur, left); + } + + grub_printf("\r%s 100%% \n", g_vtoy_prompt_msg); + grub_refresh(); + + return size; +} + +static grub_err_t ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int rc = 1; + char *buf = NULL; + grub_file_t file; + enum grub_file_type type; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc != 3) + { + return rc; + } + + if (grub_strcmp(args[0], "nodecompress") == 0) + { + type = VENTOY_FILE_TYPE; + } + else + { + type = GRUB_FILE_TYPE_LINUX_INITRD; + } + + file = ventoy_grub_file_open(type, "%s", args[1]); + if (file == NULL) + { + debug("failed to open file <%s>\n", args[1]); + return 1; + } + +#ifdef GRUB_MACHINE_EFI + buf = (char *)grub_efi_allocate_chain_buf(file->size); +#else + buf = (char *)grub_malloc(file->size); +#endif + + if (!buf) + { + grub_file_close(file); + return 1; + } + + if (g_vtoy_load_prompt) + { + ventoy_load_file_with_prompt(file, buf, file->size); + } + else + { + grub_file_read(file, buf, file->size); + } + + ventoy_memfile_env_set(args[2], buf, (ulonglong)(file->size)); + + grub_file_close(file); + rc = 0; + + return rc; +} + +static grub_err_t ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int rc = 1; + int headlen; + char *buf = NULL; + grub_file_t file; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc != 2) + { + return rc; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (file == NULL) + { + debug("failed to open file <%s> for udf check\n", args[0]); + return 1; + } + + headlen = sizeof(ventoy_chain_head); + +#ifdef GRUB_MACHINE_EFI + buf = (char *)grub_efi_allocate_iso_buf(headlen + file->size); +#else + buf = (char *)grub_malloc(headlen + file->size); +#endif + + ventoy_fill_os_param(file, (ventoy_os_param *)buf); + + grub_file_read(file, buf + headlen, file->size); + + ventoy_memfile_env_set(args[1], buf, (ulonglong)(file->size)); + + grub_file_close(file); + rc = 0; + + return rc; +} + +static grub_err_t ventoy_cmd_iso9660_is_joliet(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + if (grub_iso9660_is_joliet()) + { + debug("This time has joliet process\n"); + return 0; + } + else + { + return 1; + } +} + +static grub_err_t ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + + if (argc != 1) + { + return 1; + } + + if (args[0][0] == '1') + { + grub_iso9660_set_nojoliet(1); + } + else + { + grub_iso9660_set_nojoliet(0); + } + + return 0; +} + +static grub_err_t ventoy_cmd_is_udf(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int rc = 1; + grub_file_t file; + grub_uint8_t buf[32]; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc != 1) + { + return rc; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (file == NULL) + { + debug("failed to open file <%s> for udf check\n", args[0]); + return 1; + } + + for (i = 16; i < 32; i++) + { + grub_file_seek(file, i * 2048); + grub_file_read(file, buf, sizeof(buf)); + if (buf[0] == 255) + { + break; + } + } + + i++; + grub_file_seek(file, i * 2048); + grub_file_read(file, buf, sizeof(buf)); + + if (grub_memcmp(buf + 1, "BEA01", 5) == 0) + { + i++; + grub_file_seek(file, i * 2048); + grub_file_read(file, buf, sizeof(buf)); + + if (grub_memcmp(buf + 1, "NSR02", 5) == 0 || + grub_memcmp(buf + 1, "NSR03", 5) == 0) + { + rc = 0; + } + } + + grub_file_close(file); + + debug("ISO UDF: %s\n", rc ? "NO" : "YES"); + + return rc; +} + +static grub_err_t ventoy_cmd_cmp(grub_extcmd_context_t ctxt, int argc, char **args) +{ + long value_long1 = 0; + long value_long2 = 0; + + if ((argc != 3) || (!ventoy_is_decimal(args[0])) || (!ventoy_is_decimal(args[2]))) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq|ne|gt|lt|ge|le } {Int2}", cmd_raw_name); + } + + value_long1 = grub_strtol(args[0], NULL, 10); + value_long2 = grub_strtol(args[2], NULL, 10); + + if (0 == grub_strcmp(args[1], "eq")) + { + grub_errno = (value_long1 == value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE; + } + else if (0 == grub_strcmp(args[1], "ne")) + { + grub_errno = (value_long1 != value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE; + } + else if (0 == grub_strcmp(args[1], "gt")) + { + grub_errno = (value_long1 > value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE; + } + else if (0 == grub_strcmp(args[1], "lt")) + { + grub_errno = (value_long1 < value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE; + } + else if (0 == grub_strcmp(args[1], "ge")) + { + grub_errno = (value_long1 >= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE; + } + else if (0 == grub_strcmp(args[1], "le")) + { + grub_errno = (value_long1 <= value_long2) ? GRUB_ERR_NONE : GRUB_ERR_TEST_FAILURE; + } + else + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {Int1} { eq ne gt lt ge le } {Int2}", cmd_raw_name); + } + + return grub_errno; +} + +static grub_err_t ventoy_cmd_device(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char *pos = NULL; + char buf[128] = {0}; + + if (argc != 2) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s path var", cmd_raw_name); + } + + grub_strncpy(buf, (args[0][0] == '(') ? args[0] + 1 : args[0], sizeof(buf) - 1); + pos = grub_strstr(buf, ","); + if (pos) + { + *pos = 0; + } + + grub_env_set(args[1], buf); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_check_compatible(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + char buf[256]; + grub_disk_t disk; + char *pos = NULL; + const char *files[] = { "ventoy.dat", "VENTOY.DAT" }; + + (void)ctxt; + + if (argc != 1) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s (loop)", cmd_raw_name); + } + + for (i = 0; i < (int)ARRAY_SIZE(files); i++) + { + grub_snprintf(buf, sizeof(buf) - 1, "[ -e \"%s/%s\" ]", args[0], files[i]); + if (0 == grub_script_execute_sourcecode(buf)) + { + debug("file %s exist, ventoy_compatible YES\n", buf); + grub_env_set("ventoy_compatible", "YES"); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); + } + else + { + debug("file %s NOT exist\n", buf); + } + } + + grub_snprintf(buf, sizeof(buf) - 1, "%s", args[0][0] == '(' ? (args[0] + 1) : args[0]); + pos = grub_strstr(buf, ")"); + if (pos) + { + *pos = 0; + } + + disk = grub_disk_open(buf); + if (disk) + { + grub_disk_read(disk, 16 << 2, 0, 1024, g_img_swap_tmp_buf); + grub_disk_close(disk); + + g_img_swap_tmp_buf[703] = 0; + for (i = 318; i < 703; i++) + { + if (g_img_swap_tmp_buf[i] == 'V' && + 0 == grub_strncmp(g_img_swap_tmp_buf + i, VENTOY_COMPATIBLE_STR, VENTOY_COMPATIBLE_STR_LEN)) + { + debug("Ventoy compatible string exist at %d, ventoy_compatible YES\n", i); + grub_env_set("ventoy_compatible", "YES"); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); + } + } + } + else + { + debug("failed to open disk <%s>\n", buf); + } + + grub_env_set("ventoy_compatible", "NO"); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +int ventoy_cmp_img(img_info *img1, img_info *img2) +{ + char *s1, *s2; + int c1 = 0; + int c2 = 0; + + if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST) + { + return (img1->plugin_list_index - img2->plugin_list_index); + } + + for (s1 = img1->name, s2 = img2->name; *s1 && *s2; s1++, s2++) + { + c1 = *s1; + c2 = *s2; + + if (0 == g_sort_case_sensitive) + { + if (grub_islower(c1)) + { + c1 = c1 - 'a' + 'A'; + } + + if (grub_islower(c2)) + { + c2 = c2 - 'a' + 'A'; + } + } + + if (c1 != c2) + { + break; + } + } + + return (c1 - c2); +} + +static int ventoy_cmp_subdir(img_iterator_node *node1, img_iterator_node *node2) +{ + int i = 0; + int c1 = 0; + int c2 = 0; + int len = 0; + char *s1, *s2; + + if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST) + { + return (node1->plugin_list_index - node2->plugin_list_index); + } + + s1 = node1->dir; + s2 = node2->dir; + len = grub_min(node1->dirlen, node2->dirlen); + + for (i = 0; i < len - 1; i++) + { + c1 = *s1++; + c2 = *s2++; + + if (0 == g_sort_case_sensitive) + { + if (grub_islower(c1)) + { + c1 = c1 - 'a' + 'A'; + } + + if (grub_islower(c2)) + { + c2 = c2 - 'a' + 'A'; + } + } + + if (c1 != c2) + { + return (c1 - c2); + } + } + + if (len == node1->dirlen) + { + c1 = 0; + } + + if (len == node2->dirlen) + { + c2 = 0; + } + + return (c1 - c2); +} + +void ventoy_swap_img(img_info *img1, img_info *img2) +{ + grub_memcpy(&g_img_swap_tmp, img1, sizeof(img_info)); + + grub_memcpy(img1, img2, sizeof(img_info)); + img1->next = g_img_swap_tmp.next; + img1->prev = g_img_swap_tmp.prev; + + g_img_swap_tmp.next = img2->next; + g_img_swap_tmp.prev = img2->prev; + grub_memcpy(img2, &g_img_swap_tmp, sizeof(img_info)); +} + +int ventoy_img_name_valid(const char *filename, grub_size_t namelen) +{ + (void)namelen; + + if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_') + { + return 0; + } + + return 1; +} + +static int ventoy_vlnk_iterate_partition(struct grub_disk *disk, const grub_partition_t partition, void *data) +{ + ventoy_vlnk_part *node = NULL; + grub_uint32_t SelfSig; + grub_uint32_t *pSig = (grub_uint32_t *)data; + + /* skip Ventoy partition 1/2 */ + grub_memcpy(&SelfSig, g_ventoy_part_info->MBR.BootCode + 0x1b8, 4); + if (partition->number < 2 && SelfSig == *pSig) + { + return 0; + } + + node = grub_zalloc(sizeof(ventoy_vlnk_part)); + if (node) + { + node->disksig = *pSig; + node->partoffset = (partition->start << GRUB_DISK_SECTOR_BITS); + grub_snprintf(node->disk, sizeof(node->disk) - 1, "%s", disk->name); + grub_snprintf(node->device, sizeof(node->device) - 1, "%s,%d", disk->name, partition->number + 1); + + node->next = g_vlnk_part_list; + g_vlnk_part_list = node; + } + + return 0; +} + +static int ventoy_vlnk_iterate_disk(const char *name, void *data) +{ + grub_disk_t disk; + grub_uint32_t sig; + + (void)data; + + disk = grub_disk_open(name); + if (disk) + { + grub_disk_read(disk, 0, 0x1b8, 4, &sig); + grub_partition_iterate(disk, ventoy_vlnk_iterate_partition, &sig); + grub_disk_close(disk); + } + + return 0; +} + +static int ventoy_vlnk_probe_fs(ventoy_vlnk_part *cur) +{ + const char *fs[ventoy_fs_max + 1] = + { + "exfat", "ntfs", "ext2", "xfs", "udf", "fat", "btrfs", NULL + }; + + if (!cur->dev) + { + cur->dev = grub_device_open(cur->device); + } + + if (cur->dev) + { + cur->fs = grub_fs_list_probe(cur->dev, fs); + } + + return 0; +} + +static int ventoy_check_vlnk_data(ventoy_vlnk *vlnk, int print, char *dst, int size) +{ + int diskfind = 0; + int partfind = 0; + int filefind = 0; + char *disk, *device; + grub_uint32_t readcrc, calccrc; + ventoy_vlnk_part *cur; + grub_fs_t fs = NULL; + + if (grub_memcmp(&(vlnk->guid), &g_ventoy_guid, sizeof(ventoy_guid))) + { + if (print) + { + grub_printf("VLNK invalid guid\n"); + grub_refresh(); + } + return 1; + } + + readcrc = vlnk->crc32; + vlnk->crc32 = 0; + calccrc = grub_getcrc32c(0, vlnk, sizeof(ventoy_vlnk)); + if (readcrc != calccrc) + { + if (print) + { + grub_printf("VLNK invalid crc 0x%08x 0x%08x\n", calccrc, readcrc); + grub_refresh(); + } + return 1; + } + + if (!g_vlnk_part_list) + { + grub_disk_dev_iterate(ventoy_vlnk_iterate_disk, NULL); + } + + for (cur = g_vlnk_part_list; cur && filefind == 0; cur = cur->next) + { + if (cur->disksig == vlnk->disk_signature) + { + diskfind = 1; + disk = cur->disk; + if (cur->partoffset == vlnk->part_offset) + { + partfind = 1; + device = cur->device; + + if (cur->probe == 0) + { + cur->probe = 1; + ventoy_vlnk_probe_fs(cur); + } + + if (!fs) + { + fs = cur->fs; + } + + if (cur->fs) + { + struct grub_file file; + + grub_memset(&file, 0, sizeof(file)); + file.device = cur->dev; + if (cur->fs->fs_open(&file, vlnk->filepath) == GRUB_ERR_NONE) + { + filefind = 1; + cur->fs->fs_close(&file); + grub_snprintf(dst, size - 1, "(%s)%s", cur->device, vlnk->filepath); + } + else + { + grub_errno = 0; + } + } + } + } + } + + if (print) + { + grub_printf("\n==== VLNK Information ====\n" + "Disk Signature: %08x\n" + "Partition Offset: %llu\n" + "File Path: <%s>\n\n", + vlnk->disk_signature, (ulonglong)vlnk->part_offset, vlnk->filepath); + + if (diskfind) + { + grub_printf("Disk Find: [ YES ] [ %s ]\n", disk); + } + else + { + grub_printf("Disk Find: [ NO ]\n"); + } + + if (partfind) + { + grub_printf("Part Find: [ YES ] [ %s ] [ %s ]\n", device, fs ? fs->name : "N/A"); + } + else + { + grub_printf("Part Find: [ NO ]\n"); + } + grub_printf("File Find: [ %s ]\n", filefind ? "YES" : "NO"); + if (filefind) + { + grub_printf("VLNK File: <%s>\n", dst); + } + + grub_printf("\n"); + grub_refresh(); + } + + return (1 - filefind); +} + +int ventoy_add_vlnk_file(char *dir, const char *name) +{ + int rc = 1; + char src[512]; + char dst[512]; + grub_file_t file = NULL; + ventoy_vlnk vlnk; + + if (!dir) + { + grub_snprintf(src, sizeof(src), "%s%s", g_iso_path, name); + } + else if (dir[0] == '/') + { + grub_snprintf(src, sizeof(src), "%s%s%s", g_iso_path, dir, name); + } + else + { + grub_snprintf(src, sizeof(src), "%s/%s%s", g_iso_path, dir, name); + } + + file = grub_file_open(src, VENTOY_FILE_TYPE); + if (!file) + { + return 1; + } + + grub_memset(&vlnk, 0, sizeof(vlnk)); + grub_file_read(file, &vlnk, sizeof(vlnk)); + grub_file_close(file); + + if (ventoy_check_vlnk_data(&vlnk, 0, dst, sizeof(dst)) == 0) + { + rc = grub_file_add_vlnk(src, dst); + } + + return rc; +} + +static int ventoy_collect_img_files(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + //int i = 0; + int type = 0; + int ignore = 0; + int index = 0; + int vlnk = 0; + grub_size_t len; + img_info *img; + img_info *tail; + const menu_tip *tip; + img_iterator_node *tmp; + img_iterator_node *new_node; + img_iterator_node *node = (img_iterator_node *)data; + + if (g_enumerate_time_checked == 0) + { + g_enumerate_finish_time_ms = grub_get_time_ms(); + if ((g_enumerate_finish_time_ms - g_enumerate_start_time_ms) >= 3000) + { + grub_cls(); + grub_printf("\n\n Ventoy scanning files, please wait...\n"); + grub_refresh(); + g_enumerate_time_checked = 1; + } + } + + len = grub_strlen(filename); + + if (info->dir) + { + if (node->level + 1 > g_img_max_search_level) + { + return 0; + } + + if ((len == 1 && filename[0] == '.') || + (len == 2 && filename[0] == '.' && filename[1] == '.')) + { + return 0; + } + + if (!ventoy_img_name_valid(filename, len)) + { + return 0; + } + + if (g_filt_trash_dir) + { + if (0 == grub_strncmp(filename, ".trash-", 7) || + 0 == grub_strcmp(filename, ".Trashes") || + 0 == grub_strncmp(filename, "$RECYCLE.BIN", 12)) + { + return 0; + } + } + + if (g_plugin_image_list == VENTOY_IMG_WHITE_LIST) + { + grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s/", node->dir, filename); + index = ventoy_plugin_get_image_list_index(vtoy_class_directory, g_img_swap_tmp_buf); + if (index == 0) + { + debug("Directory %s not found in image_list plugin config...\n", g_img_swap_tmp_buf); + return 0; + } + } + + new_node = grub_zalloc(sizeof(img_iterator_node)); + if (new_node) + { + new_node->level = node->level + 1; + new_node->plugin_list_index = index; + new_node->dirlen = grub_snprintf(new_node->dir, sizeof(new_node->dir), "%s%s/", node->dir, filename); + + g_enum_fs->fs_dir(g_enum_dev, new_node->dir, ventoy_check_ignore_flag, &ignore); + if (ignore) + { + debug("Directory %s ignored...\n", new_node->dir); + grub_free(new_node); + return 0; + } + + new_node->tail = node->tail; + + new_node->parent = node; + if (!node->firstchild) + { + node->firstchild = new_node; + } + + if (g_img_iterator_tail) + { + g_img_iterator_tail->next = new_node; + g_img_iterator_tail = new_node; + } + else + { + g_img_iterator_head.next = new_node; + g_img_iterator_tail = new_node; + } + } + } + else + { + debug("Find a file %s\n", filename); + if (len < 4) + { + return 0; + } + + if (FILE_FLT(ISO) && 0 == grub_strcasecmp(filename + len - 4, ".iso")) + { + type = img_type_iso; + } + else if (FILE_FLT(WIM) && g_wimboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".wim"))) + { + type = img_type_wim; + } + else if (FILE_FLT(VHD) && g_vhdboot_enable && (0 == grub_strcasecmp(filename + len - 4, ".vhd") || + (len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vhdx")))) + { + type = img_type_vhd; + } + #ifdef GRUB_MACHINE_EFI + else if (FILE_FLT(EFI) && 0 == grub_strcasecmp(filename + len - 4, ".efi")) + { + type = img_type_efi; + } + #endif + else if (FILE_FLT(IMG) && 0 == grub_strcasecmp(filename + len - 4, ".img")) + { + if (len == 18 && grub_strncmp(filename, "ventoy_", 7) == 0) + { + if (grub_strncmp(filename + 7, "wimboot", 7) == 0 || + grub_strncmp(filename + 7, "vhdboot", 7) == 0) + { + return 0; + } + } + type = img_type_img; + } + else if (FILE_FLT(VTOY) && len >= 5 && 0 == grub_strcasecmp(filename + len - 5, ".vtoy")) + { + type = img_type_vtoy; + } + else if (len >= 9 && 0 == grub_strcasecmp(filename + len - 5, ".vcfg")) + { + if (filename[len - 9] == '.' || (len >= 10 && filename[len - 10] == '.')) + { + grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename); + ventoy_plugin_add_custom_boot(g_img_swap_tmp_buf); + } + return 0; + } + else + { + return 0; + } + + if (g_filt_dot_underscore_file && filename[0] == '.' && filename[1] == '_') + { + return 0; + } + + if (g_plugin_image_list) + { + grub_snprintf(g_img_swap_tmp_buf, sizeof(g_img_swap_tmp_buf), "%s%s", node->dir, filename); + index = ventoy_plugin_get_image_list_index(vtoy_class_image_file, g_img_swap_tmp_buf); + if (VENTOY_IMG_WHITE_LIST == g_plugin_image_list && index == 0) + { + debug("File %s not found in image_list plugin config...\n", g_img_swap_tmp_buf); + return 0; + } + else if (VENTOY_IMG_BLACK_LIST == g_plugin_image_list && index > 0) + { + debug("File %s found in image_blacklist plugin config %d ...\n", g_img_swap_tmp_buf, index); + return 0; + } + } + + if (info->size == VTOY_FILT_MIN_FILE_SIZE || info->size == 0) + { + if (grub_file_is_vlnk_suffix(filename, len)) + { + vlnk = 1; + if (ventoy_add_vlnk_file(node->dir, filename) != 0) + { + return 0; + } + } + } + + img = grub_zalloc(sizeof(img_info)); + if (img) + { + img->type = type; + img->plugin_list_index = index; + grub_snprintf(img->name, sizeof(img->name), "%s", filename); + + img->pathlen = grub_snprintf(img->path, sizeof(img->path), "%s%s", node->dir, img->name); + + img->size = info->size; + if (vlnk || 0 == img->size) + { + if (node->dir[0] == '/') + { + img->size = ventoy_grub_get_file_size("%s%s%s", g_iso_path, node->dir, filename); + } + else + { + img->size = ventoy_grub_get_file_size("%s/%s%s", g_iso_path, node->dir, filename); + } + } + + if (img->size < VTOY_FILT_MIN_FILE_SIZE) + { + debug("img <%s> size too small %llu\n", img->name, (ulonglong)img->size); + grub_free(img); + return 0; + } + + if (g_ventoy_img_list) + { + tail = *(node->tail); + img->prev = tail; + tail->next = img; + } + else + { + g_ventoy_img_list = img; + } + + img->id = g_ventoy_img_count; + img->parent = node; + if (node && NULL == node->firstiso) + { + node->firstiso = img; + } + + node->isocnt++; + tmp = node->parent; + while (tmp) + { + tmp->isocnt++; + tmp = tmp->parent; + } + + *((img_info **)(node->tail)) = img; + g_ventoy_img_count++; + + img->alias = ventoy_plugin_get_menu_alias(vtoy_alias_image_file, img->path); + + tip = ventoy_plugin_get_menu_tip(vtoy_tip_image_file, img->path); + if (tip) + { + img->tip1 = tip->tip1; + img->tip2 = tip->tip2; + } + + img->class = ventoy_plugin_get_menu_class(vtoy_class_image_file, img->name, img->path); + if (!img->class) + { + img->class = g_menu_class[type]; + } + img->menu_prefix = g_menu_prefix[type]; + + if (img_type_iso == type) + { + if (ventoy_plugin_check_memdisk(img->path)) + { + img->menu_prefix = "miso"; + } + } + else if (img_type_img == type) + { + if (ventoy_plugin_check_memdisk(img->path)) + { + img->menu_prefix = "mimg"; + } + } + + debug("Add %s%s to list %d\n", node->dir, filename, g_ventoy_img_count); + } + } + + return 0; +} + +int ventoy_fill_data(grub_uint32_t buflen, char *buffer) +{ + int len = GRUB_UINT_MAX; + const char *value = NULL; + char name[32] = {0}; + char plat[32] = {0}; + char guidstr[32] = {0}; + ventoy_guid guid = VENTOY_GUID; + const char *fmt1 = NULL; + const char *fmt2 = NULL; + const char *fmt3 = NULL; + grub_uint32_t *puint = (grub_uint32_t *)name; + grub_uint32_t *puint2 = (grub_uint32_t *)plat; + const char fmtdata[]={ 0x39, 0x35, 0x25, 0x00, 0x35, 0x00, 0x23, 0x30, 0x30, 0x30, 0x30, 0x66, 0x66, 0x00 }; + const char fmtcode[]={ + 0x22, 0x0A, 0x2B, 0x20, 0x68, 0x62, 0x6F, 0x78, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x74, 0x6F, 0x70, + 0x20, 0x3D, 0x20, 0x25, 0x73, 0x0A, 0x20, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x3D, 0x20, 0x25, + 0x73, 0x0A, 0x20, 0x20, 0x2B, 0x20, 0x6C, 0x61, 0x62, 0x65, 0x6C, 0x20, 0x7B, 0x74, 0x65, 0x78, + 0x74, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x20, 0x25, 0x73, 0x25, 0x73, 0x22, 0x20, 0x63, 0x6F, + 0x6C, 0x6F, 0x72, 0x20, 0x3D, 0x20, 0x22, 0x25, 0x73, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, + 0x20, 0x3D, 0x20, 0x22, 0x6C, 0x65, 0x66, 0x74, 0x22, 0x7D, 0x0A, 0x7D, 0x0A, 0x22, 0x00 + }; + + grub_memset(name, 0, sizeof(name)); + puint[0] = grub_swap_bytes32(0x56454e54); + puint[3] = grub_swap_bytes32(0x4f4e0000); + puint[2] = grub_swap_bytes32(0x45525349); + puint[1] = grub_swap_bytes32(0x4f595f56); + value = ventoy_get_env(name); + + grub_memset(name, 0, sizeof(name)); + puint[1] = grub_swap_bytes32(0x5f544f50); + puint[0] = grub_swap_bytes32(0x56544c45); + fmt1 = ventoy_get_env(name); + if (!fmt1) + { + fmt1 = fmtdata; + } + + grub_memset(name, 0, sizeof(name)); + puint[1] = grub_swap_bytes32(0x5f4c4654); + puint[0] = grub_swap_bytes32(0x56544c45); + fmt2 = ventoy_get_env(name); + + grub_memset(name, 0, sizeof(name)); + puint[1] = grub_swap_bytes32(0x5f434c52); + puint[0] = grub_swap_bytes32(0x56544c45); + fmt3 = ventoy_get_env(name); + + grub_memcpy(guidstr, &guid, sizeof(guid)); + + puint2[0] = grub_swap_bytes32(g_ventoy_plat_data); + + /* Easter egg :) It will be appreciated if you reserve it, but NOT mandatory. */ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wformat-nonliteral" + len = grub_snprintf(buffer, buflen, fmtcode, + fmt1 ? fmt1 : fmtdata, + fmt2 ? fmt2 : fmtdata + 4, + value ? value : "", plat, guidstr, + fmt3 ? fmt3 : fmtdata + 6); + #pragma GCC diagnostic pop + + grub_memset(name, 0, sizeof(name)); + puint[0] = grub_swap_bytes32(0x76746f79); + puint[2] = grub_swap_bytes32(0x656e7365); + puint[1] = grub_swap_bytes32(0x5f6c6963); + ventoy_set_env(name, guidstr); + + return len; +} + +static int +ventoy_password_get (char buf[], unsigned buf_size) +{ + unsigned i, cur_len = 0; + int key; + struct grub_term_coordinate *pos = grub_term_save_pos (); + + while (1) + { + key = grub_getkey (); + if (key == '\n' || key == '\r') + break; + + if (key == GRUB_TERM_ESC) + { + cur_len = 0; + break; + } + + if (key == '\b') + { + if (cur_len) + { + grub_term_restore_pos (pos); + for (i = 0; i < cur_len; i++) + grub_xputs (" "); + grub_term_restore_pos (pos); + cur_len--; + for (i = 0; i < cur_len; i++) + grub_xputs ("*"); + grub_refresh (); + } + continue; + } + + if (!grub_isprint (key)) + continue; + + if (cur_len + 2 < buf_size) + buf[cur_len++] = key; + grub_xputs ("*"); + grub_refresh (); + } + + grub_memset (buf + cur_len, 0, buf_size - cur_len); + + grub_xputs ("\n"); + grub_refresh (); + grub_free (pos); + + return (key != GRUB_TERM_ESC); +} + +static int ventoy_get_password(char buf[], unsigned buf_size) +{ + const char *env = NULL; + + env = grub_env_get("VTOY_SHOW_PASSWORD_ASTERISK"); + if (env && env[0] == '0' && env[1] == 0) + { + return grub_password_get(buf, buf_size); + } + else + { + return ventoy_password_get(buf, buf_size); + } +} + +int ventoy_check_password(const vtoy_password *pwd, int retry) +{ + int offset; + char input[256]; + grub_uint8_t md5[16]; + + while (retry--) + { + grub_memset(input, 0, sizeof(input)); + + grub_printf("Enter password: "); + grub_refresh(); + + if (pwd->type == VTOY_PASSWORD_TXT) + { + ventoy_get_password(input, 128); + if (grub_strcmp(pwd->text, input) == 0) + { + return 0; + } + } + else if (pwd->type == VTOY_PASSWORD_MD5) + { + ventoy_get_password(input, 128); + grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input)); + if (grub_memcmp(pwd->md5, md5, 16) == 0) + { + return 0; + } + } + else if (pwd->type == VTOY_PASSWORD_SALT_MD5) + { + offset = (int)grub_snprintf(input, 128, "%s", pwd->salt); + ventoy_get_password(input + offset, 128); + + grub_crypto_hash(GRUB_MD_MD5, md5, input, grub_strlen(input)); + if (grub_memcmp(pwd->md5, md5, 16) == 0) + { + return 0; + } + } + + grub_printf("Invalid password!\n\n"); + grub_refresh(); + } + + return 1; +} + +static img_info * ventoy_get_min_iso(img_iterator_node *node) +{ + img_info *minimg = NULL; + img_info *img = (img_info *)(node->firstiso); + + while (img && (img_iterator_node *)(img->parent) == node) + { + if (img->select == 0 && (NULL == minimg || ventoy_cmp_img(img, minimg) < 0)) + { + minimg = img; + } + img = img->next; + } + + if (minimg) + { + minimg->select = 1; + } + + return minimg; +} + +static img_iterator_node * ventoy_get_min_child(img_iterator_node *node) +{ + img_iterator_node *Minchild = NULL; + img_iterator_node *child = node->firstchild; + + while (child && child->parent == node) + { + if (child->select == 0 && (NULL == Minchild || ventoy_cmp_subdir(child, Minchild) < 0)) + { + Minchild = child; + } + child = child->next; + } + + if (Minchild) + { + Minchild->select = 1; + } + + return Minchild; +} + +static int ventoy_dynamic_tree_menu(img_iterator_node *node) +{ + int offset = 1; + img_info *img = NULL; + const char *dir_class = NULL; + const char *dir_alias = NULL; + img_iterator_node *child = NULL; + const menu_tip *tip = NULL; + + if (node->isocnt == 0 || node->done == 1) + { + return 0; + } + + if (node->parent && node->parent->dirlen < node->dirlen) + { + offset = node->parent->dirlen; + } + + if (node == &g_img_iterator_head) + { + if (g_default_menu_mode == 0) + { + if (g_tree_view_menu_style == 0) + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "menuentry \"%-10s [%s]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n" + "}\n", "<--", ventoy_get_vmenu_title("VTLANG_RET_TO_LISTVIEW")); + } + else + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "menuentry \"[%s]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n" + "}\n", ventoy_get_vmenu_title("VTLANG_RET_TO_LISTVIEW")); + } + } + + g_tree_script_pre = g_tree_script_pos; + } + else + { + node->dir[node->dirlen - 1] = 0; + dir_class = ventoy_plugin_get_menu_class(vtoy_class_directory, node->dir, node->dir); + if (!dir_class) + { + dir_class = "vtoydir"; + } + + tip = ventoy_plugin_get_menu_tip(vtoy_tip_directory, node->dir); + + dir_alias = ventoy_plugin_get_menu_alias(vtoy_alias_directory, node->dir); + if (dir_alias) + { + if (g_tree_view_menu_style == 0) + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "submenu \"%-10s %s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n", + "DIR", dir_alias, dir_class, node->dir + offset, tip); + } + else + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "submenu \"%s\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n", + dir_alias, dir_class, node->dir + offset, tip); + } + } + else + { + dir_alias = node->dir + offset; + + if (g_tree_view_menu_style == 0) + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "submenu \"%-10s [%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n", + "DIR", dir_alias, dir_class, node->dir + offset, tip); + } + else + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "submenu \"[%s]\" --class=\"%s\" --id=\"DIR_%s\" _VTIP_%p {\n", + dir_alias, dir_class, node->dir + offset, tip); + } + } + + if (g_tree_view_menu_style == 0) + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "menuentry \"%-10s [%s/..]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n" + "}\n", "<--", node->dir); + } + else + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "menuentry \"[%s/..]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n" + "}\n", node->dir); + } + } + + while ((child = ventoy_get_min_child(node)) != NULL) + { + ventoy_dynamic_tree_menu(child); + } + + while ((img = ventoy_get_min_iso(node)) != NULL) + { + if (g_tree_view_menu_style == 0) + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "menuentry \"%-10s %s%s\" --class=\"%s\" --id=\"VID_%p\" {\n" + " %s_%s \n" + "}\n", + grub_get_human_size(img->size, GRUB_HUMAN_SIZE_SHORT), + img->unsupport ? "[***********] " : "", + img->alias ? img->alias : img->name, img->class, img, + img->menu_prefix, + img->unsupport ? "unsupport_menuentry" : "common_menuentry"); + } + else + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, + "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n" + " %s_%s \n" + "}\n", + img->unsupport ? "[***********] " : "", + img->alias ? img->alias : img->name, img->class, img, + img->menu_prefix, + img->unsupport ? "unsupport_menuentry" : "common_menuentry"); + } + } + + if (node != &g_img_iterator_head) + { + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "}\n"); + } + + node->done = 1; + return 0; +} + +static int ventoy_set_default_menu(void) +{ + int img_len = 0; + char *pos = NULL; + char *end = NULL; + char *def = NULL; + const char *strdata = NULL; + img_info *cur = NULL; + img_info *default_node = NULL; + const char *default_image = NULL; + + default_image = ventoy_get_env("VTOY_DEFAULT_IMAGE"); + if (default_image && default_image[0] == '/') + { + img_len = grub_strlen(default_image); + + for (cur = g_ventoy_img_list; cur; cur = cur->next) + { + if (img_len == cur->pathlen && grub_strcmp(default_image, cur->path) == 0) + { + default_node = cur; + break; + } + } + + if (!default_node) + { + return 1; + } + + if (0 == g_default_menu_mode) + { + vtoy_ssprintf(g_list_script_buf, g_list_script_pos, "set default='VID_%p'\n", default_node); + } + else + { + def = grub_strdup(default_image); + if (!def) + { + return 1; + } + + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "set default=%c", '\''); + + strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT"); + if (strdata && strdata[0] == '/') + { + pos = def + grub_strlen(strdata); + if (*pos == '/') + { + pos++; + } + } + else + { + pos = def + 1; + } + + while ((end = grub_strchr(pos, '/')) != NULL) + { + *end = 0; + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "DIR_%s>", pos); + pos = end + 1; + } + + vtoy_ssprintf(g_tree_script_buf, g_tree_script_pos, "VID_%p'\n", default_node); + grub_free(def); + } + } + + return 0; +} + +static grub_err_t ventoy_cmd_clear_img(grub_extcmd_context_t ctxt, int argc, char **args) +{ + img_info *next = NULL; + img_info *cur = g_ventoy_img_list; + + (void)ctxt; + (void)argc; + (void)args; + + while (cur) + { + next = cur->next; + grub_free(cur); + cur = next; + } + + g_ventoy_img_list = NULL; + g_ventoy_img_count = 0; + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_img_name(grub_extcmd_context_t ctxt, int argc, char **args) +{ + long img_id = 0; + img_info *cur = g_ventoy_img_list; + + (void)ctxt; + + if (argc != 2 || (!ventoy_is_decimal(args[0]))) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {imageID} {var}", cmd_raw_name); + } + + img_id = grub_strtol(args[0], NULL, 10); + if (img_id >= g_ventoy_img_count) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images %ld %ld", img_id, g_ventoy_img_count); + } + + debug("Find image %ld name \n", img_id); + + while (cur && img_id > 0) + { + img_id--; + cur = cur->next; + } + + if (!cur) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such many images"); + } + + debug("image name is %s\n", cur->name); + + grub_env_set(args[1], cur->name); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_ext_select_img_path(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int len = 0; + char id[32] = {0}; + img_info *cur = g_ventoy_img_list; + + (void)ctxt; + + if (argc != 1) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name); + } + + len = (int)grub_strlen(args[0]); + + while (cur) + { + if (len == cur->pathlen && 0 == grub_strcmp(args[0], cur->path)) + { + break; + } + cur = cur->next; + } + + if (!cur) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image"); + } + + grub_snprintf(id, sizeof(id), "VID_%p", cur); + grub_env_set("chosen", id); + grub_env_export("chosen"); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static char g_fake_vlnk_src[512]; +static char g_fake_vlnk_dst[512]; +static grub_uint64_t g_fake_vlnk_size; +static grub_err_t ventoy_cmd_set_fake_vlnk(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + g_fake_vlnk_size = (grub_uint64_t)grub_strtoull(args[2], NULL, 10); + + grub_strncpy(g_fake_vlnk_dst, args[0], sizeof(g_fake_vlnk_dst)); + grub_snprintf(g_fake_vlnk_src, sizeof(g_fake_vlnk_src), "%s/________VENTOYVLNK.vlnk.%s", g_iso_path, args[1]); + + grub_file_vtoy_vlnk(g_fake_vlnk_src, g_fake_vlnk_dst); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_reset_fake_vlnk(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + g_fake_vlnk_src[0] = 0; + g_fake_vlnk_dst[0] = 0; + g_fake_vlnk_size = 0; + grub_file_vtoy_vlnk(NULL, NULL); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + + +static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char value[32]; + char *pos = NULL; + char *last = NULL; + const char *id = NULL; + img_info *cur = NULL; + + (void)ctxt; + + if (argc < 1 || argc > 3) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name); + } + + if (g_fake_vlnk_src[0] && g_fake_vlnk_dst[0]) + { + pos = grub_strchr(g_fake_vlnk_src, '/'); + grub_env_set(args[0], pos); + if (argc > 1) + { + grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(g_fake_vlnk_size)); + grub_env_set(args[1], value); + } + + if (argc > 2) + { + for (last = pos; *pos; pos++) + { + if (*pos == '/') + { + last = pos; + } + } + grub_env_set(args[2], last + 1); + } + + goto end; + } + + id = grub_env_get("chosen"); + + pos = grub_strstr(id, "VID_"); + if (pos) + { + cur = (img_info *)(void *)grub_strtoul(pos + 4, NULL, 16); + } + else + { + cur = g_ventoy_img_list; + } + + if (!cur) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "No such image"); + } + + grub_env_set(args[0], cur->path); + + if (argc > 1) + { + grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size)); + grub_env_set(args[1], value); + } + + if (argc > 2) + { + grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size)); + grub_env_set(args[2], cur->name); + } + +end: + g_svd_replace_offset = 0; + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + + +static grub_err_t ventoy_cmd_list_img(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int len; + grub_fs_t fs; + grub_device_t dev = NULL; + img_info *cur = NULL; + img_info *tail = NULL; + img_info *min = NULL; + img_info *head = NULL; + const char *strdata = NULL; + char *device_name = NULL; + char buf[32]; + img_iterator_node *node = NULL; + img_iterator_node *tmp = NULL; + + (void)ctxt; + + if (argc != 2) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {device} {cntvar}", cmd_raw_name); + } + + if (g_ventoy_img_list || g_ventoy_img_count) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Must clear image before list"); + } + + VTOY_CMD_CHECK(1); + + g_enumerate_time_checked = 0; + g_enumerate_start_time_ms = grub_get_time_ms(); + + strdata = ventoy_get_env("VTOY_FILT_DOT_UNDERSCORE_FILE"); + if (strdata && strdata[0] == '1' && strdata[1] == 0) + { + g_filt_dot_underscore_file = 1; + } + + strdata = ventoy_get_env("VTOY_FILT_TRASH_DIR"); + if (strdata && strdata[0] == '0' && strdata[1] == 0) + { + g_filt_trash_dir = 0; + } + + strdata = ventoy_get_env("VTOY_SORT_CASE_SENSITIVE"); + if (strdata && strdata[0] == '1' && strdata[1] == 0) + { + g_sort_case_sensitive = 1; + } + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + goto fail; + } + + g_enum_dev = dev = grub_device_open(device_name); + if (!dev) + { + goto fail; + } + + g_enum_fs = fs = grub_fs_probe(dev); + if (!fs) + { + goto fail; + } + + if (ventoy_get_fs_type(fs->name) >= ventoy_fs_max) + { + debug("unsupported fs:<%s>\n", fs->name); + ventoy_set_env("VTOY_NO_ISO_TIP", "unsupported file system"); + goto fail; + } + + ventoy_set_env("vtoy_iso_fs", fs->name); + + strdata = ventoy_get_env("VTOY_DEFAULT_MENU_MODE"); + if (strdata && strdata[0] == '1') + { + g_default_menu_mode = 1; + } + + grub_memset(&g_img_iterator_head, 0, sizeof(g_img_iterator_head)); + + grub_snprintf(g_iso_path, sizeof(g_iso_path), "%s", args[0]); + + strdata = ventoy_get_env("VTOY_DEFAULT_SEARCH_ROOT"); + if (strdata && strdata[0] == '/') + { + len = grub_snprintf(g_img_iterator_head.dir, sizeof(g_img_iterator_head.dir) - 1, "%s", strdata); + if (g_img_iterator_head.dir[len - 1] != '/') + { + g_img_iterator_head.dir[len++] = '/'; + } + g_img_iterator_head.dirlen = len; + } + else + { + g_img_iterator_head.dirlen = 1; + grub_strcpy(g_img_iterator_head.dir, "/"); + } + + g_img_iterator_head.tail = &tail; + + if (g_img_max_search_level < 0) + { + g_img_max_search_level = GRUB_INT_MAX; + strdata = ventoy_get_env("VTOY_MAX_SEARCH_LEVEL"); + if (strdata && ventoy_is_decimal(strdata)) + { + g_img_max_search_level = (int)grub_strtoul(strdata, NULL, 10); + } + } + + g_vtoy_file_flt[VTOY_FILE_FLT_ISO] = ventoy_control_get_flag("VTOY_FILE_FLT_ISO"); + g_vtoy_file_flt[VTOY_FILE_FLT_WIM] = ventoy_control_get_flag("VTOY_FILE_FLT_WIM"); + g_vtoy_file_flt[VTOY_FILE_FLT_EFI] = ventoy_control_get_flag("VTOY_FILE_FLT_EFI"); + g_vtoy_file_flt[VTOY_FILE_FLT_IMG] = ventoy_control_get_flag("VTOY_FILE_FLT_IMG"); + g_vtoy_file_flt[VTOY_FILE_FLT_VHD] = ventoy_control_get_flag("VTOY_FILE_FLT_VHD"); + g_vtoy_file_flt[VTOY_FILE_FLT_VTOY] = ventoy_control_get_flag("VTOY_FILE_FLT_VTOY"); + + for (node = &g_img_iterator_head; node; node = node->next) + { + fs->fs_dir(dev, node->dir, ventoy_collect_img_files, node); + } + + strdata = ventoy_get_env("VTOY_TREE_VIEW_MENU_STYLE"); + if (strdata && strdata[0] == '1' && strdata[1] == 0) + { + g_tree_view_menu_style = 1; + } + + ventoy_set_default_menu(); + + for (node = &g_img_iterator_head; node; node = node->next) + { + ventoy_dynamic_tree_menu(node); + } + + /* free node */ + node = g_img_iterator_head.next; + while (node) + { + tmp = node->next; + grub_free(node); + node = tmp; + } + + /* sort image list by image name */ + while (g_ventoy_img_list) + { + min = g_ventoy_img_list; + for (cur = g_ventoy_img_list->next; cur; cur = cur->next) + { + if (ventoy_cmp_img(min, cur) > 0) + { + min = cur; + } + } + + if (min->prev) + { + min->prev->next = min->next; + } + + if (min->next) + { + min->next->prev = min->prev; + } + + if (min == g_ventoy_img_list) + { + g_ventoy_img_list = min->next; + } + + if (head == NULL) + { + head = tail = min; + min->prev = NULL; + min->next = NULL; + } + else + { + tail->next = min; + min->prev = tail; + min->next = NULL; + tail = min; + } + } + + g_ventoy_img_list = head; + + if (g_default_menu_mode == 1) + { + vtoy_ssprintf(g_list_script_buf, g_list_script_pos, + "menuentry \"%s [%s]\" --class=\"vtoyret\" VTOY_RET {\n " + " echo 'return ...' \n" + "}\n", "<--", ventoy_get_vmenu_title("VTLANG_RET_TO_TREEVIEW")); + } + + for (cur = g_ventoy_img_list; cur; cur = cur->next) + { + vtoy_ssprintf(g_list_script_buf, g_list_script_pos, + "menuentry \"%s%s\" --class=\"%s\" --id=\"VID_%p\" {\n" + " %s_%s \n" + "}\n", + cur->unsupport ? "[***********] " : "", + cur->alias ? cur->alias : cur->name, cur->class, cur, + cur->menu_prefix, + cur->unsupport ? "unsupport_menuentry" : "common_menuentry"); + } + + g_tree_script_buf[g_tree_script_pos] = 0; + g_list_script_buf[g_list_script_pos] = 0; + + grub_snprintf(buf, sizeof(buf), "%d", g_ventoy_img_count); + grub_env_set(args[1], buf); + +fail: + + check_free(device_name, grub_free); + check_free(dev, grub_device_close); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature) +{ + grub_disk_t disk; + char *device_name; + char *pos; + char *pos2; + + device_name = grub_file_get_device_name(filename); + if (!device_name) + { + return 1; + } + + pos = device_name; + if (pos[0] == '(') + { + pos++; + } + + pos2 = grub_strstr(pos, ","); + if (!pos2) + { + pos2 = grub_strstr(pos, ")"); + } + + if (pos2) + { + *pos2 = 0; + } + + disk = grub_disk_open(pos); + if (disk) + { + grub_disk_read(disk, 0, 0x180, 16, guid); + grub_disk_read(disk, 0, 0x1b8, 4, signature); + grub_disk_close(disk); + } + else + { + return 1; + } + + grub_free(device_name); + return 0; +} + +grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file) +{ + eltorito_descriptor desc; + + grub_memset(&desc, 0, sizeof(desc)); + grub_file_seek(file, 17 * 2048); + grub_file_read(file, &desc, sizeof(desc)); + + if (desc.type != 0 || desc.version != 1) + { + return 0; + } + + if (grub_strncmp((char *)desc.id, "CD001", 5) != 0 || + grub_strncmp((char *)desc.system_id, "EL TORITO SPECIFICATION", 23) != 0) + { + return 0; + } + + return desc.sector; +} + +static grub_uint32_t ventoy_get_bios_eltorito_rba(grub_file_t file, grub_uint32_t sector) +{ + grub_uint8_t buf[512]; + + grub_file_seek(file, sector * 2048); + grub_file_read(file, buf, sizeof(buf)); + + if (buf[0] == 0x01 && buf[1] == 0x00 && + buf[30] == 0x55 && buf[31] == 0xaa && buf[32] == 0x88) + { + return *((grub_uint32_t *)(buf + 40)); + } + + return 0; +} + +int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector) +{ + int i; + int x86count = 0; + grub_uint8_t buf[512]; + grub_uint8_t parttype[] = { 0x04, 0x06, 0x0B, 0x0C }; + + grub_file_seek(file, sector * 2048); + grub_file_read(file, buf, sizeof(buf)); + + if (buf[0] == 0x01 && buf[1] == 0xEF) + { + debug("%s efi eltorito in Validation Entry\n", file->name); + return 1; + } + + if (buf[0] == 0x01 && buf[1] == 0x00) + { + x86count++; + } + + for (i = 64; i < (int)sizeof(buf); i += 32) + { + if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF) + { + debug("%s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]); + return 1; + } + + if ((buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0x00 && x86count == 1) + { + debug("0x9100 assume %s efi eltorito offset %d 0x%02x\n", file->name, i, buf[i]); + return 1; + } + } + + if (x86count && buf[32] == 0x88 && buf[33] == 0x04) + { + for (i = 0; i < (int)(ARRAY_SIZE(parttype)); i++) + { + if (buf[36] == parttype[i]) + { + debug("hard disk image assume %s efi eltorito, part type 0x%x\n", file->name, buf[36]); + return 1; + } + } + } + + debug("%s does not contain efi eltorito\n", file->name); + return 0; +} + +void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param) +{ + char *pos; + const char *fs = NULL; + const char *val = NULL; + const char *cdprompt = NULL; + grub_uint32_t i; + grub_uint8_t chksum = 0; + grub_disk_t disk; + + disk = file->device->disk; + grub_memcpy(¶m->guid, &g_ventoy_guid, sizeof(ventoy_guid)); + + param->vtoy_disk_size = disk->total_sectors * (1 << disk->log_sector_size); + param->vtoy_disk_part_id = disk->partition->number + 1; + param->vtoy_disk_part_type = ventoy_get_fs_type(file->fs->name); + + pos = grub_strstr(file->name, "/"); + if (!pos) + { + pos = file->name; + } + + grub_snprintf(param->vtoy_img_path, sizeof(param->vtoy_img_path), "%s", pos); + + ventoy_get_disk_guid(file->name, param->vtoy_disk_guid, param->vtoy_disk_signature); + + param->vtoy_img_size = file->size; + + param->vtoy_reserved[0] = g_ventoy_break_level; + param->vtoy_reserved[1] = g_ventoy_debug_level; + + param->vtoy_reserved[2] = g_ventoy_chain_type; + + /* Windows CD/DVD prompt 0:suppress 1:reserved */ + param->vtoy_reserved[4] = 0; + if (g_ventoy_chain_type == 1) /* Windows */ + { + cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT"); + if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0) + { + param->vtoy_reserved[4] = 1; + } + } + + fs = ventoy_get_env("ventoy_fs_probe"); + if (fs && grub_strcmp(fs, "udf") == 0) + { + param->vtoy_reserved[3] = 1; + } + + param->vtoy_reserved[5] = 0; + val = ventoy_get_env("VTOY_LINUX_REMOUNT"); + if (val && val[0] == '1' && val[1] == 0) + { + param->vtoy_reserved[5] = 1; + } + + /* ventoy_disk_signature used for vlnk */ + param->vtoy_reserved[6] = file->vlnk; + grub_memcpy(param->vtoy_reserved + 7, g_ventoy_part_info->MBR.BootCode + 0x1b8, 4); + + + /* Windows UEFI force resolution lock */ + if (g_ventoy_chain_type == 1) /* Windows */ + { + val = ventoy_get_env("VTOY_WIN_UEFI_RES_LOCK"); + if (val && val[1] == 0) + { + if (val[0] == '1') + { + param->vtoy_reserved[11] = 1; + } + else if (val[0] == '2') + { + param->vtoy_reserved[11] = 2; + } + } + } + + + /* calculate checksum */ + for (i = 0; i < sizeof(ventoy_os_param); i++) + { + chksum += *((grub_uint8_t *)param + i); + } + param->chksum = (grub_uint8_t)(0x100 - chksum); + + return; +} + +static const char* g_chunk_err_msg[VTOY_CHUNK_ERR_MAX] = +{ + "success", + "File system use more than 1 disks! (maybe RAID)", + "File system enable RAID feature, this is NOT supported!", + "File is compressed in disk, this is not supported!", + "File not flat in disk! (maybe compressed)", + "Read buffer overflow!", +}; + +static const char * ventoy_get_chunk_err_msg(grub_uint32_t err) +{ + if (err < VTOY_CHUNK_ERR_MAX) + { + return g_chunk_err_msg[err]; + } + + return "XXXX"; +} + +int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, +grub_disk_addr_t start, char *err, grub_uint32_t len) +{ + grub_uint32_t i = 0; + grub_uint64_t total = 0; + grub_uint64_t fileblk = 0; + ventoy_img_chunk *chunk = NULL; + + if (chunklist->err_code) + { + if (err) + { + grub_snprintf(err, len, "%s", ventoy_get_chunk_err_msg(chunklist->err_code)); + } + + return 1; + } + + if (err) + { + grub_snprintf(err, len, "Unsupported chunk list."); + } + + for (i = 0; i < chunklist->cur_chunk; i++) + { + chunk = chunklist->chunk + i; + + if (chunk->disk_start_sector <= start) + { + debug("%u disk start invalid %lu\n", i, (ulong)start); + return 1; + } + + total += chunk->disk_end_sector + 1 - chunk->disk_start_sector; + } + + fileblk = (file->size + 511) / 512; + + if (total != fileblk) + { + debug("Invalid total: %llu %llu\n", (ulonglong)total, (ulonglong)fileblk); + if ((file->size % 512) && (total + 1 == fileblk)) + { + debug("maybe img file to be processed.\n"); + return 0; + } + + return 1; + } + + return 0; +} + +int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start) +{ + int fs_type; + int len; + grub_uint32_t i = 0; + grub_uint32_t sector = 0; + grub_uint32_t count = 0; + grub_off_t size = 0; + grub_off_t read = 0; + + fs_type = ventoy_get_fs_type(file->fs->name); + if (fs_type == ventoy_fs_exfat) + { + grub_fat_get_file_chunk(start, file, chunklist); + } + else if (fs_type == ventoy_fs_ext) + { + grub_ext_get_file_chunk(start, file, chunklist); + } + else if (fs_type == ventoy_fs_btrfs) + { + grub_btrfs_get_file_chunk(start, file, chunklist); + } + else + { + file->read_hook = (grub_disk_read_hook_t)(void *)grub_disk_blocklist_read; + file->read_hook_data = chunklist; + + for (size = file->size; size > 0; size -= read) + { + read = (size > VTOY_SIZE_1GB) ? VTOY_SIZE_1GB : size; + grub_file_read(file, NULL, read); + } + + for (i = 0; start > 0 && i < chunklist->cur_chunk; i++) + { + chunklist->chunk[i].disk_start_sector += start; + chunklist->chunk[i].disk_end_sector += start; + } + + if (ventoy_fs_udf == fs_type) + { + for (i = 0; i < chunklist->cur_chunk; i++) + { + count = (chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector) >> 2; + chunklist->chunk[i].img_start_sector = sector; + chunklist->chunk[i].img_end_sector = sector + count - 1; + sector += count; + } + } + } + + len = (int)grub_strlen(file->name); + if ((len > 4 && grub_strncasecmp(file->name + len - 4, ".img", 4) == 0) || + (len > 4 && grub_strncasecmp(file->name + len - 4, ".vhd", 4) == 0) || + (len > 5 && grub_strncasecmp(file->name + len - 5, ".vhdx", 5) == 0) || + (len > 5 && grub_strncasecmp(file->name + len - 5, ".vtoy", 5) == 0)) + { + for (i = 0; i < chunklist->cur_chunk; i++) + { + count = chunklist->chunk[i].disk_end_sector + 1 - chunklist->chunk[i].disk_start_sector; + if (count < 4) + { + count = 1; + } + else + { + count >>= 2; + } + + chunklist->chunk[i].img_start_sector = sector; + chunklist->chunk[i].img_end_sector = sector + count - 1; + sector += count; + } + } + + return 0; +} + +static grub_err_t ventoy_cmd_img_sector(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int rc; + int fs_type; + grub_file_t file; + grub_disk_addr_t start; + char errmsg[128]; + + (void)ctxt; + (void)argc; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]); + } + + g_conf_replace_count = 0; + grub_memset(g_conf_replace_node, 0, sizeof(g_conf_replace_node )); + grub_memset(g_conf_replace_offset, 0, sizeof(g_conf_replace_offset )); + + if (g_img_chunk_list.chunk) + { + grub_free(g_img_chunk_list.chunk); + } + + fs_type = ventoy_get_fs_type(file->fs->name); + if (fs_type >= ventoy_fs_max) + { + grub_file_close(file); + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Unsupported filesystem %s\n", file->fs->name); + } + + /* get image chunk data */ + grub_memset(&g_img_chunk_list, 0, sizeof(g_img_chunk_list)); + g_img_chunk_list.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM); + if (NULL == g_img_chunk_list.chunk) + { + return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n"); + } + + g_img_chunk_list.max_chunk = DEFAULT_CHUNK_NUM; + g_img_chunk_list.cur_chunk = 0; + + start = file->device->disk->partition->start; + + ventoy_get_block_list(file, &g_img_chunk_list, start); + + rc = ventoy_check_block_list(file, &g_img_chunk_list, start, errmsg, sizeof(errmsg)); + grub_file_close(file); + + if (rc) + { + if (fs_type == ventoy_fs_btrfs) + { + vtoy_tip(10, "%s\n\nWill exit in 10 seconds...\n", errmsg); + grub_exit(); + } + return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "%s\n", errmsg); + } + + grub_memset(&g_grub_param->file_replace, 0, sizeof(g_grub_param->file_replace)); + grub_memset(&g_grub_param->img_replace, 0, sizeof(g_grub_param->img_replace)); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_select_conf_replace(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int n; + grub_uint64_t offset = 0; + grub_uint32_t align = 0; + grub_file_t file = NULL; + conf_replace *node = NULL; + conf_replace *nodes[VTOY_MAX_CONF_REPLACE] = { NULL }; + ventoy_grub_param_file_replace *replace = NULL; + + (void)ctxt; + (void)argc; + (void)args; + + debug("select conf replace argc:%d\n", argc); + + if (argc < 2) + { + return 0; + } + + n = ventoy_plugin_find_conf_replace(args[1], nodes); + if (!n) + { + debug("Conf replace not found for %s\n", args[1]); + goto end; + } + + debug("Find %d conf replace for %s\n", n, args[1]); + + g_conf_replace_count = n; + for (i = 0; i < n; i++) + { + node = nodes[i]; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->orgconf); + if (file) + { + offset = grub_iso9660_get_last_file_dirent_pos(file); + grub_file_close(file); + } + else if (node->img > 0) + { + offset = 0; + } + else + { + debug("<(loop)%s> NOT exist\n", node->orgconf); + continue; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->newconf); + if (!file) + { + debug("New config file <%s%s> NOT exist\n", args[0], node->newconf); + continue; + } + + align = ((int)file->size + 2047) / 2048 * 2048; + + if (align > vtoy_max_replace_file_size) + { + debug("New config file <%s%s> too big\n", args[0], node->newconf); + grub_file_close(file); + continue; + } + + grub_file_read(file, g_conf_replace_new_buf[i], file->size); + grub_file_close(file); + g_conf_replace_new_len[i] = (int)file->size; + g_conf_replace_new_len_align[i] = align; + + g_conf_replace_node[i] = node; + g_conf_replace_offset[i] = offset + 2; + + if (node->img > 0) + { + replace = &(g_grub_param->img_replace[i]); + replace->magic = GRUB_IMG_REPLACE_MAGIC; + grub_snprintf(replace->old_file_name[replace->old_name_cnt], 256, "%s", node->orgconf); + replace->old_name_cnt++; + } + + debug("conf_replace OK: newlen[%d]: %d img:%d\n", i, g_conf_replace_new_len[i], node->img); + } + +end: + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_var_expand(int *record, int *flag, const char *var, char *expand, int len) +{ + int i = 0; + int n = 0; + char c; + const char *ch = var; + + *record = 0; + expand[0] = 0; + + while (*ch) + { + if (*ch == '_' || (*ch >= '0' && *ch <= '9') || (*ch >= 'A' && *ch <= 'Z') || (*ch >= 'a' && *ch <= 'z')) + { + ch++; + n++; + } + else + { + debug("Invalid variable letter <%c>\n", *ch); + goto end; + } + } + + if (n > 32) + { + debug("Invalid variable length:%d <%s>\n", n, var); + goto end; + } + + if (grub_strncmp(var, "VT_", 3) == 0) /* built-in variables */ + { + + } + else + { + if (*flag == 0) + { + *flag = 1; + grub_printf("\n=================== Variables Expansion ===================\n\n"); + } + + grub_printf("<%s>: ", var); + grub_refresh(); + + while (i < (len - 1)) + { + c = grub_getkey(); + if ((c == '\n') || (c == '\r')) + { + if (i > 0) + { + grub_printf("\n"); + grub_refresh(); + *record = 1; + break; + } + } + else if (grub_isprint(c)) + { + if (i + 1 < (len - 1)) + { + grub_printf("%c", c); + grub_refresh(); + expand[i++] = c; + expand[i] = 0; + } + } + else if (c == '\b') + { + if (i > 0) + { + expand[i - 1] = ' '; + grub_printf("\r<%s>: %s", var, expand); + + expand[i - 1] = 0; + grub_printf("\r<%s>: %s", var, expand); + + grub_refresh(); + i--; + } + } + } + } + +end: + if (expand[0] == 0) + { + grub_snprintf(expand, len, "$$%s$$", var); + } + + return 0; +} + +static int ventoy_auto_install_var_expand(install_template *node) +{ + int pos = 0; + int flag = 0; + int record = 0; + int newlen = 0; + char *start = NULL; + char *end = NULL; + char *newbuf = NULL; + char *curline = NULL; + char *nextline = NULL; + grub_uint8_t *code = NULL; + char value[512]; + var_node *CurNode = NULL; + var_node *pVarList = NULL; + + code = (grub_uint8_t *)node->filebuf; + + if (node->filelen >= VTOY_SIZE_1MB) + { + debug("auto install script too long %d\n", node->filelen); + return 0; + } + + if ((code[0] == 0xff && code[1] == 0xfe) || (code[0] == 0xfe && code[1] == 0xff)) + { + debug("UCS-2 encoding NOT supported\n"); + return 0; + } + + start = grub_strstr(node->filebuf, "$$"); + if (!start) + { + debug("no need to expand variable, no start.\n"); + return 0; + } + + end = grub_strstr(start + 2, "$$"); + if (!end) + { + debug("no need to expand variable, no end.\n"); + return 0; + } + + newlen = grub_max(node->filelen * 10, VTOY_SIZE_128KB); + newbuf = grub_malloc(newlen); + if (!newbuf) + { + debug("Failed to alloc newbuf %d\n", newlen); + return 0; + } + + for (curline = node->filebuf; curline; curline = nextline) + { + nextline = ventoy_get_line(curline); + + start = grub_strstr(curline, "$$"); + if (start) + { + end = grub_strstr(start + 2, "$$"); + } + + if (start && end) + { + *start = *end = 0; + VTOY_APPEND_NEWBUF(curline); + + for (CurNode = pVarList; CurNode; CurNode = CurNode->next) + { + if (grub_strcmp(start + 2, CurNode->var) == 0) + { + grub_snprintf(value, sizeof(value) - 1, "%s", CurNode->val); + break; + } + } + + if (!CurNode) + { + value[sizeof(value) - 1] = 0; + ventoy_var_expand(&record, &flag, start + 2, value, sizeof(value) - 1); + + if (record) + { + CurNode = grub_zalloc(sizeof(var_node)); + if (CurNode) + { + grub_snprintf(CurNode->var, sizeof(CurNode->var), "%s", start + 2); + grub_snprintf(CurNode->val, sizeof(CurNode->val), "%s", value); + CurNode->next = pVarList; + pVarList = CurNode; + } + } + } + + VTOY_APPEND_NEWBUF(value); + + VTOY_APPEND_NEWBUF(end + 2); + } + else + { + VTOY_APPEND_NEWBUF(curline); + } + + if (pos > 0 && newbuf[pos - 1] == '\r') + { + newbuf[pos - 1] = '\n'; + } + else + { + newbuf[pos++] = '\n'; + } + } + + grub_free(node->filebuf); + node->filebuf = newbuf; + node->filelen = pos; + + while (pVarList) + { + CurNode = pVarList->next; + grub_free(pVarList); + pVarList = CurNode; + } + + return 0; +} + +static grub_err_t ventoy_cmd_sel_auto_install(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i = 0; + int pos = 0; + int defidx = 1; + char *buf = NULL; + grub_file_t file = NULL; + char configfile[128]; + install_template *node = NULL; + + (void)ctxt; + (void)argc; + (void)args; + + debug("select auto installation argc:%d\n", argc); + + if (argc < 1) + { + return 0; + } + + node = ventoy_plugin_find_install_template(args[0]); + if (!node) + { + debug("Auto install template not found for %s\n", args[0]); + return 0; + } + + if (node->autosel >= 0 && node->autosel <= node->templatenum) + { + defidx = node->autosel; + if (node->timeout < 0) + { + node->cursel = node->autosel - 1; + debug("Auto install template auto select %d\n", node->autosel); + goto load; + } + } + + buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF); + if (!buf) + { + return 0; + } + + if (node->timeout > 0) + { + vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout); + } + + vtoy_ssprintf(buf, pos, "menuentry \"$VTLANG_NO_AUTOINS_SCRIPT\" --class=\"sel_auto_install\" {\n" + " echo %s\n}\n", ""); + + for (i = 0; i < node->templatenum; i++) + { + vtoy_ssprintf(buf, pos, "menuentry \"%s %s\" --class=\"sel_auto_install\" {\n" + " echo \"\"\n}\n", + ventoy_get_vmenu_title("VTLANG_AUTOINS_USE"), + node->templatepath[i].path); + } + + g_ventoy_menu_esc = 1; + g_ventoy_suppress_esc = 1; + g_ventoy_suppress_esc_default = defidx; + g_ventoy_secondary_menu_on = 1; + + grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos); + grub_script_execute_sourcecode(configfile); + + g_ventoy_menu_esc = 0; + g_ventoy_suppress_esc = 0; + g_ventoy_suppress_esc_default = 1; + g_ventoy_secondary_menu_on = 0; + + grub_free(buf); + + node->cursel = g_ventoy_last_entry - 1; + +load: + grub_check_free(node->filebuf); + node->filelen = 0; + + if (node->cursel >= 0 && node->cursel < node->templatenum) + { + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ventoy_get_env("vtoy_iso_part"), + node->templatepath[node->cursel].path); + if (file) + { + node->filebuf = grub_malloc(file->size + 8); + if (node->filebuf) + { + grub_file_read(file, node->filebuf, file->size); + grub_file_close(file); + + grub_memset(node->filebuf + file->size, 0, 8); + node->filelen = (int)file->size; + + ventoy_auto_install_var_expand(node); + } + } + else + { + debug("Failed to open auto install script <%s%s>\n", + ventoy_get_env("vtoy_iso_part"), node->templatepath[node->cursel].path); + } + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_sel_persistence(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i = 0; + int pos = 0; + int defidx = 1; + char *buf = NULL; + char configfile[128]; + persistence_config *node; + + (void)ctxt; + (void)argc; + (void)args; + + debug("select persistence argc:%d\n", argc); + + if (argc < 1) + { + return 0; + } + + node = ventoy_plugin_find_persistent(args[0]); + if (!node) + { + debug("Persistence image not found for %s\n", args[0]); + return 0; + } + + if (node->autosel >= 0 && node->autosel <= node->backendnum) + { + defidx = node->autosel; + if (node->timeout < 0) + { + node->cursel = node->autosel - 1; + debug("Persistence image auto select %d\n", node->autosel); + return 0; + } + } + + buf = (char *)grub_malloc(VTOY_MAX_SCRIPT_BUF); + if (!buf) + { + return 0; + } + + if (node->timeout > 0) + { + vtoy_ssprintf(buf, pos, "set timeout=%d\n", node->timeout); + } + + vtoy_ssprintf(buf, pos, "menuentry \"$VTLANG_NO_PERSIST\" --class=\"sel_persistence\" {\n" + " echo %s\n}\n", ""); + + for (i = 0; i < node->backendnum; i++) + { + vtoy_ssprintf(buf, pos, "menuentry \"%s %s\" --class=\"sel_persistence\" {\n" + " echo \"\"\n}\n", + ventoy_get_vmenu_title("VTLANG_PERSIST_USE"), + node->backendpath[i].path); + + } + + g_ventoy_menu_esc = 1; + g_ventoy_suppress_esc = 1; + g_ventoy_suppress_esc_default = defidx; + g_ventoy_secondary_menu_on = 1; + + grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, pos); + grub_script_execute_sourcecode(configfile); + + g_ventoy_menu_esc = 0; + g_ventoy_suppress_esc = 0; + g_ventoy_suppress_esc_default = 1; + g_ventoy_secondary_menu_on = 0; + + grub_free(buf); + + node->cursel = g_ventoy_last_entry - 1; + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_dump_img_sector(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint32_t i; + ventoy_img_chunk *cur; + + (void)ctxt; + (void)argc; + (void)args; + + for (i = 0; i < g_img_chunk_list.cur_chunk; i++) + { + cur = g_img_chunk_list.chunk + i; + grub_printf("image:[%u - %u] <==> disk:[%llu - %llu]\n", + cur->img_start_sector, cur->img_end_sector, + (unsigned long long)cur->disk_start_sector, (unsigned long long)cur->disk_end_sector + ); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_test_block_list(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint32_t i; + grub_file_t file; + ventoy_img_chunk_list chunklist; + char errmsg[128]; + + (void)ctxt; + (void)argc; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]); + } + + /* get image chunk data */ + grub_memset(&chunklist, 0, sizeof(chunklist)); + chunklist.chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM); + if (NULL == chunklist.chunk) + { + return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n"); + } + + chunklist.max_chunk = DEFAULT_CHUNK_NUM; + chunklist.cur_chunk = 0; + + ventoy_get_block_list(file, &chunklist, 0); + + if (0 != ventoy_check_block_list(file, &chunklist, 0, errmsg, sizeof(errmsg))) + { + grub_printf("%s\n", errmsg); + grub_printf("########## UNSUPPORTED ###############\n"); + } + + grub_printf("filesystem: <%s> entry number:<%u>\n", file->fs->name, chunklist.cur_chunk); + + for (i = 0; i < chunklist.cur_chunk; i++) + { + grub_printf("%llu+%llu,", (ulonglong)chunklist.chunk[i].disk_start_sector, + (ulonglong)(chunklist.chunk[i].disk_end_sector + 1 - chunklist.chunk[i].disk_start_sector)); + } + + grub_printf("\n==================================\n"); + + for (i = 0; i < chunklist.cur_chunk; i++) + { + grub_printf("%2u: [%llu %llu] - [%llu %llu]\n", i, + (ulonglong)chunklist.chunk[i].img_start_sector, + (ulonglong)chunklist.chunk[i].img_end_sector, + (ulonglong)chunklist.chunk[i].disk_start_sector, + (ulonglong)chunklist.chunk[i].disk_end_sector + ); + } + + grub_free(chunklist.chunk); + grub_file_close(file); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_add_replace_file(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + ventoy_grub_param_file_replace *replace = NULL; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc >= 2) + { + replace = &(g_grub_param->file_replace); + replace->magic = GRUB_FILE_REPLACE_MAGIC; + + replace->old_name_cnt = 0; + for (i = 0; i < 4 && i + 1 < argc; i++) + { + replace->old_name_cnt++; + grub_snprintf(replace->old_file_name[i], sizeof(replace->old_file_name[i]), "%s", args[i + 1]); + } + + replace->new_file_virtual_id = (grub_uint32_t)grub_strtoul(args[0], NULL, 10); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_get_replace_file_cnt(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char buf[32]; + ventoy_grub_param_file_replace *replace = &(g_grub_param->file_replace); + + (void)ctxt; + + if (argc >= 1) + { + grub_snprintf(buf, sizeof(buf), "%u", replace->old_name_cnt); + grub_env_set(args[0], buf); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_dump_menu(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + if (argc == 0) + { + grub_printf("List Mode: CurLen:%d MaxLen:%u\n", g_list_script_pos, VTOY_MAX_SCRIPT_BUF); + grub_printf("%s", g_list_script_buf); + } + else + { + grub_printf("Tree Mode: CurLen:%d MaxLen:%u\n", g_tree_script_pos, VTOY_MAX_SCRIPT_BUF); + grub_printf("%s", g_tree_script_buf); + } + + return 0; +} + +static grub_err_t ventoy_cmd_dump_img_list(grub_extcmd_context_t ctxt, int argc, char **args) +{ + img_info *cur = g_ventoy_img_list; + + (void)ctxt; + (void)argc; + (void)args; + + while (cur) + { + grub_printf("path:<%s> id=%d list_index=%d\n", cur->path, cur->id, cur->plugin_list_index); + grub_printf("name:<%s>\n\n", cur->name); + cur = cur->next; + } + + return 0; +} + +static grub_err_t ventoy_cmd_dump_injection(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + ventoy_plugin_dump_injection(); + + return 0; +} + +static grub_err_t ventoy_cmd_dump_auto_install(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + ventoy_plugin_dump_auto_install(); + + return 0; +} + +static grub_err_t ventoy_cmd_dump_persistence(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + ventoy_plugin_dump_persistence(); + + return 0; +} + +static int ventoy_check_mode_by_name(char *filename, const char *suffix) +{ + int i; + int len1; + int len2; + + len1 = (int)grub_strlen(filename); + len2 = (int)grub_strlen(suffix); + + if (len1 <= len2) + { + return 0; + } + + for (i = len1 - 1; i >= 0; i--) + { + if (filename[i] == '.') + { + break; + } + } + + if (i < len2 + 1) + { + return 0; + } + + if (filename[i - len2 - 1] != '_') + { + return 0; + } + + if (grub_strncasecmp(filename + (i - len2), suffix, len2) == 0) + { + return 1; + } + + return 0; +} + +static grub_err_t ventoy_cmd_check_mode(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + if (argc != 1 && argc != 2) + { + return 1; + } + + if (args[0][0] == '0') + { + if (g_ventoy_memdisk_mode) + { + return 0; + } + + if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtmemdisk")) + { + return 0; + } + + return 1; + } + else if (args[0][0] == '1') + { + if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtcompat")) + { + return 0; + } + + return g_ventoy_iso_raw ? 0 : 1; + } + else if (args[0][0] == '2') + { + return g_ventoy_iso_uefi_drv ? 0 : 1; + } + else if (args[0][0] == '3') + { + if (g_ventoy_grub2_mode) + { + return 0; + } + + if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtgrub2")) + { + return 0; + } + + return 1; + } + else if (args[0][0] == '4') + { + if (g_ventoy_wimboot_mode) + { + return 0; + } + + if (argc == 2 && ventoy_check_mode_by_name(args[1], "vtwimboot")) + { + return 0; + } + + return 1; + } + + return 1; +} + +static grub_err_t ventoy_cmd_dynamic_menu(grub_extcmd_context_t ctxt, int argc, char **args) +{ + static int configfile_mode = 0; + char memfile[128] = {0}; + + (void)ctxt; + (void)argc; + (void)args; + + /* + * args[0]: 0:normal 1:configfile + * args[1]: 0:list_buf 1:tree_buf + */ + + if (argc != 2) + { + debug("Invalid argc %d\n", argc); + return 0; + } + + VTOY_CMD_CHECK(1); + + if (args[0][0] == '0') + { + if (args[1][0] == '0') + { + grub_script_execute_sourcecode(g_list_script_buf); + } + else + { + grub_script_execute_sourcecode(g_tree_script_buf); + } + } + else + { + if (configfile_mode) + { + debug("Now already in F3 mode %d\n", configfile_mode); + return 0; + } + + if (args[1][0] == '0') + { + grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d", + (ulonglong)(ulong)g_list_script_buf, g_list_script_pos); + } + else + { + g_ventoy_last_entry = -1; + grub_snprintf(memfile, sizeof(memfile), "configfile mem:0x%llx:size:%d", + (ulonglong)(ulong)g_tree_script_buf, g_tree_script_pos); + } + + configfile_mode = 1; + grub_script_execute_sourcecode(memfile); + configfile_mode = 0; + } + + return 0; +} + +static grub_err_t ventoy_cmd_file_exist_nocase(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_file_t file; + + (void)ctxt; + + if (argc != 1) + { + return 1; + } + + g_ventoy_case_insensitive = 1; + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + g_ventoy_case_insensitive = 0; + + grub_errno = 0; + + if (file) + { + grub_file_close(file); + return 0; + } + return 1; +} + +static grub_err_t ventoy_cmd_find_bootable_hdd(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int id = 0; + int find = 0; + grub_disk_t disk; + const char *isopath = NULL; + char hdname[32]; + ventoy_mbr_head mbr; + + (void)ctxt; + (void)argc; + + if (argc != 1) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s variable\n", cmd_raw_name); + } + + isopath = grub_env_get("vtoy_iso_part"); + if (!isopath) + { + debug("isopath is null %p\n", isopath); + return 0; + } + + debug("isopath is %s\n", isopath); + + for (id = 0; id < 30 && (find == 0); id++) + { + grub_snprintf(hdname, sizeof(hdname), "hd%d,", id); + if (grub_strstr(isopath, hdname)) + { + debug("skip %s ...\n", hdname); + continue; + } + + grub_snprintf(hdname, sizeof(hdname), "hd%d", id); + + disk = grub_disk_open(hdname); + if (!disk) + { + debug("%s not exist\n", hdname); + break; + } + + grub_memset(&mbr, 0, sizeof(mbr)); + if (0 == grub_disk_read(disk, 0, 0, 512, &mbr)) + { + if (mbr.Byte55 == 0x55 && mbr.ByteAA == 0xAA) + { + if (mbr.PartTbl[0].Active == 0x80 || mbr.PartTbl[1].Active == 0x80 || + mbr.PartTbl[2].Active == 0x80 || mbr.PartTbl[3].Active == 0x80) + { + + grub_env_set(args[0], hdname); + find = 1; + } + } + debug("%s is %s\n", hdname, find ? "bootable" : "NOT bootable"); + } + else + { + debug("read %s failed\n", hdname); + } + + grub_disk_close(disk); + } + + return 0; +} + +static grub_err_t ventoy_cmd_read_1st_line(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int len = 1024; + grub_file_t file; + char *buf = NULL; + + (void)ctxt; + (void)argc; + + if (argc != 2) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file var \n", cmd_raw_name); + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + debug("failed to open file %s\n", args[0]); + return 0; + } + + buf = grub_malloc(len); + if (!buf) + { + goto end; + } + + buf[len - 1] = 0; + grub_file_read(file, buf, len - 1); + + ventoy_get_line(buf); + ventoy_set_env(args[1], buf); + +end: + + grub_check_free(buf); + grub_file_close(file); + + return 0; +} + +static int ventoy_img_partition_callback (struct grub_disk *disk, const grub_partition_t partition, void *data) +{ + grub_uint64_t end_max = 0; + int *pCnt = (int *)data; + + (void)disk; + + (*pCnt)++; + g_part_list_pos += grub_snprintf(g_part_list_buf + g_part_list_pos, VTOY_MAX_SCRIPT_BUF - g_part_list_pos, + "0 %llu linear /dev/ventoy %llu\n", + (ulonglong)partition->len, (ulonglong)partition->start); + + end_max = (partition->len + partition->start) * 512; + if (end_max > g_part_end_max) + { + g_part_end_max = end_max; + } + + return 0; +} + +static grub_err_t ventoy_cmd_img_part_info(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int cnt = 0; + char *device_name = NULL; + grub_device_t dev = NULL; + char buf[64]; + + (void)ctxt; + + g_part_list_pos = 0; + g_part_end_max = 0; + grub_env_unset("vtoy_img_part_file"); + + if (argc != 1) + { + return 1; + } + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + debug("ventoy_cmd_img_part_info failed, %s\n", args[0]); + goto end; + } + + dev = grub_device_open(device_name); + if (!dev) + { + debug("grub_device_open failed, %s\n", device_name); + goto end; + } + + grub_partition_iterate(dev->disk, ventoy_img_partition_callback, &cnt); + + grub_snprintf(buf, sizeof(buf), "newc:vtoy_dm_table:mem:0x%llx:size:%d", (ulonglong)(ulong)g_part_list_buf, g_part_list_pos); + grub_env_set("vtoy_img_part_file", buf); + + grub_snprintf(buf, sizeof(buf), "%d", cnt); + grub_env_set("vtoy_img_part_cnt", buf); + + grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)g_part_end_max); + grub_env_set("vtoy_img_max_part_end", buf); + +end: + + check_free(device_name, grub_free); + check_free(dev, grub_device_close); + + return 0; +} + + +static grub_err_t ventoy_cmd_file_strstr(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int rc = 1; + grub_file_t file; + char *buf = NULL; + + (void)ctxt; + (void)argc; + + if (argc != 2) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s file str \n", cmd_raw_name); + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + debug("failed to open file %s\n", args[0]); + return 1; + } + + buf = grub_malloc(file->size + 1); + if (!buf) + { + goto end; + } + + buf[file->size] = 0; + grub_file_read(file, buf, file->size); + + if (grub_strstr(buf, args[1])) + { + rc = 0; + } + +end: + + grub_check_free(buf); + grub_file_close(file); + + return rc; +} + +static grub_err_t ventoy_cmd_parse_volume(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int len; + grub_file_t file; + char buf[64]; + grub_uint64_t size; + ventoy_iso9660_vd pvd; + + (void)ctxt; + (void)argc; + + if (argc != 4) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s sysid volid space \n", cmd_raw_name); + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + debug("failed to open file %s\n", args[0]); + return 0; + } + + grub_file_seek(file, 16 * 2048); + len = (int)grub_file_read(file, &pvd, sizeof(pvd)); + if (len != sizeof(pvd)) + { + debug("failed to read pvd %d\n", len); + goto end; + } + + grub_memset(buf, 0, sizeof(buf)); + grub_memcpy(buf, pvd.sys, sizeof(pvd.sys)); + ventoy_set_env(args[1], buf); + + grub_memset(buf, 0, sizeof(buf)); + grub_memcpy(buf, pvd.vol, sizeof(pvd.vol)); + ventoy_set_env(args[2], buf); + + size = pvd.space; + size *= 2048; + grub_snprintf(buf, sizeof(buf), "%llu", (ulonglong)size); + ventoy_set_env(args[3], buf); + +end: + grub_file_close(file); + + return 0; +} + +static grub_err_t ventoy_cmd_parse_create_date(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int len; + grub_file_t file; + char buf[64]; + + (void)ctxt; + (void)argc; + + if (argc != 2) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s var \n", cmd_raw_name); + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + debug("failed to open file %s\n", args[0]); + return 0; + } + + grub_memset(buf, 0, sizeof(buf)); + grub_file_seek(file, 16 * 2048 + 813); + len = (int)grub_file_read(file, buf, 17); + if (len != 17) + { + debug("failed to read create date %d\n", len); + goto end; + } + + ventoy_set_env(args[1], buf); + +end: + grub_file_close(file); + + return 0; +} + +static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + ventoy_env_hook_root(1); + + return 0; +} + +static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + ventoy_env_hook_root(0); + + return 0; +} + +#ifdef GRUB_MACHINE_EFI +static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + return g_sys_sb ? 0 : 1; +} +#else +static grub_err_t ventoy_cmd_check_secureboot_var(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + return 1; +} +#endif + +static grub_err_t ventoy_cmd_img_check_range(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int ret = 1; + grub_file_t file; + grub_uint64_t FileSectors = 0; + ventoy_gpt_info *gpt = NULL; + ventoy_part_table *pt = NULL; + grub_uint8_t zeroguid[16] = {0}; + + (void)ctxt; + (void)argc; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + debug("failed to open file %s\n", args[0]); + return 1; + } + + if (file->size % 512) + { + debug("unaligned file size: %llu\n", (ulonglong)file->size); + goto out; + } + + gpt = grub_zalloc(sizeof(ventoy_gpt_info)); + if (!gpt) + { + goto out; + } + + FileSectors = file->size / 512; + + grub_file_read(file, gpt, sizeof(ventoy_gpt_info)); + if (grub_strncmp(gpt->Head.Signature, "EFI PART", 8) == 0) + { + debug("This is EFI partition table\n"); + + for (i = 0; i < 128; i++) + { + if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16)) + { + if (FileSectors < gpt->PartTbl[i].LastLBA) + { + debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i, + (ulonglong)gpt->PartTbl[i].LastLBA, (ulonglong)FileSectors); + goto out; + } + } + } + } + else + { + debug("This is MBR partition table\n"); + + for (i = 0; i < 4; i++) + { + pt = gpt->MBR.PartTbl + i; + if (FileSectors < pt->StartSectorId + pt->SectorCount) + { + debug("out of range: part[%d] LastLBA:%llu FileSectors:%llu\n", i, + (ulonglong)(pt->StartSectorId + pt->SectorCount), + (ulonglong)FileSectors); + goto out; + } + } + } + + ret = 0; + +out: + grub_file_close(file); + grub_check_free(gpt); + grub_errno = GRUB_ERR_NONE; + return ret; +} + +static grub_err_t ventoy_cmd_clear_key(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int ret; + + (void)ctxt; + (void)argc; + (void)args; + + for (i = 0; i < 500; i++) + { + ret = grub_getkey_noblock(); + if (ret == GRUB_TERM_NO_KEY) + { + break; + } + } + + if (i >= 500) + { + grub_cls(); + grub_printf("\n\n Still have key input after clear.\n"); + grub_refresh(); + grub_sleep(5); + } + + return 0; +} + +static grub_err_t ventoy_cmd_acpi_param(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int buflen; + int datalen; + int loclen; + int img_chunk_num; + int image_sector_size; + char cmd[64]; + ventoy_chain_head *chain; + ventoy_img_chunk *chunk; + ventoy_os_param *osparam; + ventoy_image_location *location; + ventoy_image_disk_region *region; + struct grub_acpi_table_header *acpi; + + (void)ctxt; + + if (argc != 2) + { + return 1; + } + + debug("ventoy_cmd_acpi_param %s %s\n", args[0], args[1]); + + chain = (ventoy_chain_head *)(ulong)grub_strtoul(args[0], NULL, 16); + if (!chain) + { + return 1; + } + + image_sector_size = (int)grub_strtol(args[1], NULL, 10); + + if (grub_memcmp(&g_ventoy_guid, &(chain->os_param.guid), 16)) + { + debug("Invalid ventoy guid 0x%x\n", chain->os_param.guid.data1); + return 1; + } + + img_chunk_num = chain->img_chunk_num; + + loclen = sizeof(ventoy_image_location) + (img_chunk_num - 1) * sizeof(ventoy_image_disk_region); + datalen = sizeof(ventoy_os_param) + loclen; + + buflen = sizeof(struct grub_acpi_table_header) + datalen; + acpi = grub_zalloc(buflen); + if (!acpi) + { + return 1; + } + + /* Step1: Fill acpi table header */ + grub_memcpy(acpi->signature, "VTOY", 4); + acpi->length = buflen; + acpi->revision = 1; + grub_memcpy(acpi->oemid, "VENTOY", 6); + grub_memcpy(acpi->oemtable, "OSPARAMS", 8); + acpi->oemrev = 1; + acpi->creator_id[0] = 1; + acpi->creator_rev = 1; + + /* Step2: Fill data */ + osparam = (ventoy_os_param *)(acpi + 1); + grub_memcpy(osparam, &chain->os_param, sizeof(ventoy_os_param)); + osparam->vtoy_img_location_addr = 0; + osparam->vtoy_img_location_len = loclen; + osparam->chksum = 0; + osparam->chksum = 0x100 - grub_byte_checksum(osparam, sizeof(ventoy_os_param)); + + location = (ventoy_image_location *)(osparam + 1); + grub_memcpy(&location->guid, &osparam->guid, sizeof(ventoy_guid)); + location->image_sector_size = image_sector_size; + location->disk_sector_size = chain->disk_sector_size; + location->region_count = img_chunk_num; + + region = location->regions; + chunk = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset); + if (512 == image_sector_size) + { + for (i = 0; i < img_chunk_num; i++) + { + region->image_sector_count = chunk->disk_end_sector - chunk->disk_start_sector + 1; + region->image_start_sector = chunk->img_start_sector * 4; + region->disk_start_sector = chunk->disk_start_sector; + region++; + chunk++; + } + } + else + { + for (i = 0; i < img_chunk_num; i++) + { + region->image_sector_count = chunk->img_end_sector - chunk->img_start_sector + 1; + region->image_start_sector = chunk->img_start_sector; + region->disk_start_sector = chunk->disk_start_sector; + region++; + chunk++; + } + } + + /* Step3: Fill acpi checksum */ + acpi->checksum = 0; + acpi->checksum = 0x100 - grub_byte_checksum(acpi, acpi->length); + + /* load acpi table */ + grub_snprintf(cmd, sizeof(cmd), "acpi mem:0x%lx:size:%d", (ulong)acpi, acpi->length); + grub_script_execute_sourcecode(cmd); + + grub_free(acpi); + + VENTOY_CMD_RETURN(0); +} + +static grub_err_t ventoy_cmd_push_last_entry(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + g_ventoy_last_entry_back = g_ventoy_last_entry; + g_ventoy_last_entry = -1; + + return 0; +} + +static grub_err_t ventoy_cmd_pop_last_entry(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + g_ventoy_last_entry = g_ventoy_last_entry_back; + + return 0; +} + +static int ventoy_lib_module_callback(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + const char *pos = filename + 1; + + if (info->dir) + { + while (*pos) + { + if (*pos == '.') + { + if ((*(pos - 1) >= '0' && *(pos - 1) <= '9') && (*(pos + 1) >= '0' && *(pos + 1) <= '9')) + { + grub_strncpy((char *)data, filename, 128); + return 1; + } + } + pos++; + } + } + + return 0; +} + +static grub_err_t ventoy_cmd_lib_module_ver(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int rc = 1; + char *device_name = NULL; + grub_device_t dev = NULL; + grub_fs_t fs = NULL; + char buf[128] = {0}; + + (void)ctxt; + + if (argc != 3) + { + debug("ventoy_cmd_lib_module_ver, invalid param num %d\n", argc); + return 1; + } + + debug("ventoy_cmd_lib_module_ver %s %s %s\n", args[0], args[1], args[2]); + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + debug("grub_file_get_device_name failed, %s\n", args[0]); + goto end; + } + + dev = grub_device_open(device_name); + if (!dev) + { + debug("grub_device_open failed, %s\n", device_name); + goto end; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + debug("grub_fs_probe failed, %s\n", device_name); + goto end; + } + + fs->fs_dir(dev, args[1], ventoy_lib_module_callback, buf); + + if (buf[0]) + { + ventoy_set_env(args[2], buf); + } + + rc = 0; + +end: + + check_free(device_name, grub_free); + check_free(dev, grub_device_close); + + return rc; +} + +int ventoy_load_part_table(const char *diskname) +{ + char name[64]; + int ret; + grub_disk_t disk; + grub_device_t dev; + + g_ventoy_part_info = grub_zalloc(sizeof(ventoy_gpt_info)); + if (!g_ventoy_part_info) + { + return 1; + } + + disk = grub_disk_open(diskname); + if (!disk) + { + debug("Failed to open disk %s\n", diskname); + return 1; + } + + g_ventoy_disk_size = disk->total_sectors * (1U << disk->log_sector_size); + + g_ventoy_disk_bios_id = disk->id; + + grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), g_ventoy_part_info); + grub_disk_close(disk); + + grub_snprintf(name, sizeof(name), "%s,1", diskname); + dev = grub_device_open(name); + if (dev) + { + /* Check for official Ventoy device */ + ret = ventoy_check_official_device(dev); + grub_device_close(dev); + + if (ret) + { + return 1; + } + } + + g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0); + g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1); + + return 0; +} + +void ventoy_prompt_end(void) +{ + int op = 0; + char c; + + grub_printf("\n\n\n"); + grub_printf(" 1 --- Exit grub\n"); + grub_printf(" 2 --- Reboot\n"); + grub_printf(" 3 --- Shut down\n"); + grub_printf("Please enter your choice: "); + grub_refresh(); + + while (1) + { + c = grub_getkey(); + if (c >= '1' && c <= '3') + { + if (op == 0) + { + op = c - '0'; + grub_printf("%c", c); + grub_refresh(); + } + } + else if (c == '\r' || c == '\n') + { + if (op) + { + if (op == 1) + { + grub_exit(); + } + else if (op == 2) + { + grub_reboot(); + } + else if (op == 3) + { + grub_script_execute_sourcecode("halt"); + } + } + } + else if (c == '\b') + { + if (op) + { + op = 0; + grub_printf("\rPlease enter your choice: "); + grub_printf("\rPlease enter your choice: "); + grub_refresh(); + } + } + } +} + +static grub_err_t ventoy_cmd_load_part_table(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret; + + (void)argc; + (void)ctxt; + + ret = ventoy_load_part_table(args[0]); + if (ret) + { + ventoy_prompt_end(); + } + + g_ventoy_disk_part_size[0] = ventoy_get_vtoy_partsize(0); + g_ventoy_disk_part_size[1] = ventoy_get_vtoy_partsize(1); + + return 0; +} + +static grub_err_t ventoy_cmd_check_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret = 1; + const char *vcfg = NULL; + + (void)argc; + (void)ctxt; + + vcfg = ventoy_plugin_get_custom_boot(args[0]); + if (vcfg) + { + debug("custom boot <%s>:<%s>\n", args[0], vcfg); + grub_env_set(args[1], vcfg); + ret = 0; + } + else + { + debug("custom boot <%s>:\n", args[0]); + } + + grub_errno = 0; + return ret; +} + + +static grub_err_t ventoy_cmd_part_exist(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int id; + grub_uint8_t zeroguid[16] = {0}; + + (void)argc; + (void)ctxt; + + id = (int)grub_strtoul(args[0], NULL, 10); + grub_errno = 0; + + if (grub_memcmp(g_ventoy_part_info->Head.Signature, "EFI PART", 8) == 0) + { + if (id >= 1 && id <= 128) + { + if (grub_memcmp(g_ventoy_part_info->PartTbl[id - 1].PartGuid, zeroguid, 16)) + { + return 0; + } + } + } + else + { + if (id >= 1 && id <= 4) + { + if (g_ventoy_part_info->MBR.PartTbl[id - 1].FsFlag) + { + return 0; + } + } + } + + return 1; +} + +static grub_err_t ventoy_cmd_get_fs_label(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int rc = 1; + char *device_name = NULL; + grub_device_t dev = NULL; + grub_fs_t fs = NULL; + char *label = NULL; + + (void)ctxt; + + debug("get fs label for %s\n", args[0]); + + if (argc != 2) + { + debug("ventoy_cmd_get_fs_label, invalid param num %d\n", argc); + return 1; + } + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + debug("grub_file_get_device_name failed, %s\n", args[0]); + goto end; + } + + dev = grub_device_open(device_name); + if (!dev) + { + debug("grub_device_open failed, %s\n", device_name); + goto end; + } + + fs = grub_fs_probe(dev); + if (NULL == fs || NULL == fs->fs_label) + { + debug("grub_fs_probe failed, %s %p %p\n", device_name, fs, fs->fs_label); + goto end; + } + + fs->fs_label(dev, &label); + if (label) + { + debug("label=<%s>\n", label); + ventoy_set_env(args[1], label); + grub_free(label); + } + + rc = 0; + +end: + + check_free(device_name, grub_free); + check_free(dev, grub_device_close); + + return rc; +} + +static int ventoy_fs_enum_1st_file(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + if (!info->dir) + { + grub_snprintf((char *)data, 256, "%s", filename); + return 1; + } + + return 0; +} + +static int ventoy_fs_enum_1st_dir(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + if (info->dir && filename && filename[0] != '.') + { + grub_snprintf((char *)data, 256, "%s", filename); + return 1; + } + + return 0; +} + +static grub_err_t ventoy_fs_enum_1st_child(int argc, char **args, grub_fs_dir_hook_t hook) +{ + int rc = 1; + char *device_name = NULL; + grub_device_t dev = NULL; + grub_fs_t fs = NULL; + char name[256] ={0}; + + if (argc != 3) + { + debug("ventoy_fs_enum_1st_child, invalid param num %d\n", argc); + return 1; + } + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + debug("grub_file_get_device_name failed, %s\n", args[0]); + goto end; + } + + dev = grub_device_open(device_name); + if (!dev) + { + debug("grub_device_open failed, %s\n", device_name); + goto end; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + debug("grub_fs_probe failed, %s\n", device_name); + goto end; + } + + fs->fs_dir(dev, args[1], hook, name); + if (name[0]) + { + ventoy_set_env(args[2], name); + } + + rc = 0; + +end: + + check_free(device_name, grub_free); + check_free(dev, grub_device_close); + + return rc; +} + +static grub_err_t ventoy_cmd_fs_enum_1st_file(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_file); +} + +static grub_err_t ventoy_cmd_fs_enum_1st_dir(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + return ventoy_fs_enum_1st_child(argc, args, ventoy_fs_enum_1st_dir); +} + +static grub_err_t ventoy_cmd_basename(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char c; + char *pos = NULL; + char *end = NULL; + + (void)ctxt; + + if (argc != 2) + { + debug("ventoy_cmd_basename, invalid param num %d\n", argc); + return 1; + } + + for (pos = args[0]; *pos; pos++) + { + if (*pos == '.') + { + end = pos; + } + } + + if (end) + { + c = *end; + *end = 0; + } + + grub_env_set(args[1], args[0]); + + if (end) + { + *end = c; + } + + return 0; +} + +static grub_err_t ventoy_cmd_basefile(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int len; + const char *buf; + + (void)ctxt; + + if (argc != 2) + { + debug("ventoy_cmd_basefile, invalid param num %d\n", argc); + return 1; + } + + buf = args[0]; + len = (int)grub_strlen(buf); + for (i = len; i > 0; i--) + { + if (buf[i - 1] == '/') + { + grub_env_set(args[1], buf + i); + return 0; + } + } + + grub_env_set(args[1], buf); + + return 0; +} + +static grub_err_t ventoy_cmd_enum_video_mode(grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_video_mode_info info; + char buf[32]; + + (void)ctxt; + (void)argc; + (void)args; + + if (!g_video_mode_list) + { + ventoy_enum_video_mode(); + } + + if (grub_video_get_info(&info) == GRUB_ERR_NONE) + { + grub_snprintf(buf, sizeof(buf), "Resolution (%ux%u)", info.width, info.height); + } + else + { + grub_snprintf(buf, sizeof(buf), "Resolution (0x0)"); + } + + grub_env_set("VTOY_CUR_VIDEO_MODE", buf); + + grub_snprintf(buf, sizeof(buf), "%d", g_video_mode_num); + grub_env_set("VTOY_VIDEO_MODE_NUM", buf); + + VENTOY_CMD_RETURN(0); +} + +static grub_err_t vt_cmd_update_cur_video_mode(grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_video_mode_info info; + char buf[32]; + + (void)ctxt; + (void)argc; + (void)args; + + if (grub_video_get_info(&info) == GRUB_ERR_NONE) + { + grub_snprintf(buf, sizeof(buf), "%ux%ux%u", info.width, info.height, info.bpp); + } + else + { + grub_snprintf(buf, sizeof(buf), "0x0x0"); + } + + grub_env_set(args[0], buf); + + VENTOY_CMD_RETURN(0); +} + +static grub_err_t ventoy_cmd_get_video_mode(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int id; + char buf[32]; + + (void)ctxt; + (void)argc; + + if (!g_video_mode_list) + { + return 0; + } + + id = (int)grub_strtoul(args[0], NULL, 10); + if (id < g_video_mode_num) + { + grub_snprintf(buf, sizeof(buf), "%ux%ux%u", + g_video_mode_list[id].width, g_video_mode_list[id].height, g_video_mode_list[id].bpp); + } + + grub_env_set(args[1], buf); + + VENTOY_CMD_RETURN(0); +} + +static grub_err_t ventoy_cmd_get_efivdisk_offset(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint32_t i; + grub_uint32_t loadsector = 0; + grub_file_t file; + char value[32]; + grub_uint32_t boot_catlog = 0; + grub_uint8_t buf[512]; + + (void)ctxt; + + if (argc != 2) + { + debug("ventoy_cmd_get_efivdisk_offset, invalid param num %d\n", argc); + return 1; + } + + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (!file) + { + debug("failed to open %s\n", args[0]); + return 1; + } + + boot_catlog = ventoy_get_iso_boot_catlog(file); + if (boot_catlog == 0) + { + debug("No bootcatlog found\n"); + grub_file_close(file); + return 1; + } + + grub_memset(buf, 0, sizeof(buf)); + grub_file_seek(file, boot_catlog * 2048); + grub_file_read(file, buf, sizeof(buf)); + grub_file_close(file); + + for (i = 0; i < sizeof(buf); i += 32) + { + if ((buf[i] == 0 || buf[i] == 0x90 || buf[i] == 0x91) && buf[i + 1] == 0xEF) + { + if (buf[i + 32] == 0x88) + { + loadsector = *(grub_uint32_t *)(buf + i + 32 + 8); + grub_snprintf(value, sizeof(value), "%u", loadsector * 4); //change to sector size 512 + break; + } + } + } + + if (loadsector == 0) + { + debug("No EFI eltorito info found\n"); + return 1; + } + + debug("ventoy_cmd_get_efivdisk_offset <%s>\n", value); + grub_env_set(args[1], value); + VENTOY_CMD_RETURN(0); +} + +static int ventoy_collect_replace_initrd(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + int curpos; + int printlen; + grub_size_t len; + replace_fs_dir *pfsdir = (replace_fs_dir *)data; + + if (pfsdir->initrd[0]) + { + return 1; + } + + curpos = pfsdir->curpos; + len = grub_strlen(filename); + + if (info->dir) + { + if ((len == 1 && filename[0] == '.') || + (len == 2 && filename[0] == '.' && filename[1] == '.')) + { + return 0; + } + + //debug("#### [DIR] <%s> <%s>\n", pfsdir->fullpath, filename); + pfsdir->dircnt++; + + printlen = grub_snprintf(pfsdir->fullpath + curpos, 512 - curpos, "%s/", filename); + pfsdir->curpos = curpos + printlen; + pfsdir->fs->fs_dir(pfsdir->dev, pfsdir->fullpath, ventoy_collect_replace_initrd, pfsdir); + pfsdir->curpos = curpos; + pfsdir->fullpath[curpos] = 0; + } + else + { + //debug("#### [FILE] <%s> <%s>\n", pfsdir->fullpath, filename); + pfsdir->filecnt++; + + /* We consider the xxx.img file bigger than 32MB is the initramfs file */ + if (len > 4 && grub_strncmp(filename + len - 4, ".img", 4) == 0) + { + if (info->size > 32 * VTOY_SIZE_1MB) + { + grub_snprintf(pfsdir->initrd, sizeof(pfsdir->initrd), "%s%s", pfsdir->fullpath, filename); + return 1; + } + } + } + + return 0; +} + +static grub_err_t ventoy_cmd_search_replace_initrd(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + char *pos = NULL; + char *device_name = NULL; + grub_device_t dev = NULL; + grub_fs_t fs = NULL; + replace_fs_dir *pfsdir = NULL; + + (void)ctxt; + + if (argc != 2) + { + debug("ventoy_cmd_search_replace_initrd, invalid param num %d\n", argc); + return 1; + } + + pfsdir = grub_zalloc(sizeof(replace_fs_dir)); + if (!pfsdir) + { + return 1; + } + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + goto fail; + } + + dev = grub_device_open(device_name); + if (!dev) + { + goto fail; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + goto fail; + } + + pfsdir->dev = dev; + pfsdir->fs = fs; + pfsdir->curpos = 1; + pfsdir->fullpath[0] = '/'; + fs->fs_dir(dev, "/", ventoy_collect_replace_initrd, pfsdir); + + if (pfsdir->initrd[0]) + { + debug("Replace initrd <%s> <%d %d>\n", pfsdir->initrd, pfsdir->dircnt, pfsdir->filecnt); + + for (i = 0; i < (int)sizeof(pfsdir->initrd) && pfsdir->initrd[i]; i++) + { + if (pfsdir->initrd[i] == '/') + { + pfsdir->initrd[i] = '\\'; + } + } + + pos = (pfsdir->initrd[0] == '\\') ? pfsdir->initrd + 1 : pfsdir->initrd; + grub_env_set(args[1], pos); + } + else + { + debug("Replace initrd NOT found <%s> <%d %d>\n", args[0], pfsdir->dircnt, pfsdir->filecnt); + } + +fail: + + grub_check_free(pfsdir); + grub_check_free(device_name); + check_free(dev, grub_device_close); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_push_pager(grub_extcmd_context_t ctxt, int argc, char **args) +{ + const char *pager = NULL; + + (void)ctxt; + (void)argc; + (void)args; + + pager = grub_env_get("pager"); + if (NULL == pager) + { + g_pager_flag = 1; + grub_env_set("pager", "1"); + } + else if (pager[0] == '1') + { + g_pager_flag = 0; + } + else + { + grub_snprintf(g_old_pager, sizeof(g_old_pager), "%s", pager); + g_pager_flag = 2; + grub_env_set("pager", "1"); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_pop_pager(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + if (g_pager_flag == 1) + { + grub_env_unset("pager"); + } + else if (g_pager_flag == 2) + { + grub_env_set("pager", g_old_pager); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_chk_case_file(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + if (g_json_case_mis_path[0]) + { + return 1; + } + + if (0 == info->dir && grub_strcasecmp(filename, "ventoy.json") == 0) + { + grub_snprintf(g_json_case_mis_path, 32, "%s/%s", (char *)data, filename); + return 1; + } + return 0; +} + +static int ventoy_chk_case_dir(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + char path[16]; + chk_case_fs_dir *fs_dir = (chk_case_fs_dir *)data; + + if (g_json_case_mis_path[0]) + { + return 1; + } + + if (info->dir && (filename[0] == 'v' || filename[0] == 'V')) + { + if (grub_strcasecmp(filename, "ventoy") == 0) + { + grub_snprintf(path, sizeof(path), "/%s", filename); + fs_dir->fs->fs_dir(fs_dir->dev, path, ventoy_chk_case_file, path); + if (g_json_case_mis_path[0]) + { + return 1; + } + } + } + + return 0; +} + +static grub_err_t ventoy_cmd_chk_json_pathcase(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int fstype = 0; + char *device_name = NULL; + grub_device_t dev = NULL; + grub_fs_t fs = NULL; + chk_case_fs_dir fs_dir; + + (void)ctxt; + (void)argc; + (void)args; + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + goto out; + } + + dev = grub_device_open(device_name); + if (!dev) + { + goto out; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + goto out; + } + + fstype = ventoy_get_fs_type(fs->name); + if (fstype == ventoy_fs_fat || fstype == ventoy_fs_exfat || fstype >= ventoy_fs_max) + { + goto out; + } + + g_json_case_mis_path[0] = 0; + fs_dir.dev = dev; + fs_dir.fs = fs; + fs->fs_dir(dev, "/", ventoy_chk_case_dir, &fs_dir); + + if (g_json_case_mis_path[0]) + { + grub_env_set("VTOY_PLUGIN_PATH_CASE_MISMATCH", g_json_case_mis_path); + } + +out: + + grub_check_free(device_name); + check_free(dev, grub_device_close); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t grub_cmd_gptpriority(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_disk_t disk; + grub_partition_t part; + char priority_str[3]; /* Maximum value 15 */ + + (void)ctxt; + + if (argc < 2 || argc > 3) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "gptpriority DISKNAME PARTITIONNUM [VARNAME]"); + + /* Open the disk if it exists */ + disk = grub_disk_open (args[0]); + if (!disk) + { + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Not a disk"); + } + + part = grub_partition_probe (disk, args[1]); + if (!part) + { + grub_disk_close (disk); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "No such partition"); + } + + if (grub_strcmp (part->partmap->name, "gpt")) + { + grub_disk_close (disk); + return grub_error (GRUB_ERR_BAD_PART_TABLE, + "Not a GPT partition"); + } + + grub_snprintf (priority_str, sizeof(priority_str), "%u", + (grub_uint32_t)((part->gpt_attrib >> 48) & 0xfULL)); + + if (argc == 3) + { + grub_env_set (args[2], priority_str); + grub_env_export (args[2]); + } + else + { + grub_printf ("Priority is %s\n", priority_str); + } + + grub_disk_close (disk); + return GRUB_ERR_NONE; +} + + +static grub_err_t grub_cmd_syslinux_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret = 1; + int joliet = 0; + grub_file_t file = NULL; + grub_uint32_t loadrba = 0; + grub_uint32_t boot_catlog = 0; + grub_uint8_t sector[512]; + boot_info_table *info = NULL; + + (void)ctxt; + (void)argc; + + /* This also trigger a iso9660 fs parse */ + if (ventoy_check_file_exist("(loop)/isolinux/isolinux.cfg")) + { + return 0; + } + + joliet = grub_iso9660_is_joliet(); + if (joliet == 0) + { + return 1; + } + + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (!file) + { + debug("failed to open %s\n", args[0]); + return 1; + } + + boot_catlog = ventoy_get_iso_boot_catlog(file); + if (boot_catlog == 0) + { + debug("no bootcatlog found %u\n", boot_catlog); + goto out; + } + + loadrba = ventoy_get_bios_eltorito_rba(file, boot_catlog); + if (loadrba == 0) + { + debug("no bios eltorito rba found %u\n", loadrba); + goto out; + } + + grub_file_seek(file, loadrba * 2048); + grub_file_read(file, sector, 512); + + info = (boot_info_table *)sector; + if (info->bi_data0 == 0x7c6ceafa && + info->bi_data1 == 0x90900000 && + info->bi_PrimaryVolumeDescriptor == 16 && + info->bi_BootFileLocation == loadrba) + { + debug("bootloader is syslinux, %u.\n", loadrba); + ret = 0; + } + +out: + + grub_file_close(file); + grub_errno = GRUB_ERR_NONE; + return ret; +} + +static grub_err_t grub_cmd_vlnk_dump_part(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int n = 0; + ventoy_vlnk_part *node; + + (void)ctxt; + (void)argc; + (void)args; + + for (node = g_vlnk_part_list; node; node = node->next) + { + grub_printf("[%d] %s disksig:%08x offset:%llu fs:%s\n", + ++n, node->device, node->disksig, + (ulonglong)node->partoffset, (node->fs ? node->fs->name : "N/A")); + } + + return 0; +} + +static grub_err_t grub_cmd_is_vlnk_name(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int len = 0; + + (void)ctxt; + + if (argc == 1) + { + len = (int)grub_strlen(args[0]); + if (grub_file_is_vlnk_suffix(args[0], len)) + { + return 0; + } + } + + return 1; +} + +static grub_err_t grub_cmd_get_vlnk_dst(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int vlnk = 0; + const char *name = NULL; + + (void)ctxt; + + if (argc == 2) + { + grub_env_unset(args[1]); + name = grub_file_get_vlnk(args[0], &vlnk); + if (vlnk) + { + debug("VLNK SRC: <%s>\n", args[0]); + debug("VLNK DST: <%s>\n", name); + grub_env_set(args[1], name); + return 0; + } + } + + return 1; +} + +static grub_err_t grub_cmd_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret = 1; + int len = 0; + grub_file_t file = NULL; + ventoy_vlnk vlnk; + char dst[512]; + + (void)ctxt; + + if (argc != 1) + { + goto out; + } + + len = (int)grub_strlen(args[0]); + if (!grub_file_is_vlnk_suffix(args[0], len)) + { + grub_printf("Invalid vlnk suffix\n"); + goto out; + } + + file = grub_file_open(args[0], VENTOY_FILE_TYPE | GRUB_FILE_TYPE_NO_VLNK); + if (!file) + { + grub_printf("Failed to open %s\n", args[0]); + goto out; + } + + if (file->size != 32768) + { + grub_printf("Invalid vlnk file (size=%llu).\n", (ulonglong)file->size); + goto out; + } + + grub_memset(&vlnk, 0, sizeof(vlnk)); + grub_file_read(file, &vlnk, sizeof(vlnk)); + + ret = ventoy_check_vlnk_data(&vlnk, 1, dst, sizeof(dst)); + +out: + + grub_refresh(); + check_free(file, grub_file_close); + grub_errno = GRUB_ERR_NONE; + return ret; +} + +static grub_err_t ventoy_iso_vd_id_clear(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + g_iso_vd_id_publisher[0] = 0; + g_iso_vd_id_prepare[0] = 0; + g_iso_vd_id_application[0] = 0; + + return 0; +} + +static grub_err_t ventoy_cmd_iso_vd_id_parse(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret = 1; + int offset = 318; + grub_file_t file = NULL; + + (void)ctxt; + (void)argc; + + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (!file) + { + grub_printf("Failed to open %s\n", args[0]); + goto out; + } + + grub_file_seek(file, 16 * 2048 + offset); + grub_file_read(file, g_iso_vd_id_publisher, 128); + + offset += 128; + grub_file_seek(file, 16 * 2048 + offset); + grub_file_read(file, g_iso_vd_id_prepare, 128); + + offset += 128; + grub_file_seek(file, 16 * 2048 + offset); + grub_file_read(file, g_iso_vd_id_application, 128); + +out: + + check_free(file, grub_file_close); + grub_errno = GRUB_ERR_NONE; + return ret; +} + +static grub_err_t ventoy_cmd_iso_vd_id_begin(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret = 1; + char *id = g_iso_vd_id_publisher; + + (void)ctxt; + (void)argc; + + if (args[0][0] == '1') + { + id = g_iso_vd_id_prepare; + } + else if (args[0][0] == '2') + { + id = g_iso_vd_id_application; + } + + if (args[1][0] == '0' && grub_strncasecmp(id, args[2], grub_strlen(args[2])) == 0) + { + ret = 0; + } + + if (args[1][0] == '1' && grub_strncmp(id, args[2], grub_strlen(args[2])) == 0) + { + ret = 0; + } + + grub_errno = GRUB_ERR_NONE; + return ret; +} + +static grub_err_t ventoy_cmd_fn_mutex_lock(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + + g_ventoy_fn_mutex = 0; + if (argc == 1 && args[0][0] == '1' && args[0][1] == 0) + { + g_ventoy_fn_mutex = 1; + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_dump_rsv_page(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint64_t total; + grub_uint64_t org_required; + grub_uint64_t new_required; + + (void)ctxt; + (void)argc; + (void)args; + +#ifdef GRUB_MACHINE_EFI + grub_efi_get_reserved_page_num(&total, &org_required, &new_required); + grub_printf("Total pages: %llu\n", (unsigned long long)total); + grub_printf("OrgReq pages: %llu\n", (unsigned long long)org_required); + grub_printf("NewReq pages: %llu\n", (unsigned long long)new_required); +#else + (void)total; + (void)org_required; + (void)new_required; + grub_printf("Non EFI mode!\n"); +#endif + + grub_refresh(); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_need_secondary_menu(grub_extcmd_context_t ctxt, int argc, char **args) +{ + const char *env = NULL; + + (void)ctxt; + (void)argc; + + if (g_ventoy_memdisk_mode || g_ventoy_grub2_mode || g_ventoy_wimboot_mode || g_ventoy_iso_raw) + { + return 1; + } + + if (ventoy_check_mode_by_name(args[0], "vtgrub2") || + ventoy_check_mode_by_name(args[0], "vtwimboot") || + ventoy_check_mode_by_name(args[0], "vtmemdisk") || + ventoy_check_mode_by_name(args[0], "vtnormal") || + ventoy_check_mode_by_name(args[0], "vtcompat") + ) + { + return 1; + } + + env = grub_env_get("VTOY_SECONDARY_BOOT_MENU"); + if (env && env[0] == '0' && env[1] == 0) + { + return 1; + } + + return 0; +} + +static grub_err_t ventoy_cmd_show_secondary_menu(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int n = 0; + int pos = 0; + int len = 0; + int select = 0; + int timeout = 0; + char *cmd = NULL; + const char *env = NULL; + ulonglong fsize = 0; + char cfgfile[128]; + int seldata[16] = {0}; + + (void)ctxt; + (void)argc; + + len = 8 * VTOY_SIZE_1KB; + cmd = (char *)grub_malloc(len); + if (!cmd) + { + return 1; + } + + g_vtoy_secondary_need_recover = 0; + grub_env_unset("VTOY_SECOND_EXIT"); + grub_env_unset("VTOY_CHKSUM_FILE_PATH"); + + env = grub_env_get("VTOY_SECONDARY_TIMEOUT"); + if (env) + { + timeout = (int)grub_strtol(env, NULL, 10); + } + + if (timeout > 0) + { + vtoy_len_ssprintf(cmd, pos, len, "set timeout=%d\n", timeout); + } + + fsize = grub_strtoull(args[2], NULL, 10); + + vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_NORMAL_MODE", "second_normal"); seldata[n++] = 1; + + if (grub_strcmp(args[1], "Unix") != 0) + { + if (grub_strcmp(args[1], "Windows") == 0) + { + vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_WIMBOOT_MODE", "second_wimboot"); seldata[n++] = 2; + } + else + { + vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_GRUB2_MODE", "second_grub2"); seldata[n++] = 3; + } + + if (fsize <= VTOY_SIZE_1GB) + { + vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_MEMDISK_MODE", "second_memdisk"); seldata[n++] = 4; + } + } + + vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_FILE_CHKSUM", "second_checksum"); seldata[n++] = 5; + vtoy_dummy_menuentry(cmd, pos, len, "$VTLANG_RETURN_PRV_NOESC", "second_return"); seldata[n++] = 6; + + do { + grub_errno = GRUB_ERR_NONE; + g_ventoy_menu_esc = 1; + g_ventoy_suppress_esc = 1; + g_ventoy_suppress_esc_default = 0; + g_ventoy_secondary_menu_on = 1; + grub_snprintf(cfgfile, sizeof(cfgfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)cmd, pos); + grub_script_execute_sourcecode(cfgfile); + g_ventoy_menu_esc = 0; + g_ventoy_suppress_esc = 0; + g_ventoy_suppress_esc_default = 1; + g_ventoy_secondary_menu_on = 0; + + select = seldata[g_ventoy_last_entry]; + + if (select == 2) + { + g_ventoy_wimboot_mode = 1; + g_vtoy_secondary_need_recover = 1; + } + else if (select == 3) + { + g_ventoy_grub2_mode = 1; + g_vtoy_secondary_need_recover = 2; + } + else if (select == 4) + { + g_ventoy_memdisk_mode = 1; + g_vtoy_secondary_need_recover = 3; + } + else if (select == 5) + { + grub_env_set("VTOY_CHKSUM_FILE_PATH", args[0]); + grub_script_execute_sourcecode("configfile $vtoy_efi_part/grub/checksum.cfg"); + } + else if (select == 6) + { + grub_env_set("VTOY_SECOND_EXIT", "1"); + } + }while (select == 5); + + grub_free(cmd); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_secondary_recover_mode(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + if (g_vtoy_secondary_need_recover == 1) + { + g_ventoy_wimboot_mode = 0; + } + else if (g_vtoy_secondary_need_recover == 2) + { + g_ventoy_grub2_mode = 0; + } + else if (g_vtoy_secondary_need_recover == 3) + { + g_ventoy_memdisk_mode = 0; + } + + g_vtoy_secondary_need_recover = 0; + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_cmd_fs_ignore_case(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + + if (args[0][0] == '0') + { + g_ventoy_case_insensitive = 0; + } + else + { + g_ventoy_case_insensitive = 1; + } + + return 0; +} + +static grub_err_t ventoy_cmd_init_menu_lang(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + + ventoy_plugin_load_menu_lang(1, args[0]); + VENTOY_CMD_RETURN(0); +} + +static grub_err_t ventoy_cmd_load_menu_lang(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + + ventoy_plugin_load_menu_lang(0, args[0]); + VENTOY_CMD_RETURN(0); +} + +static grub_err_t ventoy_cmd_update_sb_policy(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + +#ifdef GRUB_MACHINE_EFI + ventoy_set_sb_policy(); +#endif + + VENTOY_CMD_RETURN(0); +} + +static grub_err_t ventoy_cmd_timeout_lock(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + + if (args[0] && args[0][0] == '1') + { + ventoy_timeout_lock(1); + } + else + { + ventoy_timeout_lock(0); + } + + VENTOY_CMD_RETURN(0); +} + +static grub_err_t ventoy_cmd_theme_lock(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + + if (args[0] && args[0][0] == '1') + { + ventoy_theme_lock(1); + } + else + { + ventoy_theme_lock(0); + } + + VENTOY_CMD_RETURN(0); +} + +static grub_err_t ventoy_cmd_sb_info(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + +#ifdef GRUB_MACHINE_EFI + const char *policy = NULL; + grub_efi_guid_t security = + { 0xA46423E3, 0x4617, 0x49f1, {0xB9, 0xFF, 0xD1, 0xBF, 0xA9, 0x11, 0x58, 0x39 } }; + grub_efi_guid_t security2 = + { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } }; + + if (g_sb_policy == VTOY_SB_POLICY_BYPASS) + { + policy = "ByPass"; + } + else if (g_sb_policy == VTOY_SB_POLICY_CHECK) + { + policy = "Check"; + } + else + { + policy = "XXX"; + } + + grub_printf("UEFI Security %s\n", grub_efi_locate_protocol(&security, NULL) ? "Yes" : "No"); + grub_printf("UEFI Security2 %s\n", grub_efi_locate_protocol(&security2, NULL) ? "Yes" : "No"); + grub_printf("Ventoy Secure Policy %s\n", policy); + +#else + grub_printf("Non EFI mode!\n"); +#endif + + grub_refresh(); + + VENTOY_CMD_RETURN(0); +} + +static int ventoy_chksum_pathcmp(int chktype, char *rlpath, char *rdpath) +{ + char *pos1 = NULL; + char *pos2 = NULL; + + if (chktype == 2) + { + pos1 = ventoy_str_basename(rlpath); + pos2 = ventoy_str_basename(rdpath); + return grub_strcmp(pos1, pos2); + } + else if (chktype == 3 || chktype == 4) + { + if (grub_strcmp(rlpath, rdpath) == 0 || grub_strcmp(rlpath + 1, rdpath) == 0) + { + return 0; + } + } + + return 1; +} + +static int ventoy_find_checksum +( + grub_file_t file, + const char *uname, + int retlen, + char *path, + int chktype, + char *chksum +) +{ + int ulen; + char *pos = NULL; + char *pos1 = NULL; + char *pos2 = NULL; + char *buf = NULL; + char *currline = NULL; + char *nextline = NULL; + + ulen = (int)grub_strlen(uname); + + /* read file to buffer */ + buf = grub_malloc(file->size + 4); + if (!buf) + { + return 1; + } + grub_file_read(file, buf, file->size); + buf[file->size] = 0; + + /* parse each line */ + for (currline = buf; currline; currline = nextline) + { + nextline = ventoy_get_line(currline); + VTOY_SKIP_SPACE(currline); + + if (grub_strncasecmp(currline, uname, ulen) == 0) + { + pos = grub_strchr(currline, '='); + pos1 = grub_strchr(currline, '('); + pos2 = grub_strchr(currline, ')'); + + if (pos && pos1 && pos2) + { + *pos2 = 0; + if (ventoy_chksum_pathcmp(chktype, path, pos1 + 1) == 0) + { + VTOY_SKIP_SPACE_NEXT(pos, 1); + grub_memcpy(chksum, pos, retlen); + goto end; + } + } + } + else if (ventoy_str_len_alnum(currline, retlen)) + { + VTOY_SKIP_SPACE_NEXT_EX(pos, currline, retlen); + if (ventoy_chksum_pathcmp(chktype, path, pos) == 0) + { + grub_memcpy(chksum, currline, retlen); + goto end; + } + } + } + +end: + grub_free(buf); + return 0; +} + +static int ventoy_check_chkfile(const char *isopart, char *path, const char *lchkname, grub_file_t *pfile) +{ + int ret = 0; + int cnt = 0; + char c = 0; + char *pos = NULL; + grub_file_t file = NULL; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s.%s", isopart, path, lchkname); + if (file) + { + VTOY_GOTO_END(1); + } + + cnt = ventoy_str_chrcnt(path, '/'); + if (cnt > 1) + { + pos = grub_strrchr(path, '/'); + c = *pos; + *pos = 0; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s/VENTOY_CHECKSUM", isopart, path); + if (file) + { + *pos = c; + VTOY_GOTO_END(2); + } + *pos = c; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/VENTOY_CHECKSUM", isopart); + if (file) + { + ret = (cnt > 1) ? 3 : 4; + } + +end: + + if (pfile) + { + *pfile = file; + } + else + { + check_free(file, grub_file_close); + } + return ret; +} + +static grub_err_t ventoy_cmd_cmp_checksum(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int index = 0; + int chktype = 0; + char *pos = NULL; + grub_file_t file = NULL; + const char *calc_value = NULL; + const char *isopart = NULL; + char fchksum[64]; + char readchk[256] = {0}; + char filebuf[512] = {0}; + char uchkname[16]; + + (void)ctxt; + + index = (int)grub_strtol(args[0], NULL, 10); + if (argc != 2 || index < 0 || index >= VTOY_CHKSUM_NUM) + { + return 1; + } + + grub_strncpy(uchkname, g_lower_chksum_name[index], sizeof(uchkname)); + ventoy_str_toupper(uchkname); + + isopart = grub_env_get("vtoy_iso_part"); + calc_value = grub_env_get("VT_LAST_CHECK_SUM"); + + chktype = ventoy_check_chkfile(isopart, args[1], g_lower_chksum_name[index], &file); + if (chktype <= 0) + { + grub_printf("\n\nNo checksum file found.\n"); + goto end; + } + + if (chktype == 1) + { + grub_snprintf(fchksum, sizeof(fchksum), ".%s", g_lower_chksum_name[index]); + grub_memset(filebuf, 0, sizeof(filebuf)); + grub_file_read(file, filebuf, 511); + + pos = grub_strchr(filebuf, '='); + if (pos) + { + VTOY_SKIP_SPACE_NEXT(pos, 1); + grub_memcpy(readchk, pos, g_chksum_retlen[index]); + } + else + { + grub_memcpy(readchk, filebuf, g_chksum_retlen[index]); + } + } + else if (chktype == 3 || chktype == 4) + { + grub_snprintf(fchksum, sizeof(fchksum), "global VENTOY_CHECKSUM"); + ventoy_find_checksum(file, uchkname, g_chksum_retlen[index], args[1], chktype, readchk); + if (readchk[0] == 0) + { + grub_printf("\n\n%s value not found in %s.\n", uchkname, fchksum); + goto end; + } + } + else + { + grub_snprintf(fchksum, sizeof(fchksum), "local VENTOY_CHECKSUM"); + ventoy_find_checksum(file, uchkname, g_chksum_retlen[index], args[1], chktype, readchk); + if (readchk[0] == 0) + { + grub_file_close(file); + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/VENTOY_CHECKSUM", isopart); + if (file) + { + grub_snprintf(fchksum, sizeof(fchksum), "global VENTOY_CHECKSUM"); + ventoy_find_checksum(file, uchkname, g_chksum_retlen[index], args[1], 3, readchk); + if (readchk[0] == 0) + { + grub_printf("\n\n%s value not found in both local and global VENTOY_CHECKSUM.\n", uchkname); + goto end; + } + } + } + } + + if (grub_strcasecmp(calc_value, readchk) == 0) + { + grub_printf("\n\nCheck %s value with %s file. [ SUCCESS ]\n", uchkname, fchksum); + } + else + { + grub_printf("\n\nCheck %s value with %s file. [ ERROR ]\n", uchkname, fchksum); + grub_printf("The %s value in %s file is:\n%s\n", uchkname, fchksum, readchk); + } + +end: + grub_refresh(); + check_free(file, grub_file_close); + VENTOY_CMD_RETURN(0); +} + +static int ventoy_find_all_checksum +( + grub_file_t file, + char *path, + int chktype, + int exists[VTOY_CHKSUM_NUM], + int *ptotexist +) +{ + int i; + int ulen; + int tot = 0; + char c = 0; + char *pos = NULL; + char *pos1 = NULL; + char *pos2 = NULL; + char *buf = NULL; + char *currline = NULL; + char *nextline = NULL; + const char *uname = NULL; + + tot = *ptotexist; + + /* read file to buffer */ + buf = grub_malloc(file->size + 4); + if (!buf) + { + return 1; + } + grub_file_read(file, buf, file->size); + buf[file->size] = 0; + + /* parse each line */ + for (currline = buf; currline; currline = nextline) + { + nextline = ventoy_get_line(currline); + VTOY_SKIP_SPACE(currline); + + for (i = 0; i < VTOY_CHKSUM_NUM; i++) + { + if (exists[i]) + { + continue; + } + + uname = g_lower_chksum_name[i]; + ulen = g_lower_chksum_namelen[i]; + + if (grub_strncasecmp(currline, uname, ulen) == 0) + { + pos = grub_strchr(currline, '='); + pos1 = grub_strchr(currline, '('); + pos2 = grub_strchr(currline, ')'); + + if (pos && pos1 && pos2) + { + c = *pos2; + *pos2 = 0; + if (ventoy_chksum_pathcmp(chktype, path, pos1 + 1) == 0) + { + exists[i] = 1; + tot++; + } + *pos2 = c; + } + } + else if (ventoy_str_len_alnum(currline, g_chksum_retlen[i])) + { + VTOY_SKIP_SPACE_NEXT_EX(pos, currline, g_chksum_retlen[i]); + if (ventoy_chksum_pathcmp(chktype, path, pos) == 0) + { + exists[i] = 1; + tot++; + } + } + + if (tot >= VTOY_CHKSUM_NUM) + { + goto end; + } + } + } + +end: + + *ptotexist = tot; + grub_free(buf); + return 0; +} + +static grub_err_t ventoy_cmd_vtoychksum_exist(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i = 0; + int cnt = 0; + char c = 0; + int tip = 0; + char *pos = NULL; + grub_file_t file = NULL; + const char *isopart = NULL; + int exists[VTOY_CHKSUM_NUM] = { 0, 0, 0, 0 }; + int totexist = 0; + + (void)argc; + (void)ctxt; + + isopart = grub_env_get("vtoy_iso_part"); + + for (i = 0; i < VTOY_CHKSUM_NUM; i++) + { + if (ventoy_check_file_exist("%s%s.%s", isopart, args[0], g_lower_chksum_name[i])) + { + exists[i] = 1; + totexist++; + } + } + + if (totexist == VTOY_CHKSUM_NUM) + { + goto end; + } + + cnt = ventoy_str_chrcnt(args[0], '/'); + if (cnt > 1) + { + pos = grub_strrchr(args[0], '/'); + c = *pos; + *pos = 0; + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s/VENTOY_CHECKSUM", isopart, args[0]); + *pos = c; + + if (file) + { + if (tip == 0 && file->size > (32 * VTOY_SIZE_1KB)) + { + tip = 1; + grub_printf("Reading checksum file...\n"); + grub_refresh(); + } + + debug("parse local VENTOY_CHECKSUM\n"); + ventoy_find_all_checksum(file, args[0], 2, exists, &totexist); + grub_file_close(file); + } + } + + if (totexist == VTOY_CHKSUM_NUM) + { + goto end; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/VENTOY_CHECKSUM", isopart); + if (file) + { + if (tip == 0 && file->size > (32 * VTOY_SIZE_1KB)) + { + tip = 1; + grub_printf("Reading checksum file...\n"); + grub_refresh(); + } + + debug("parse global VENTOY_CHECKSUM\n"); + ventoy_find_all_checksum(file, args[0], (cnt > 1) ? 3 : 4, exists, &totexist); + grub_file_close(file); + } + +end: + + ventoy_env_int_set("VT_EXIST_MD5", exists[0]); + ventoy_env_int_set("VT_EXIST_SHA1", exists[1]); + ventoy_env_int_set("VT_EXIST_SHA256", exists[2]); + ventoy_env_int_set("VT_EXIST_SHA512", exists[3]); + + VENTOY_CMD_RETURN(0); +} + + +static const char * ventoy_menu_lang_read_hook(struct grub_env_var *var, const char *val) +{ + (void)var; + return ventoy_get_vmenu_title(val); +} + +int ventoy_env_init(void) +{ + int i; + char buf[64]; + + grub_env_set("vtdebug_flag", ""); + + grub_register_vtoy_menu_lang_hook(ventoy_menu_lang_read_hook); + ventoy_ctrl_var_init(); + ventoy_global_var_init(); + + g_part_list_buf = grub_malloc(VTOY_PART_BUF_LEN); + g_tree_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF); + g_list_script_buf = grub_malloc(VTOY_MAX_SCRIPT_BUF); + for (i = 0; i < VTOY_MAX_CONF_REPLACE; i++) + { + g_conf_replace_new_buf[i] = grub_malloc(vtoy_max_replace_file_size); + } + + ventoy_filt_register(0, ventoy_wrapper_open); + + g_grub_param = (ventoy_grub_param *)grub_zalloc(sizeof(ventoy_grub_param)); + if (g_grub_param) + { + g_grub_param->grub_env_get = grub_env_get; + g_grub_param->grub_env_set = (grub_env_set_pf)grub_env_set; + g_grub_param->grub_env_printf = (grub_env_printf_pf)grub_printf; + grub_snprintf(buf, sizeof(buf), "%p", g_grub_param); + grub_env_set("env_param", buf); + grub_env_set("ventoy_env_param", buf); + + grub_env_export("env_param"); + grub_env_export("ventoy_env_param"); + } + + grub_env_export("vtoy_winpeshl_ini_addr"); + grub_env_export("vtoy_winpeshl_ini_size"); + + grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_size); + grub_env_set("vtoy_chain_file_size", buf); + grub_env_export("vtoy_chain_file_size"); + + grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_chain_file_read); + grub_env_set("vtoy_chain_file_read", buf); + grub_env_export("vtoy_chain_file_read"); + + grub_snprintf(buf, sizeof(buf), "0x%lx", (ulong)ventoy_get_vmenu_title); + grub_env_set("VTOY_VMENU_FUNC_ADDR", buf); + grub_env_export("VTOY_VMENU_FUNC_ADDR"); + + grub_snprintf(buf, sizeof(buf), "%s-%s", GRUB_TARGET_CPU, GRUB_PLATFORM); + grub_env_set("grub_cpu_platform", buf); + grub_env_export("grub_cpu_platform"); + + return 0; +} + + + +static cmd_para ventoy_cmds[] = +{ + { "vt_browser_disk", ventoy_cmd_browser_disk, 0, NULL, "", "", NULL }, + { "vt_browser_dir", ventoy_cmd_browser_dir, 0, NULL, "", "", NULL }, + { "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL }, + { "vt_mod", ventoy_cmd_mod, 0, NULL, "{Int} {Int} {Var}", "mod integer variable", NULL }, + { "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL }, + { "vt_istrstr", ventoy_cmd_istrstr, 0, NULL, "", "", NULL }, + { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL }, + { "vt_str_casebegin", ventoy_cmd_strcasebegin, 0, NULL, "", "", NULL }, + { "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL }, + { "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL }, + { "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL }, + { "vt_cmp", ventoy_cmd_cmp, 0, NULL, "{Int1} { eq|ne|gt|lt|ge|le } {Int2}", "Comare two integers", NULL }, + { "vt_device", ventoy_cmd_device, 0, NULL, "path var", "", NULL }, + { "vt_check_compatible", ventoy_cmd_check_compatible, 0, NULL, "", "", NULL }, + { "vt_list_img", ventoy_cmd_list_img, 0, NULL, "{device} {cntvar}", "find all iso file in device", NULL }, + { "vt_clear_img", ventoy_cmd_clear_img, 0, NULL, "", "clear image list", NULL }, + { "vt_img_name", ventoy_cmd_img_name, 0, NULL, "{imageID} {var}", "get image name", NULL }, + { "vt_chosen_img_path", ventoy_cmd_chosen_img_path, 0, NULL, "{var}", "get chosen img path", NULL }, + { "vt_ext_select_img_path", ventoy_cmd_ext_select_img_path, 0, NULL, "{var}", "select chosen img path", NULL }, + { "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL }, + { "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL }, + { "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL }, + { "vt_load_vhdboot", ventoy_cmd_load_vhdboot, 0, NULL, "", "", NULL }, + { "vt_patch_vhdboot", ventoy_cmd_patch_vhdboot, 0, NULL, "", "", NULL }, + { "vt_raw_chain_data", ventoy_cmd_raw_chain_data, 0, NULL, "", "", NULL }, + { "vt_get_vtoy_type", ventoy_cmd_get_vtoy_type, 0, NULL, "", "", NULL }, + { "vt_check_custom_boot", ventoy_cmd_check_custom_boot, 0, NULL, "", "", NULL }, + { "vt_dump_custom_boot", ventoy_cmd_dump_custom_boot, 0, NULL, "", "", NULL }, + + { "vt_skip_svd", ventoy_cmd_skip_svd, 0, NULL, "", "", NULL }, + { "vt_cpio_busybox64", ventoy_cmd_cpio_busybox_64, 0, NULL, "", "", NULL }, + { "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL }, + { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL }, + { "vt_push_last_entry", ventoy_cmd_push_last_entry, 0, NULL, "", "", NULL }, + { "vt_pop_last_entry", ventoy_cmd_pop_last_entry, 0, NULL, "", "", NULL }, + { "vt_get_lib_module_ver", ventoy_cmd_lib_module_ver, 0, NULL, "", "", NULL }, + + { "vt_load_part_table", ventoy_cmd_load_part_table, 0, NULL, "", "", NULL }, + { "vt_check_part_exist", ventoy_cmd_part_exist, 0, NULL, "", "", NULL }, + { "vt_get_fs_label", ventoy_cmd_get_fs_label, 0, NULL, "", "", NULL }, + { "vt_fs_enum_1st_file", ventoy_cmd_fs_enum_1st_file, 0, NULL, "", "", NULL }, + { "vt_fs_enum_1st_dir", ventoy_cmd_fs_enum_1st_dir, 0, NULL, "", "", NULL }, + { "vt_file_basename", ventoy_cmd_basename, 0, NULL, "", "", NULL }, + { "vt_file_basefile", ventoy_cmd_basefile, 0, NULL, "", "", NULL }, + { "vt_enum_video_mode", ventoy_cmd_enum_video_mode, 0, NULL, "", "", NULL }, + { "vt_get_video_mode", ventoy_cmd_get_video_mode, 0, NULL, "", "", NULL }, + { "vt_update_cur_video_mode", vt_cmd_update_cur_video_mode, 0, NULL, "", "", NULL }, + + + { "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL }, + { "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL }, + { "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL }, + { "vt_check_mode", ventoy_cmd_check_mode, 0, NULL, "", "", NULL }, + { "vt_dump_img_list", ventoy_cmd_dump_img_list, 0, NULL, "", "", NULL }, + { "vt_dump_injection", ventoy_cmd_dump_injection, 0, NULL, "", "", NULL }, + { "vt_dump_auto_install", ventoy_cmd_dump_auto_install, 0, NULL, "", "", NULL }, + { "vt_dump_persistence", ventoy_cmd_dump_persistence, 0, NULL, "", "", NULL }, + { "vt_select_auto_install", ventoy_cmd_sel_auto_install, 0, NULL, "", "", NULL }, + { "vt_select_persistence", ventoy_cmd_sel_persistence, 0, NULL, "", "", NULL }, + { "vt_select_conf_replace", ventoy_select_conf_replace, 0, NULL, "", "", NULL }, + + { "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL }, + { "vt_iso9660_isjoliet", ventoy_cmd_iso9660_is_joliet, 0, NULL, "", "", NULL }, + { "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL }, + { "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL }, + { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL }, + { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL }, + { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL }, + + { "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL }, + { "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL }, + { "vt_linux_specify_initrd_file", ventoy_cmd_specify_initrd_file, 0, NULL, "", "", NULL }, + { "vt_linux_clear_initrd", ventoy_cmd_clear_initrd_list, 0, NULL, "", "", NULL }, + { "vt_linux_dump_initrd", ventoy_cmd_dump_initrd_list, 0, NULL, "", "", NULL }, + { "vt_linux_initrd_count", ventoy_cmd_initrd_count, 0, NULL, "", "", NULL }, + { "vt_linux_valid_initrd_count", ventoy_cmd_valid_initrd_count, 0, NULL, "", "", NULL }, + { "vt_linux_locate_initrd", ventoy_cmd_linux_locate_initrd, 0, NULL, "", "", NULL }, + { "vt_linux_chain_data", ventoy_cmd_linux_chain_data, 0, NULL, "", "", NULL }, + { "vt_linux_get_main_initrd_index", ventoy_cmd_linux_get_main_initrd_index, 0, NULL, "", "", NULL }, + + { "vt_windows_reset", ventoy_cmd_wimdows_reset, 0, NULL, "", "", NULL }, + { "vt_windows_chain_data", ventoy_cmd_windows_chain_data, 0, NULL, "", "", NULL }, + { "vt_windows_wimboot_data", ventoy_cmd_windows_wimboot_data, 0, NULL, "", "", NULL }, + { "vt_windows_collect_wim_patch", ventoy_cmd_collect_wim_patch, 0, NULL, "", "", NULL }, + { "vt_windows_locate_wim_patch", ventoy_cmd_locate_wim_patch, 0, NULL, "", "", NULL }, + { "vt_windows_count_wim_patch", ventoy_cmd_wim_patch_count, 0, NULL, "", "", NULL }, + { "vt_dump_wim_patch", ventoy_cmd_dump_wim_patch, 0, NULL, "", "", NULL }, + { "vt_wim_check_bootable", ventoy_cmd_wim_check_bootable, 0, NULL, "", "", NULL }, + { "vt_wim_chain_data", ventoy_cmd_wim_chain_data, 0, NULL, "", "", NULL }, + + { "vt_add_replace_file", ventoy_cmd_add_replace_file, 0, NULL, "", "", NULL }, + { "vt_get_replace_file_cnt", ventoy_cmd_get_replace_file_cnt, 0, NULL, "", "", NULL }, + { "vt_test_block_list", ventoy_cmd_test_block_list, 0, NULL, "", "", NULL }, + { "vt_file_exist_nocase", ventoy_cmd_file_exist_nocase, 0, NULL, "", "", NULL }, + + + { "vt_load_plugin", ventoy_cmd_load_plugin, 0, NULL, "", "", NULL }, + { "vt_check_plugin_json", ventoy_cmd_plugin_check_json, 0, NULL, "", "", NULL }, + { "vt_check_password", ventoy_cmd_check_password, 0, NULL, "", "", NULL }, + + { "vt_1st_line", ventoy_cmd_read_1st_line, 0, NULL, "", "", NULL }, + { "vt_file_strstr", ventoy_cmd_file_strstr, 0, NULL, "", "", NULL }, + { "vt_img_part_info", ventoy_cmd_img_part_info, 0, NULL, "", "", NULL }, + + + { "vt_parse_iso_volume", ventoy_cmd_parse_volume, 0, NULL, "", "", NULL }, + { "vt_parse_iso_create_date", ventoy_cmd_parse_create_date, 0, NULL, "", "", NULL }, + { "vt_parse_freenas_ver", ventoy_cmd_parse_freenas_ver, 0, NULL, "", "", NULL }, + { "vt_unix_parse_freebsd_ver", ventoy_cmd_unix_freebsd_ver, 0, NULL, "", "", NULL }, + { "vt_unix_parse_freebsd_ver_elf", ventoy_cmd_unix_freebsd_ver_elf, 0, NULL, "", "", NULL }, + { "vt_unix_reset", ventoy_cmd_unix_reset, 0, NULL, "", "", NULL }, + { "vt_unix_check_vlnk", ventoy_cmd_unix_check_vlnk, 0, NULL, "", "", NULL }, + { "vt_unix_replace_conf", ventoy_cmd_unix_replace_conf, 0, NULL, "", "", NULL }, + { "vt_unix_replace_grub_conf", ventoy_cmd_unix_replace_grub_conf, 0, NULL, "", "", NULL }, + { "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL }, + { "vt_unix_ko_fillmap", ventoy_cmd_unix_ko_fillmap, 0, NULL, "", "", NULL }, + { "vt_unix_fill_image_desc", ventoy_cmd_unix_fill_image_desc, 0, NULL, "", "", NULL }, + { "vt_unix_gzip_new_ko", ventoy_cmd_unix_gzip_newko, 0, NULL, "", "", NULL }, + { "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL }, + + { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL }, + { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL }, + { "vt_acpi_param", ventoy_cmd_acpi_param, 0, NULL, "", "", NULL }, + { "vt_check_secureboot_var", ventoy_cmd_check_secureboot_var, 0, NULL, "", "", NULL }, + { "vt_clear_key", ventoy_cmd_clear_key, 0, NULL, "", "", NULL }, + { "vt_img_check_range", ventoy_cmd_img_check_range, 0, NULL, "", "", NULL }, + { "vt_is_pe64", ventoy_cmd_is_pe64, 0, NULL, "", "", NULL }, + { "vt_sel_wimboot", ventoy_cmd_sel_wimboot, 0, NULL, "", "", NULL }, + { "vt_set_wim_load_prompt", ventoy_cmd_set_wim_prompt, 0, NULL, "", "", NULL }, + { "vt_set_theme", ventoy_cmd_set_theme, 0, NULL, "", "", NULL }, + { "vt_set_theme_path", ventoy_cmd_set_theme_path, 0, NULL, "", "", NULL }, + { "vt_select_theme_cfg", ventoy_cmd_select_theme_cfg, 0, NULL, "", "", NULL }, + + { "vt_get_efi_vdisk_offset", ventoy_cmd_get_efivdisk_offset, 0, NULL, "", "", NULL }, + { "vt_search_replace_initrd", ventoy_cmd_search_replace_initrd, 0, NULL, "", "", NULL }, + { "vt_push_pager", ventoy_cmd_push_pager, 0, NULL, "", "", NULL }, + { "vt_pop_pager", ventoy_cmd_pop_pager, 0, NULL, "", "", NULL }, + { "vt_check_json_path_case", ventoy_cmd_chk_json_pathcase, 0, NULL, "", "", NULL }, + { "vt_append_extra_sector", ventoy_cmd_append_ext_sector, 0, NULL, "", "", NULL }, + { "gptpriority", grub_cmd_gptpriority, 0, NULL, "", "", NULL }, + { "vt_syslinux_need_nojoliet", grub_cmd_syslinux_nojoliet, 0, NULL, "", "", NULL }, + { "vt_vlnk_check", grub_cmd_check_vlnk, 0, NULL, "", "", NULL }, + { "vt_vlnk_dump_part", grub_cmd_vlnk_dump_part, 0, NULL, "", "", NULL }, + { "vt_is_vlnk_name", grub_cmd_is_vlnk_name, 0, NULL, "", "", NULL }, + { "vt_get_vlnk_dst", grub_cmd_get_vlnk_dst, 0, NULL, "", "", NULL }, + { "vt_set_fake_vlnk", ventoy_cmd_set_fake_vlnk, 0, NULL, "", "", NULL }, + { "vt_reset_fake_vlnk", ventoy_cmd_reset_fake_vlnk, 0, NULL, "", "", NULL }, + { "vt_iso_vd_id_parse", ventoy_cmd_iso_vd_id_parse, 0, NULL, "", "", NULL }, + { "vt_iso_vd_id_clear", ventoy_iso_vd_id_clear, 0, NULL, "", "", NULL }, + { "vt_iso_vd_id_begin", ventoy_cmd_iso_vd_id_begin, 0, NULL, "", "", NULL }, + { "vt_fn_mutex_lock", ventoy_cmd_fn_mutex_lock, 0, NULL, "", "", NULL }, + { "vt_efi_dump_rsv_page", ventoy_cmd_dump_rsv_page, 0, NULL, "", "", NULL }, + { "vt_is_standard_winiso", ventoy_cmd_is_standard_winiso, 0, NULL, "", "", NULL }, + { "vt_sel_winpe_wim", ventoy_cmd_sel_winpe_wim, 0, NULL, "", "", NULL }, + { "vt_need_secondary_menu", ventoy_cmd_need_secondary_menu, 0, NULL, "", "", NULL }, + { "vt_show_secondary_menu", ventoy_cmd_show_secondary_menu, 0, NULL, "", "", NULL }, + { "vt_fs_ignore_case", ventoy_cmd_fs_ignore_case, 0, NULL, "", "", NULL }, + { "vt_systemd_menu", ventoy_cmd_linux_systemd_menu, 0, NULL, "", "", NULL }, + { "vt_limine_menu", ventoy_cmd_linux_limine_menu, 0, NULL, "", "", NULL }, + { "vt_secondary_recover_mode", ventoy_cmd_secondary_recover_mode, 0, NULL, "", "", NULL }, + { "vt_load_menu_lang", ventoy_cmd_load_menu_lang, 0, NULL, "", "", NULL }, + { "vt_init_menu_lang", ventoy_cmd_init_menu_lang, 0, NULL, "", "", NULL }, + { "vt_cur_menu_lang", ventoy_cmd_cur_menu_lang, 0, NULL, "", "", NULL }, + { "vt_vtoychksum_exist", ventoy_cmd_vtoychksum_exist, 0, NULL, "", "", NULL }, + { "vt_cmp_checksum", ventoy_cmd_cmp_checksum, 0, NULL, "", "", NULL }, + { "vt_push_menu_lang", ventoy_cmd_push_menulang, 0, NULL, "", "", NULL }, + { "vt_pop_menu_lang", ventoy_cmd_pop_menulang, 0, NULL, "", "", NULL }, + { "vt_linux_initrd", ventoy_cmd_linux_initrd, 0, NULL, "", "", NULL }, + + { "vt_sbinfo", ventoy_cmd_sb_info, 0, NULL, "", "", NULL }, + { "vt_update_sb_policy", ventoy_cmd_update_sb_policy, 0, NULL, "", "", NULL }, + + { "vt_timeout_lock", ventoy_cmd_timeout_lock, 0, NULL, "", "", NULL }, + { "vt_theme_lock", ventoy_cmd_theme_lock, 0, NULL, "", "", NULL }, + +}; + +int ventoy_register_all_cmd(void) +{ + grub_uint32_t i; + cmd_para *cur = NULL; + + for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++) + { + cur = ventoy_cmds + i; + cur->cmd = grub_register_extcmd(cur->name, cur->func, cur->flags, + cur->summary, cur->description, cur->parser); + } + + return 0; +} + +int ventoy_unregister_all_cmd(void) +{ + grub_uint32_t i; + + for (i = 0; i < ARRAY_SIZE(ventoy_cmds); i++) + { + grub_unregister_extcmd(ventoy_cmds[i].cmd); + } + + return 0; +} + + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h new file mode 100644 index 0000000..b78ef4a --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_def.h @@ -0,0 +1,1347 @@ +/****************************************************************************** + * ventoy_def.h + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#ifndef __VENTOY_DEF_H__ +#define __VENTOY_DEF_H__ + +#define VTOY_MAX_DIR_DEPTH 32 + +#define VTOY_MAX_SCRIPT_BUF (4 * 1024 * 1024) + +#define VTOY_PART_BUF_LEN (128 * 1024) + +#define VTOY_FILT_MIN_FILE_SIZE 32768 + +#define VTOY_LINUX_SYSTEMD_MENU_MAX_BUF 16384 + +#define VTOY_SIZE_1GB 1073741824 +#define VTOY_SIZE_1MB (1024 * 1024) +#define VTOY_SIZE_2MB (2 * 1024 * 1024) +#define VTOY_SIZE_4MB (4 * 1024 * 1024) +#define VTOY_SIZE_512KB (512 * 1024) +#define VTOY_SIZE_1KB 1024 +#define VTOY_SIZE_4KB 4096 +#define VTOY_SIZE_32KB (32 * 1024) +#define VTOY_SIZE_128KB (128 * 1024) + +#define JSON_SUCCESS 0 +#define JSON_FAILED 1 +#define JSON_NOT_FOUND 2 + +#define WINDATA_FLAG_TEMPLATE 1 + +#define ulong unsigned long +#define ulonglong unsigned long long + +#define vtoy_to_upper(c) (((char)(c) >= 'a' && (char)(c) <= 'z') ? ((char)(c) - 'a' + 'A') : (char)(c)) + +#define VENTOY_CMD_RETURN(err) grub_errno = (err); return (err) +#define VENTOY_FILE_TYPE (GRUB_FILE_TYPE_NO_DECOMPRESS | GRUB_FILE_TYPE_LINUX_INITRD) + +#define ventoy_env_op1(op, a) grub_env_##op(a) +#define ventoy_env_op2(op, a, b) grub_env_##op((a), (b)) + +#define ventoy_get_env(key) ventoy_env_op1(get, key) +#define ventoy_set_env(key, val) ventoy_env_op2(set, key, val) + +#define VTOY_WARNING "!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!" + +#define VTOY_CHKSUM_NUM 4 + +#define VTOY_PLAT_I386_UEFI 0x49413332 +#define VTOY_PLAT_ARM64_UEFI 0x41413634 +#define VTOY_PLAT_X86_64_UEFI 0x55454649 +#define VTOY_PLAT_X86_LEGACY 0x42494f53 +#define VTOY_PLAT_MIPS_UEFI 0x4D495053 + +#define VTOY_COMM_CPIO "ventoy.cpio" +#if defined(__arm__) || defined(__aarch64__) +#define VTOY_ARCH_CPIO "ventoy_arm64.cpio" +#elif defined(__mips__) +#define VTOY_ARCH_CPIO "ventoy_mips64.cpio" +#else +#define VTOY_ARCH_CPIO "ventoy_x86.cpio" +#endif + +#define ventoy_left_key "VTLE_LFT" +#define ventoy_top_key "VTLE_TOP" +#define ventoy_color_key "VTLE_CLR" + +#define ventoy_varg_4(arg) arg[0], arg[1], arg[2], arg[3] +#define ventoy_varg_8(arg) arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7] + +#define VTOY_PWD_CORRUPTED(err) \ +{\ + grub_printf("\n\n Password corrupted, will reboot after 5 seconds.\n\n"); \ + grub_refresh(); \ + grub_sleep(5); \ + grub_exit(); \ + return (err);\ +} + +#define vtoy_tip(wait_seconds, fmt, ...) \ + grub_printf(fmt, __VA_ARGS__); \ + grub_refresh(); \ + grub_sleep(wait_seconds) + + +#define VTOY_APPEND_NEWBUF(buf) \ +{\ + char *__c = buf;\ + while (*__c)\ + {\ + newbuf[pos++] = *__c;\ + __c++;\ + }\ +} + +#define VTOY_SKIP_SPACE(s) \ + while (ventoy_isspace(*s)) \ + {\ + s++;\ + } + +#define VTOY_SKIP_SPACE_NEXT(s, initial) \ + s += initial;\ + while (ventoy_isspace(*s)) \ + {\ + s++;\ + } + +#define VTOY_SKIP_SPACE_NEXT_EX(s, base, initial) \ + s = base + initial;\ + while (ventoy_isspace(*s)) \ + {\ + s++;\ + } + +#define VTOY_GOTO_END(v) ret = v; goto end + +typedef enum VTOY_FILE_FLT +{ + VTOY_FILE_FLT_ISO = 0, /* .iso */ + VTOY_FILE_FLT_WIM, /* .wim */ + VTOY_FILE_FLT_EFI, /* .efi */ + VTOY_FILE_FLT_IMG, /* .img */ + VTOY_FILE_FLT_VHD, /* .vhd(x) */ + VTOY_FILE_FLT_VTOY, /* .vtoy */ + + VTOY_FILE_FLT_BUTT +}VTOY_FILE_FLT; + +#define FILE_FLT(type) (0 == g_vtoy_file_flt[VTOY_FILE_FLT_##type]) + +typedef struct ventoy_initrd_ctx +{ + const char *path_prefix; + const char *dir_prefix; +}ventoy_initrd_ctx; + +typedef struct cmd_para +{ + const char *name; + grub_extcmd_func_t func; + grub_command_flags_t flags; + const struct grub_arg_option *parser; + + const char *summary; + const char *description; + + grub_extcmd_t cmd; +}cmd_para; + +#define ventoy_align_2k(value) ((value + 2047) / 2048 * 2048) +#define ventoy_align(value, align) (((value) + ((align) - 1)) & (~((align) - 1))) + +#pragma pack(1) +typedef struct cpio_newc_header +{ + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +}cpio_newc_header; +#pragma pack() + + +#define cmd_raw_name ctxt->extcmd->cmd->name +#define check_free(p, func) if (p) { func(p); p = NULL; } +#define grub_check_free(p) if (p) { grub_free(p); p = NULL; } + +#define VTOY_SHIM_POLICY_GUID {0x90a29d14, 0x3968, 0x48fe, { 0x85, 0x81, 0x6b, 0x7f, 0x7d, 0xc4, 0x70, 0x55 }}; + +typedef void (*VTOY_BYPASS_SB)(void); +typedef void (*VTOY_CHECK_SB)(void); +typedef void (*VTOY_LAUNCHED)(void); +typedef struct _VTOY_SHIM{ + VTOY_BYPASS_SB ByPassSB; + VTOY_CHECK_SB CheckSB; + VTOY_LAUNCHED Launched; +} VTOY_SHIM; + + +typedef int (*grub_char_check_func)(int c); +#define ventoy_is_decimal(str) ventoy_string_check(str, grub_isdigit) + +#define OFFSET_OF(TYPE, MEMBER) ((grub_size_t) &((TYPE *)0)->MEMBER) + +#pragma pack(1) +typedef struct ventoy_patch_vhd +{ + grub_uint8_t part_offset_or_guid[16]; + grub_uint32_t reserved1; + grub_uint32_t part_type; + grub_uint8_t disk_signature_or_guid[16]; + grub_uint8_t reserved2[16]; + grub_uint8_t vhd_file_path[1]; +}ventoy_patch_vhd; +#pragma pack() + +// El Torito Boot Record Volume Descriptor +#pragma pack(1) +typedef struct eltorito_descriptor +{ + grub_uint8_t type; + grub_uint8_t id[5]; + grub_uint8_t version; + grub_uint8_t system_id[32]; + grub_uint8_t reserved[32]; + grub_uint32_t sector; +}eltorito_descriptor; + +typedef struct ventoy_iso9660_override +{ + grub_uint32_t first_sector; + grub_uint32_t first_sector_be; + grub_uint32_t size; + grub_uint32_t size_be; +}ventoy_iso9660_override; + +typedef struct ventoy_udf_override +{ + grub_uint32_t length; + grub_uint32_t position; +}ventoy_udf_override; + +typedef struct ventoy_iso9660_vd +{ + grub_uint8_t type; + grub_uint8_t id[5]; + grub_uint8_t ver; + grub_uint8_t res; + char sys[32]; + char vol[32]; + grub_uint8_t res2[8]; + grub_uint32_t space; +}ventoy_iso9660_vd; + +/* https://wiki.osdev.org/El-Torito */ +typedef struct boot_info_table +{ + grub_uint32_t bi_data0; + grub_uint32_t bi_data1; + grub_uint32_t bi_PrimaryVolumeDescriptor; + grub_uint32_t bi_BootFileLocation; + grub_uint32_t bi_BootFileLength; + grub_uint32_t bi_Checksum; + grub_uint8_t bi_Reserved[40]; +}boot_info_table; + +#pragma pack() + +#define img_type_start 0 +#define img_type_iso 0 +#define img_type_wim 1 +#define img_type_efi 2 +#define img_type_img 3 +#define img_type_vhd 4 +#define img_type_vtoy 5 +#define img_type_max 6 + +typedef struct img_info +{ + int pathlen; + char path[512]; + char name[256]; + + const char *alias; + const char *tip1; + const char *tip2; + const char *class; + const char *menu_prefix; + + int id; + int type; + int plugin_list_index; + grub_uint64_t size; + int select; + int unsupport; + + void *parent; + + struct img_info *next; + struct img_info *prev; +}img_info; + +typedef struct img_iterator_node +{ + struct img_iterator_node *next; + img_info **tail; + char dir[400]; + int dirlen; + int level; + int isocnt; + int done; + int select; + + int plugin_list_index; + + struct img_iterator_node *parent; + struct img_iterator_node *firstchild; + + void *firstiso; +}img_iterator_node; + + + +typedef struct initrd_info +{ + char name[256]; + + grub_uint64_t offset; + grub_uint64_t size; + + grub_uint8_t iso_type; // 0: iso9660 1:udf + grub_uint32_t udf_start_block; + + grub_uint64_t override_offset; + grub_uint32_t override_length; + char override_data[32]; + + struct initrd_info *next; + struct initrd_info *prev; +}initrd_info; + +extern initrd_info *g_initrd_img_list; +extern initrd_info *g_initrd_img_tail; +extern int g_initrd_img_count; +extern int g_valid_initrd_count; + +extern img_info *g_ventoy_img_list; +extern int g_ventoy_img_count; + +extern grub_uint8_t *g_ventoy_cpio_buf; +extern grub_uint32_t g_ventoy_cpio_size; +extern cpio_newc_header *g_ventoy_initrd_head; +extern grub_uint8_t *g_ventoy_runtime_buf; + +extern ventoy_guid g_ventoy_guid; + +extern ventoy_img_chunk_list g_img_chunk_list; +extern ventoy_img_chunk_list g_wimiso_chunk_list; +extern char *g_wimiso_path; +extern grub_uint32_t g_wimiso_size; +extern char g_arch_mode_suffix[64]; +extern const char *g_menu_prefix[img_type_max]; + +extern int g_ventoy_debug; +void ventoy_debug(const char *fmt, ...); +#define debug(fmt, args...) if (g_ventoy_debug) ventoy_debug("[VTOY]: "fmt, ##args) + +#define vtoy_ssprintf(buf, pos, fmt, args...) \ + pos += grub_snprintf(buf + pos, VTOY_MAX_SCRIPT_BUF - pos, fmt, ##args) + +#define vtoy_len_ssprintf(buf, pos, len, fmt, args...) \ + pos += grub_snprintf(buf + pos, len - pos, fmt, ##args) + +#define browser_ssprintf(mbuf, fmt, args...) \ + (mbuf)->pos += grub_snprintf((mbuf)->buf + (mbuf)->pos, (mbuf)->max - (mbuf)->pos, fmt, ##args) + +#define vtoy_dummy_menuentry(buf, pos, len, title, class) \ + vtoy_len_ssprintf(buf, pos, len, "menuentry \"%s\" --class=\"%s\" {\n echo \"\"\n}\n", title, class) + + +#define FLAG_HEADER_RESERVED 0x00000001 +#define FLAG_HEADER_COMPRESSION 0x00000002 +#define FLAG_HEADER_READONLY 0x00000004 +#define FLAG_HEADER_SPANNED 0x00000008 +#define FLAG_HEADER_RESOURCE_ONLY 0x00000010 +#define FLAG_HEADER_METADATA_ONLY 0x00000020 +#define FLAG_HEADER_WRITE_IN_PROGRESS 0x00000040 +#define FLAG_HEADER_RP_FIX 0x00000080 // reparse point fixup +#define FLAG_HEADER_COMPRESS_RESERVED 0x00010000 +#define FLAG_HEADER_COMPRESS_XPRESS 0x00020000 +#define FLAG_HEADER_COMPRESS_LZX 0x00040000 +#define FLAG_HEADER_COMPRESS_LZMS 0x00080000 + +#define RESHDR_FLAG_FREE 0x01 +#define RESHDR_FLAG_METADATA 0x02 +#define RESHDR_FLAG_COMPRESSED 0x04 +#define RESHDR_FLAG_SPANNED 0x08 + +#pragma pack(1) + +/* A WIM resource header */ +typedef struct wim_resource_header +{ + grub_uint64_t size_in_wim:56; /* Compressed length */ + grub_uint64_t flags:8; /* flags */ + grub_uint64_t offset; /* Offset */ + grub_uint64_t raw_size; /* Uncompressed length */ +}wim_resource_header; + +/* WIM resource header length mask */ +#define WIM_RESHDR_ZLEN_MASK 0x00ffffffffffffffULL + +/* WIM resource header flags */ +typedef enum wim_resource_header_flags +{ + WIM_RESHDR_METADATA = ( 0x02ULL << 56 ), /* Resource contains metadata */ + WIM_RESHDR_COMPRESSED = ( 0x04ULL << 56 ), /* Resource is compressed */ + WIM_RESHDR_PACKED_STREAMS = ( 0x10ULL << 56 ), /* Resource is compressed using packed streams */ +}wim_resource_header_flags; + +#define WIM_HEAD_SIGNATURE "MSWIM\0\0" + +/* WIM header */ +typedef struct wim_header +{ + grub_uint8_t signature[8]; /* Signature */ + grub_uint32_t header_len; /* Header length */ + grub_uint32_t version; /* Verson */ + grub_uint32_t flags; /* Flags */ + grub_uint32_t chunk_len; /* Chunk length */ + grub_uint8_t guid[16]; /* GUID */ + grub_uint16_t part; /* Part number */ + grub_uint16_t parts; /* Total number of parts */ + grub_uint32_t images; /* number of images */ + wim_resource_header lookup; /* Lookup table */ + wim_resource_header xml; /* XML data */ + wim_resource_header metadata; /* Boot metadata */ + grub_uint32_t boot_index; /* Boot index */ + wim_resource_header integrity; /* Integrity table */ + grub_uint8_t reserved[60]; /* Reserved */ +} wim_header; + +/* WIM header flags */ +typedef enum wim_header_flags +{ + WIM_HDR_XPRESS = 0x00020000, /* WIM uses Xpress compresson */ + WIM_HDR_LZX = 0x00040000, /* WIM uses LZX compression */ +}wim_header_flags; + +/* A WIM file hash */ +typedef struct wim_hash +{ + /* SHA-1 hash */ + grub_uint8_t sha1[20]; +}wim_hash; + +/* A WIM lookup table entry */ +typedef struct wim_lookup_entry +{ + wim_resource_header resource; /* Resource header */ + grub_uint16_t part; /* Part number */ + grub_uint32_t refcnt; /* Reference count */ + wim_hash hash; /* Hash */ +}wim_lookup_entry; + +/* WIM chunk length */ +#define WIM_CHUNK_LEN 32768 + +/* A WIM chunk buffer */ +typedef struct wim_chunk_buffer +{ + grub_uint8_t data[WIM_CHUNK_LEN]; /*Data */ +}wim_chunk_buffer; + +/* Security data */ +typedef struct wim_security_header +{ + grub_uint32_t len; /* Length */ + grub_uint32_t count; /* Number of entries */ +}wim_security_header; + +typedef struct wim_stream_entry +{ + grub_uint64_t len; + grub_uint64_t unused1; + wim_hash hash; + grub_uint16_t name_len; + /* name */ +}wim_stream_entry; + +/* Directory entry */ +typedef struct wim_directory_entry +{ + grub_uint64_t len; /* Length */ + grub_uint32_t attributes; /* Attributes */ + grub_uint32_t security; /* Security ID */ + grub_uint64_t subdir; /* Subdirectory offset */ + grub_uint8_t reserved1[16]; /* Reserved */ + grub_uint64_t created; /* Creation time */ + grub_uint64_t accessed; /* Last access time */ + grub_uint64_t written; /* Last written time */ + wim_hash hash; /* Hash */ + grub_uint8_t reserved2[12]; /* Reserved */ + grub_uint16_t streams; /* Streams */ + grub_uint16_t short_name_len; /* Short name length */ + grub_uint16_t name_len; /* Name length */ +}wim_directory_entry; + +/** Normal file */ +#define WIM_ATTR_NORMAL 0x00000080UL + +/** No security information exists for this file */ +#define WIM_NO_SECURITY 0xffffffffUL + +typedef struct reg_vk +{ + grub_uint32_t res1; + grub_uint16_t sig; + grub_uint16_t namesize; + grub_uint32_t datasize; + grub_uint32_t dataoffset; + grub_uint32_t datatype; + grub_uint16_t flag; + grub_uint16_t res2; +}reg_vk; + +#pragma pack() + + +typedef struct wim_tail +{ + grub_uint32_t wim_raw_size; + grub_uint32_t wim_align_size; + + grub_uint8_t iso_type; + grub_uint64_t file_offset; + grub_uint32_t udf_start_block; + grub_uint64_t fe_entry_size_offset; + grub_uint64_t override_offset; + grub_uint32_t override_len; + grub_uint8_t override_data[32]; + + wim_header wim_header; + + wim_hash bin_hash; + grub_uint32_t jump_exe_len; + grub_uint8_t *jump_bin_data; + grub_uint32_t bin_raw_len; + grub_uint32_t bin_align_len; + grub_uint32_t windata_flag; + + grub_uint8_t *new_meta_data; + grub_uint32_t new_meta_len; + grub_uint32_t new_meta_align_len; + + grub_uint8_t *new_lookup_data; + grub_uint32_t new_lookup_len; + grub_uint32_t new_lookup_align_len; +}wim_tail; + +typedef struct wim_patch +{ + int pathlen; + char path[256]; + + wim_hash old_hash; + wim_tail wim_data; + wim_lookup_entry *replace_look; + + int valid; + + struct wim_patch *next; +}wim_patch; + + +typedef enum _JSON_TYPE +{ + JSON_TYPE_NUMBER = 0, + JSON_TYPE_STRING, + JSON_TYPE_BOOL, + JSON_TYPE_ARRAY, + JSON_TYPE_OBJECT, + JSON_TYPE_NULL, + JSON_TYPE_BUTT +}JSON_TYPE; + + +typedef struct _VTOY_JSON +{ + struct _VTOY_JSON *pstPrev; + struct _VTOY_JSON *pstNext; + struct _VTOY_JSON *pstChild; + + JSON_TYPE enDataType; + union + { + char *pcStrVal; + int iNumVal; + grub_uint64_t lValue; + }unData; + + char *pcName; +}VTOY_JSON; + +typedef struct _JSON_PARSE +{ + char *pcKey; + void *pDataBuf; + grub_uint32_t uiBufSize; +}JSON_PARSE; + +#define JSON_NEW_ITEM(pstJson, ret) \ +{ \ + (pstJson) = (VTOY_JSON *)grub_zalloc(sizeof(VTOY_JSON)); \ + if (NULL == (pstJson)) \ + { \ + json_debug("Failed to alloc memory for json.\n"); \ + return (ret); \ + } \ +} + +typedef int (*ventoy_plugin_entry_pf)(VTOY_JSON *json, const char *isodisk); +typedef int (*ventoy_plugin_check_pf)(VTOY_JSON *json, const char *isodisk); + +typedef struct plugin_entry +{ + const char *key; + ventoy_plugin_entry_pf entryfunc; + ventoy_plugin_check_pf checkfunc; + int flag; +}plugin_entry; + +typedef struct replace_fs_dir +{ + grub_device_t dev; + grub_fs_t fs; + char fullpath[512]; + char initrd[512]; + int curpos; + int dircnt; + int filecnt; +}replace_fs_dir; + +typedef struct chk_case_fs_dir +{ + grub_device_t dev; + grub_fs_t fs; +}chk_case_fs_dir; + +int ventoy_str_all_digit(const char *str); +int ventoy_str_all_alnum(const char *str); +int ventoy_str_len_alnum(const char *str, int len); +char * ventoy_str_basename(char *path); +void ventoy_timeout_lock(int lock); +void ventoy_theme_lock(int lock); +grub_err_t ventoy_env_int_set(const char *name, int value); +int ventoy_str_chrcnt(const char *str, char c); +int ventoy_strcmp(const char *pattern, const char *str); +int ventoy_strncmp (const char *pattern, const char *str, grub_size_t n); +void ventoy_fill_os_param(grub_file_t file, ventoy_os_param *param); +grub_err_t ventoy_cmd_isolinux_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_dump_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_clear_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args); +grub_uint32_t ventoy_get_iso_boot_catlog(grub_file_t file); +int ventoy_has_efi_eltorito(grub_file_t file, grub_uint32_t sector); +grub_err_t ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_linux_systemd_menu(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_linux_initrd(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_linux_limine_menu(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt, int argc, char **args); +int ventoy_cpio_newc_fill_head(void *buf, int filesize, const void *filedata, const char *name); +grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...); +grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...); +int ventoy_is_dir_exist(const char *fmt, ...); +int ventoy_fill_data(grub_uint32_t buflen, char *buffer); +grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_is_pe64(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_windows_wimboot_data(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_wim_chain_data(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_wim_check_bootable(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_is_standard_winiso(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_dump_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_sel_wimboot(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_set_wim_prompt(grub_extcmd_context_t ctxt, int argc, char **args); +grub_ssize_t ventoy_load_file_with_prompt(grub_file_t file, void *buf, grub_ssize_t size); +int ventoy_need_prompt_load_file(void); + +VTOY_JSON *vtoy_json_find_item +( + VTOY_JSON *pstJson, + JSON_TYPE enDataType, + const char *szKey +); +int vtoy_json_parse_value +( + char *pcNewStart, + char *pcRawStart, + VTOY_JSON *pstJson, + const char *pcData, + const char **ppcEnd +); +VTOY_JSON * vtoy_json_create(void); +int vtoy_json_parse(VTOY_JSON *pstJson, const char *szJsonData); + +int vtoy_json_scan_parse +( + const VTOY_JSON *pstJson, + grub_uint32_t uiParseNum, + JSON_PARSE *pstJsonParse +); + +int vtoy_json_scan_array +( + VTOY_JSON *pstJson, + const char *szKey, + VTOY_JSON **ppstArrayItem +); + +int vtoy_json_scan_array_ex +( + VTOY_JSON *pstJson, + const char *szKey, + VTOY_JSON **ppstArrayItem +); +int vtoy_json_scan_object +( + VTOY_JSON *pstJson, + const char *szKey, + VTOY_JSON **ppstObjectItem +); +int vtoy_json_get_int +( + VTOY_JSON *pstJson, + const char *szKey, + int *piValue +); +int vtoy_json_get_uint +( + VTOY_JSON *pstJson, + const char *szKey, + grub_uint32_t *puiValue +); +int vtoy_json_get_uint64 +( + VTOY_JSON *pstJson, + const char *szKey, + grub_uint64_t *pui64Value +); +int vtoy_json_get_bool +( + VTOY_JSON *pstJson, + const char *szKey, + grub_uint8_t *pbValue +); +int vtoy_json_get_string +( + VTOY_JSON *pstJson, + const char *szKey, + grub_uint32_t uiBufLen, + char *pcBuf +); +const char * vtoy_json_get_string_ex(VTOY_JSON *pstJson, const char *szKey); +int vtoy_json_destroy(VTOY_JSON *pstJson); + + +grub_uint32_t CalculateCrc32 +( + const void *Buffer, + grub_uint32_t Length, + grub_uint32_t InitValue +); + +static inline int ventoy_isspace (int c) +{ + return (c == '\n' || c == '\r' || c == ' ' || c == '\t'); +} + +static inline int ventoy_is_word_end(int c) +{ + return (c == 0 || c == ',' || ventoy_isspace(c)); +} + +#pragma pack(1) +typedef struct ventoy_part_table +{ + grub_uint8_t Active; // 0x00 0x80 + + grub_uint8_t StartHead; + grub_uint16_t StartSector : 6; + grub_uint16_t StartCylinder : 10; + + grub_uint8_t FsFlag; + + grub_uint8_t EndHead; + grub_uint16_t EndSector : 6; + grub_uint16_t EndCylinder : 10; + + grub_uint32_t StartSectorId; + grub_uint32_t SectorCount; +}ventoy_part_table; + +typedef struct ventoy_mbr_head +{ + grub_uint8_t BootCode[446]; + ventoy_part_table PartTbl[4]; + grub_uint8_t Byte55; + grub_uint8_t ByteAA; +}ventoy_mbr_head; + +typedef struct ventoy_gpt_head +{ + char Signature[8]; /* EFI PART */ + grub_uint8_t Version[4]; + grub_uint32_t Length; + grub_uint32_t Crc; + grub_uint8_t Reserved1[4]; + grub_uint64_t EfiStartLBA; + grub_uint64_t EfiBackupLBA; + grub_uint64_t PartAreaStartLBA; + grub_uint64_t PartAreaEndLBA; + grub_uint8_t DiskGuid[16]; + grub_uint64_t PartTblStartLBA; + grub_uint32_t PartTblTotNum; + grub_uint32_t PartTblEntryLen; + grub_uint32_t PartTblCrc; + grub_uint8_t Reserved2[420]; +}ventoy_gpt_head; + +typedef struct ventoy_gpt_part_tbl +{ + grub_uint8_t PartType[16]; + grub_uint8_t PartGuid[16]; + grub_uint64_t StartLBA; + grub_uint64_t LastLBA; + grub_uint64_t Attr; + grub_uint16_t Name[36]; +}ventoy_gpt_part_tbl; + +typedef struct ventoy_gpt_info +{ + ventoy_mbr_head MBR; + ventoy_gpt_head Head; + ventoy_gpt_part_tbl PartTbl[128]; +}ventoy_gpt_info; + +typedef struct vhd_footer_t +{ + char cookie[8]; // Cookie + grub_uint32_t features; // Features + grub_uint32_t ffversion; // File format version + grub_uint32_t dataoffset; // Data offset + grub_uint32_t timestamp; // Timestamp + grub_uint32_t creatorapp; // Creator application + grub_uint32_t creatorver; // Creator version + grub_uint32_t creatorhos; // Creator host OS + grub_uint32_t origsize; // Original size + grub_uint32_t currsize; // Current size + grub_uint32_t diskgeom; // Disk geometry + grub_uint32_t disktype; // Disk type + grub_uint32_t checksum; // Checksum + grub_uint8_t uniqueid[16]; // Unique ID + grub_uint8_t savedst; // Saved state +}vhd_footer_t; + +#define VDI_IMAGE_FILE_INFO "<<< Oracle VM VirtualBox Disk Image >>>\n" +#define VDI_IMAGE_FILE_INFO2 "<<< Oracle VirtualBox Disk Image >>>\n" + +/** Image signature. */ +#define VDI_IMAGE_SIGNATURE (0xbeda107f) + +typedef struct VDIPREHEADER +{ + /** Just text info about image type, for eyes only. */ + char szFileInfo[64]; + /** The image signature (VDI_IMAGE_SIGNATURE). */ + grub_uint32_t u32Signature; + /** The image version (VDI_IMAGE_VERSION). */ + grub_uint32_t u32Version; +} VDIPREHEADER, *PVDIPREHEADER; + +#pragma pack() + +typedef struct ventoy_video_mode +{ + grub_uint32_t width; + grub_uint32_t height; + grub_uint32_t bpp; +}ventoy_video_mode; + + + +typedef struct file_fullpath +{ + char path[256]; + int vlnk_add; +}file_fullpath; + +typedef struct theme_list +{ + file_fullpath theme; + struct theme_list *next; +}theme_list; + +#define auto_install_type_file 0 +#define auto_install_type_parent 1 +typedef struct install_template +{ + int type; + int pathlen; + char isopath[256]; + + int timeout; + int autosel; + int cursel; + int templatenum; + file_fullpath *templatepath; + + char *filebuf; + int filelen; + + struct install_template *next; +}install_template; + +typedef struct dudfile +{ + int size; + char *buf; +}dudfile; + +typedef struct dud +{ + int pathlen; + char isopath[256]; + + int dudnum; + file_fullpath *dudpath; + dudfile *files; + + struct dud *next; +}dud; + +typedef struct persistence_config +{ + int pathlen; + char isopath[256]; + + int timeout; + int autosel; + int cursel; + int backendnum; + file_fullpath *backendpath; + + struct persistence_config *next; +}persistence_config; + +#define vtoy_alias_image_file 0 +#define vtoy_alias_directory 1 + +typedef struct menu_alias +{ + int type; + int pathlen; + char isopath[256]; + char alias[256]; + + struct menu_alias *next; +}menu_alias; + +#define vtoy_tip_image_file 0 +#define vtoy_tip_directory 1 +typedef struct menu_tip +{ + int type; + int pathlen; + char isopath[256]; + char tip1[1024]; + char tip2[1024]; + + struct menu_tip *next; +}menu_tip; + + +#define vtoy_class_image_file 0 +#define vtoy_class_directory 1 + +typedef struct menu_class +{ + int type; + int patlen; + int parent; + char pattern[256]; + char class[64]; + + struct menu_class *next; +}menu_class; + +#define vtoy_custom_boot_image_file 0 +#define vtoy_custom_boot_directory 1 + +typedef struct custom_boot +{ + int type; + int pathlen; + char path[256]; + char cfg[256]; + + struct custom_boot *next; +}custom_boot; + +#define vtoy_max_replace_file_size (1024 * 1024) +typedef struct conf_replace +{ + int pathlen; + int img; + char isopath[256]; + char orgconf[256]; + char newconf[256]; + + struct conf_replace *next; +}conf_replace; + +#define injection_type_file 0 +#define injection_type_parent 1 +typedef struct injection_config +{ + int type; + int pathlen; + char isopath[256]; + char archive[256]; + + struct injection_config *next; +}injection_config; + +typedef struct auto_memdisk +{ + int pathlen; + char isopath[256]; + + struct auto_memdisk *next; +}auto_memdisk; + +typedef struct image_list +{ + int pathlen; + char isopath[256]; + + struct image_list *next; +}image_list; + +#define VTOY_PASSWORD_NONE 0 +#define VTOY_PASSWORD_TXT 1 +#define VTOY_PASSWORD_MD5 2 +#define VTOY_PASSWORD_SALT_MD5 3 + +typedef struct vtoy_password +{ + int type; + char text[128]; + char salt[64]; + grub_uint8_t md5[16]; +}vtoy_password; + +#define vtoy_menu_pwd_file 0 +#define vtoy_menu_pwd_parent 1 + +typedef struct menu_password +{ + int type; + int pathlen; + char isopath[256]; + + vtoy_password password; + + struct menu_password *next; +}menu_password; + +extern int g_ventoy_menu_esc; +extern int g_ventoy_secondary_menu_on; +extern int g_ventoy_suppress_esc; +extern int g_ventoy_suppress_esc_default; +extern int g_ventoy_last_entry; +extern int g_ventoy_memdisk_mode; +extern int g_ventoy_iso_raw; +extern int g_ventoy_grub2_mode; +extern int g_ventoy_wimboot_mode; +extern int g_ventoy_iso_uefi_drv; +extern int g_ventoy_case_insensitive; +extern int g_ventoy_fn_mutex; +extern grub_uint8_t g_ventoy_chain_type; +extern int g_vhdboot_enable; +extern int g_default_menu_mode; +extern char g_ventoy_hotkey_tip[256]; +extern int g_ventoy_menu_refresh; + +#define VENTOY_IMG_WHITE_LIST 1 +#define VENTOY_IMG_BLACK_LIST 2 +extern int g_plugin_image_list; + +extern ventoy_gpt_info *g_ventoy_part_info; +extern int g_conf_replace_count; +extern grub_uint64_t g_conf_replace_offset[VTOY_MAX_CONF_REPLACE]; +extern grub_uint64_t g_svd_replace_offset; +extern conf_replace *g_conf_replace_node[VTOY_MAX_CONF_REPLACE]; +extern grub_uint8_t *g_conf_replace_new_buf[VTOY_MAX_CONF_REPLACE]; +extern int g_conf_replace_new_len[VTOY_MAX_CONF_REPLACE]; +extern int g_conf_replace_new_len_align[VTOY_MAX_CONF_REPLACE]; +extern int g_ventoy_disk_bios_id; +extern grub_uint64_t g_ventoy_disk_size; +extern grub_uint64_t g_ventoy_disk_part_size[2]; +extern grub_uint32_t g_ventoy_plat_data; + +#define ventoy_unix_fill_virt(new_data, new_len) \ +{ \ + data_secs = (new_len + 2047) / 2048; \ + cur->mem_sector_start = sector; \ + cur->mem_sector_end = cur->mem_sector_start + data_secs; \ + cur->mem_sector_offset = offset; \ + cur->remap_sector_start = 0; \ + cur->remap_sector_end = 0; \ + cur->org_sector_start = 0; \ + grub_memcpy(override + offset, new_data, new_len); \ + cur++; \ + sector += data_secs; \ + offset += new_len; \ + chain->virt_img_size_in_bytes += data_secs * 2048; \ +} + +#define ventoy_syscall0(name) grub_##name() +#define ventoy_syscall1(name, a) grub_##name(a) + +void ventoy_str_tolower(char *str); +void ventoy_str_toupper(char *str); +char * ventoy_get_line(char *start); +char *ventoy_str_last(char *str, char ch); +int ventoy_cmp_img(img_info *img1, img_info *img2); +void ventoy_swap_img(img_info *img1, img_info *img2); +char * ventoy_plugin_get_cur_install_template(const char *isopath, install_template **cur); +install_template * ventoy_plugin_find_install_template(const char *isopath); +persistence_config * ventoy_plugin_find_persistent(const char *isopath); +grub_uint64_t ventoy_get_vtoy_partsize(int part); +void ventoy_plugin_dump_injection(void); +void ventoy_plugin_dump_auto_install(void); +int ventoy_plugin_get_persistent_chunklist(const char *isopath, int index, ventoy_img_chunk_list *chunk_list); +const char * ventoy_plugin_get_injection(const char *isopath); +const char * ventoy_plugin_get_menu_alias(int type, const char *isopath); +const menu_tip * ventoy_plugin_get_menu_tip(int type, const char *isopath); +const char * ventoy_plugin_get_menu_class(int type, const char *name, const char *path); +int ventoy_plugin_check_memdisk(const char *isopath); +int ventoy_plugin_get_image_list_index(int type, const char *name); +int ventoy_plugin_find_conf_replace(const char *iso, conf_replace *nodes[VTOY_MAX_CONF_REPLACE]); +dud * ventoy_plugin_find_dud(const char *iso); +int ventoy_plugin_load_dud(dud *node, const char *isopart); +int ventoy_get_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start); +int ventoy_check_block_list(grub_file_t file, ventoy_img_chunk_list *chunklist, grub_disk_addr_t start, char *err, grub_uint32_t len); +void ventoy_plugin_dump_persistence(void); +grub_err_t ventoy_cmd_set_theme(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_set_theme_path(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_select_theme_cfg(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_plugin_check_json(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_check_password(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_collect_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_wim_patch_count(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_locate_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_sel_winpe_wim(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_chain_data(grub_extcmd_context_t ctxt, int argc, char **args); +int ventoy_get_disk_guid(const char *filename, grub_uint8_t *guid, grub_uint8_t *signature); +grub_err_t ventoy_cmd_unix_reset(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_replace_conf(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_replace_grub_conf(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_replace_ko(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_ko_fillmap(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_fill_image_desc(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_gzip_newko(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_freebsd_ver(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_parse_freenas_ver(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_unix_freebsd_ver_elf(grub_extcmd_context_t ctxt, int argc, char **args); +int ventoy_check_device_result(int ret); +int ventoy_check_device(grub_device_t dev); +void ventoy_debug_dump_guid(const char *prefix, grub_uint8_t *guid); +grub_err_t ventoy_cmd_load_vhdboot(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_patch_vhdboot(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_raw_chain_data(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_get_vtoy_type(grub_extcmd_context_t ctxt, int argc, char **args); +int ventoy_check_password(const vtoy_password *pwd, int retry); +int ventoy_plugin_add_custom_boot(const char *vcfgpath); +const char * ventoy_plugin_get_custom_boot(const char *isopath); +grub_err_t ventoy_cmd_dump_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args); +int ventoy_gzip_compress(void *mem_in, int mem_in_len, void *mem_out, int mem_out_len); +int ventoy_load_part_table(const char *diskname); +int ventoy_env_init(void); +int ventoy_register_all_cmd(void); +int ventoy_unregister_all_cmd(void); +int ventoy_chain_file_size(const char *path); +int ventoy_chain_file_read(const char *path, int offset, int len, void *buf); + +#define VTOY_CMD_CHECK(a) if (33554432 != g_ventoy_disk_part_size[a]) ventoy_syscall0(exit) + +#define vtoy_theme_random_boot_second 0 +#define vtoy_theme_random_boot_day 1 +#define vtoy_theme_random_boot_month 2 + +#define ventoy_env_export(env, name) \ +{\ + grub_env_set((env), (name));\ + grub_env_export(env);\ +} + +#define ret_goto_end(a) ret = a; goto end; + +extern ventoy_grub_param *g_grub_param; + +#pragma pack(1) +#define VENTOY_UNIX_SEG_MAGIC0 0x11223344 +#define VENTOY_UNIX_SEG_MAGIC1 0x55667788 +#define VENTOY_UNIX_SEG_MAGIC2 0x99aabbcc +#define VENTOY_UNIX_SEG_MAGIC3 0xddeeff00 +#define VENTOY_UNIX_MAX_SEGNUM 40960 +struct g_ventoy_seg { + grub_uint64_t seg_start_bytes; + grub_uint64_t seg_end_bytes; +}; + +struct g_ventoy_map{ + grub_uint32_t magic1[4]; + grub_uint32_t magic2[4]; + grub_uint64_t segnum; + grub_uint64_t disksize; + grub_uint8_t diskuuid[16]; + struct g_ventoy_seg seglist[VENTOY_UNIX_MAX_SEGNUM]; + grub_uint32_t magic3[4]; +}; +#pragma pack() + +typedef struct ventoy_vlnk_part +{ + grub_uint32_t disksig; + grub_uint64_t partoffset; + char disk[64]; + char device[64]; + grub_device_t dev; + grub_fs_t fs; + int probe; + struct ventoy_vlnk_part *next; +}ventoy_vlnk_part; + + +typedef struct browser_mbuf +{ + int max; + int pos; + char *buf; +}browser_mbuf; + +typedef struct browser_node +{ + int dir; + char menuentry[1024]; + char filename[512]; + struct browser_node *prev; + struct browser_node *next; +}browser_node; + +typedef struct var_node +{ + char var[128]; + char val[256]; + + struct var_node *next; +}var_node; + +typedef struct systemd_menu_ctx +{ + char *dev; + char *buf; + const char *initrd_cmd; + int pos; + int len; +}systemd_menu_ctx; + +typedef struct global_var_cfg +{ + const char *name; + const char *defval; + char *value; +}global_var_cfg; + +typedef struct ctrl_var_cfg +{ + const char *name; + char szval[2]; +}ctrl_var_cfg; + +#define vtoy_check_goto_out(p) if (!p) goto out + +extern char *g_tree_script_buf; +extern int g_tree_script_pos; +extern int g_tree_script_pre; +extern int g_tree_view_menu_style; +extern int g_sort_case_sensitive; +extern int g_wimboot_enable; +extern int g_filt_dot_underscore_file; +extern int g_filt_trash_dir; +extern int g_vtoy_file_flt[VTOY_FILE_FLT_BUTT]; +extern const char *g_menu_class[img_type_max]; +extern char g_iso_path[256]; +int ventoy_add_vlnk_file(char *dir, const char *name); +grub_err_t ventoy_cmd_browser_dir(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_browser_disk(grub_extcmd_context_t ctxt, int argc, char **args); +int ventoy_get_fs_type(const char *fs); +int ventoy_img_name_valid(const char *filename, grub_size_t namelen); +void * ventoy_alloc_chain(grub_size_t size); +int ventoy_plugin_load_menu_lang(int init, const char *lang); +const char *ventoy_get_vmenu_title(const char *vMenu); +grub_err_t ventoy_cmd_cur_menu_lang(grub_extcmd_context_t ctxt, int argc, char **args); +extern int ventoy_menu_push_key(int code); +int ventoy_ctrl_var_init(void); +int ventoy_global_var_init(void); +grub_err_t ventoy_cmd_push_menulang(grub_extcmd_context_t ctxt, int argc, char **args); +grub_err_t ventoy_cmd_pop_menulang(grub_extcmd_context_t ctxt, int argc, char **args); +void ventoy_prompt_end(void); +int ventoy_set_sb_policy(void); + +#endif /* __VENTOY_DEF_H__ */ + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_json.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_json.c new file mode 100644 index 0000000..7dc5f2c --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_json.c @@ -0,0 +1,758 @@ +/****************************************************************************** + * ventoy_json.c + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ventoy_def.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +static void json_debug(const char *fmt, ...) +{ + va_list args; + + if (g_ventoy_debug == 0) + { + return; + } + + va_start (args, fmt); + grub_vprintf (fmt, args); + va_end (args); + + grub_printf("\n"); +} + +static void vtoy_json_free(VTOY_JSON *pstJsonHead) +{ + VTOY_JSON *pstNext = NULL; + + while (NULL != pstJsonHead) + { + pstNext = pstJsonHead->pstNext; + if ((pstJsonHead->enDataType < JSON_TYPE_BUTT) && (NULL != pstJsonHead->pstChild)) + { + vtoy_json_free(pstJsonHead->pstChild); + } + + grub_free(pstJsonHead); + pstJsonHead = pstNext; + } + + return; +} + +static char *vtoy_json_skip(const char *pcData) +{ + while ((NULL != pcData) && ('\0' != *pcData) && (*pcData <= 32)) + { + pcData++; + } + + return (char *)pcData; +} + +VTOY_JSON *vtoy_json_find_item +( + VTOY_JSON *pstJson, + JSON_TYPE enDataType, + const char *szKey +) +{ + while (NULL != pstJson) + { + if ((enDataType == pstJson->enDataType) && + (0 == grub_strcmp(szKey, pstJson->pcName))) + { + return pstJson; + } + pstJson = pstJson->pstNext; + } + + return NULL; +} + +static int vtoy_json_parse_number +( + VTOY_JSON *pstJson, + const char *pcData, + const char **ppcEnd +) +{ + unsigned long Value; + + Value = grub_strtoul(pcData, (char **)ppcEnd, 10); + if (*ppcEnd == pcData) + { + json_debug("Failed to parse json number %s.", pcData); + return JSON_FAILED; + } + + pstJson->enDataType = JSON_TYPE_NUMBER; + pstJson->unData.lValue = Value; + + return JSON_SUCCESS; +} + +static int vtoy_json_parse_string +( + char *pcNewStart, + char *pcRawStart, + VTOY_JSON *pstJson, + const char *pcData, + const char **ppcEnd +) +{ + grub_uint32_t uiLen = 0; + const char *pcPos = NULL; + const char *pcTmp = pcData + 1; + + *ppcEnd = pcData; + + if ('\"' != *pcData) + { + return JSON_FAILED; + } + + pcPos = grub_strchr(pcTmp, '\"'); + if ((NULL == pcPos) || (pcPos < pcTmp)) + { + json_debug("Invalid string %s.", pcData); + return JSON_FAILED; + } + + if (*(pcPos - 1) == '\\') + { + for (pcPos++; *pcPos; pcPos++) + { + if (*pcPos == '"' && *(pcPos - 1) != '\\') + { + break; + } + } + + if (*pcPos == 0 || pcPos < pcTmp) + { + json_debug("Invalid quotes string %s.", pcData); + return JSON_FAILED; + } + } + + *ppcEnd = pcPos + 1; + uiLen = (grub_uint32_t)(unsigned long)(pcPos - pcTmp); + + pstJson->enDataType = JSON_TYPE_STRING; + pstJson->unData.pcStrVal = pcNewStart + (pcTmp - pcRawStart); + pstJson->unData.pcStrVal[uiLen] = '\0'; + + return JSON_SUCCESS; +} + +static int vtoy_json_parse_array +( + char *pcNewStart, + char *pcRawStart, + VTOY_JSON *pstJson, + const char *pcData, + const char **ppcEnd +) +{ + int Ret = JSON_SUCCESS; + VTOY_JSON *pstJsonChild = NULL; + VTOY_JSON *pstJsonItem = NULL; + const char *pcTmp = pcData + 1; + + *ppcEnd = pcData; + pstJson->enDataType = JSON_TYPE_ARRAY; + + if ('[' != *pcData) + { + return JSON_FAILED; + } + + pcTmp = vtoy_json_skip(pcTmp); + + if (']' == *pcTmp) + { + *ppcEnd = pcTmp + 1; + return JSON_SUCCESS; + } + + JSON_NEW_ITEM(pstJson->pstChild, JSON_FAILED); + + Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJson->pstChild, pcTmp, ppcEnd); + if (JSON_SUCCESS != Ret) + { + json_debug("Failed to parse array child."); + return JSON_FAILED; + } + + pstJsonChild = pstJson->pstChild; + pcTmp = vtoy_json_skip(*ppcEnd); + while ((NULL != pcTmp) && (',' == *pcTmp)) + { + JSON_NEW_ITEM(pstJsonItem, JSON_FAILED); + pstJsonChild->pstNext = pstJsonItem; + pstJsonItem->pstPrev = pstJsonChild; + pstJsonChild = pstJsonItem; + + Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd); + if (JSON_SUCCESS != Ret) + { + json_debug("Failed to parse array child."); + return JSON_FAILED; + } + pcTmp = vtoy_json_skip(*ppcEnd); + } + + if ((NULL != pcTmp) && (']' == *pcTmp)) + { + *ppcEnd = pcTmp + 1; + return JSON_SUCCESS; + } + else + { + *ppcEnd = pcTmp; + return JSON_FAILED; + } +} + +static int vtoy_json_parse_object +( + char *pcNewStart, + char *pcRawStart, + VTOY_JSON *pstJson, + const char *pcData, + const char **ppcEnd +) +{ + int Ret = JSON_SUCCESS; + VTOY_JSON *pstJsonChild = NULL; + VTOY_JSON *pstJsonItem = NULL; + const char *pcTmp = pcData + 1; + + *ppcEnd = pcData; + pstJson->enDataType = JSON_TYPE_OBJECT; + + if ('{' != *pcData) + { + return JSON_FAILED; + } + + pcTmp = vtoy_json_skip(pcTmp); + if ('}' == *pcTmp) + { + *ppcEnd = pcTmp + 1; + return JSON_SUCCESS; + } + + JSON_NEW_ITEM(pstJson->pstChild, JSON_FAILED); + + Ret = vtoy_json_parse_string(pcNewStart, pcRawStart, pstJson->pstChild, pcTmp, ppcEnd); + if (JSON_SUCCESS != Ret) + { + json_debug("Failed to parse array child."); + return JSON_FAILED; + } + + pstJsonChild = pstJson->pstChild; + pstJsonChild->pcName = pstJsonChild->unData.pcStrVal; + pstJsonChild->unData.pcStrVal = NULL; + + pcTmp = vtoy_json_skip(*ppcEnd); + if ((NULL == pcTmp) || (':' != *pcTmp)) + { + *ppcEnd = pcTmp; + return JSON_FAILED; + } + + Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd); + if (JSON_SUCCESS != Ret) + { + json_debug("Failed to parse array child."); + return JSON_FAILED; + } + + pcTmp = vtoy_json_skip(*ppcEnd); + while ((NULL != pcTmp) && (',' == *pcTmp)) + { + JSON_NEW_ITEM(pstJsonItem, JSON_FAILED); + pstJsonChild->pstNext = pstJsonItem; + pstJsonItem->pstPrev = pstJsonChild; + pstJsonChild = pstJsonItem; + + Ret = vtoy_json_parse_string(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd); + if (JSON_SUCCESS != Ret) + { + json_debug("Failed to parse array child."); + return JSON_FAILED; + } + + pcTmp = vtoy_json_skip(*ppcEnd); + pstJsonChild->pcName = pstJsonChild->unData.pcStrVal; + pstJsonChild->unData.pcStrVal = NULL; + if ((NULL == pcTmp) || (':' != *pcTmp)) + { + *ppcEnd = pcTmp; + return JSON_FAILED; + } + + Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd); + if (JSON_SUCCESS != Ret) + { + json_debug("Failed to parse array child."); + return JSON_FAILED; + } + + pcTmp = vtoy_json_skip(*ppcEnd); + } + + if ((NULL != pcTmp) && ('}' == *pcTmp)) + { + *ppcEnd = pcTmp + 1; + return JSON_SUCCESS; + } + else + { + *ppcEnd = pcTmp; + return JSON_FAILED; + } +} + +int vtoy_json_parse_value +( + char *pcNewStart, + char *pcRawStart, + VTOY_JSON *pstJson, + const char *pcData, + const char **ppcEnd +) +{ + pcData = vtoy_json_skip(pcData); + + switch (*pcData) + { + case 'n': + { + if (0 == grub_strncmp(pcData, "null", 4)) + { + pstJson->enDataType = JSON_TYPE_NULL; + *ppcEnd = pcData + 4; + return JSON_SUCCESS; + } + break; + } + case 'f': + { + if (0 == grub_strncmp(pcData, "false", 5)) + { + pstJson->enDataType = JSON_TYPE_BOOL; + pstJson->unData.lValue = 0; + *ppcEnd = pcData + 5; + return JSON_SUCCESS; + } + break; + } + case 't': + { + if (0 == grub_strncmp(pcData, "true", 4)) + { + pstJson->enDataType = JSON_TYPE_BOOL; + pstJson->unData.lValue = 1; + *ppcEnd = pcData + 4; + return JSON_SUCCESS; + } + break; + } + case '\"': + { + return vtoy_json_parse_string(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd); + } + case '[': + { + return vtoy_json_parse_array(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd); + } + case '{': + { + return vtoy_json_parse_object(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd); + } + case '-': + { + return vtoy_json_parse_number(pstJson, pcData, ppcEnd); + } + default : + { + if (*pcData >= '0' && *pcData <= '9') + { + return vtoy_json_parse_number(pstJson, pcData, ppcEnd); + } + } + } + + *ppcEnd = pcData; + json_debug("Invalid json data %u.", (grub_uint8_t)(*pcData)); + return JSON_FAILED; +} + +VTOY_JSON * vtoy_json_create(void) +{ + VTOY_JSON *pstJson = NULL; + + pstJson = (VTOY_JSON *)grub_zalloc(sizeof(VTOY_JSON)); + if (NULL == pstJson) + { + return NULL; + } + + return pstJson; +} + +int vtoy_json_parse(VTOY_JSON *pstJson, const char *szJsonData) +{ + grub_uint32_t uiMemSize = 0; + int Ret = JSON_SUCCESS; + char *pcNewBuf = NULL; + const char *pcEnd = NULL; + + uiMemSize = grub_strlen(szJsonData) + 1; + pcNewBuf = (char *)grub_malloc(uiMemSize); + if (NULL == pcNewBuf) + { + json_debug("Failed to alloc new buf."); + return JSON_FAILED; + } + grub_memcpy(pcNewBuf, szJsonData, uiMemSize); + pcNewBuf[uiMemSize - 1] = 0; + + Ret = vtoy_json_parse_value(pcNewBuf, (char *)szJsonData, pstJson, szJsonData, &pcEnd); + if (JSON_SUCCESS != Ret) + { + json_debug("Failed to parse json data %s start=%p, end=%p:%s.", + szJsonData, szJsonData, pcEnd, pcEnd); + return JSON_FAILED; + } + + return JSON_SUCCESS; +} + +int vtoy_json_scan_parse +( + const VTOY_JSON *pstJson, + grub_uint32_t uiParseNum, + JSON_PARSE *pstJsonParse +) +{ + grub_uint32_t i = 0; + const VTOY_JSON *pstJsonCur = NULL; + JSON_PARSE *pstCurParse = NULL; + + for (pstJsonCur = pstJson; NULL != pstJsonCur; pstJsonCur = pstJsonCur->pstNext) + { + if ((JSON_TYPE_OBJECT == pstJsonCur->enDataType) || + (JSON_TYPE_ARRAY == pstJsonCur->enDataType)) + { + continue; + } + + for (i = 0, pstCurParse = NULL; i < uiParseNum; i++) + { + if (0 == grub_strcmp(pstJsonParse[i].pcKey, pstJsonCur->pcName)) + { + pstCurParse = pstJsonParse + i; + break; + } + } + + if (NULL == pstCurParse) + { + continue; + } + + switch (pstJsonCur->enDataType) + { + case JSON_TYPE_NUMBER: + { + if (sizeof(grub_uint32_t) == pstCurParse->uiBufSize) + { + *(grub_uint32_t *)(pstCurParse->pDataBuf) = (grub_uint32_t)pstJsonCur->unData.lValue; + } + else if (sizeof(grub_uint16_t) == pstCurParse->uiBufSize) + { + *(grub_uint16_t *)(pstCurParse->pDataBuf) = (grub_uint16_t)pstJsonCur->unData.lValue; + } + else if (sizeof(grub_uint8_t) == pstCurParse->uiBufSize) + { + *(grub_uint8_t *)(pstCurParse->pDataBuf) = (grub_uint8_t)pstJsonCur->unData.lValue; + } + else if ((pstCurParse->uiBufSize > sizeof(grub_uint64_t))) + { + grub_snprintf((char *)pstCurParse->pDataBuf, pstCurParse->uiBufSize, "%llu", + (unsigned long long)(pstJsonCur->unData.lValue)); + } + else + { + json_debug("Invalid number data buf size %u.", pstCurParse->uiBufSize); + } + break; + } + case JSON_TYPE_STRING: + { + grub_strncpy((char *)pstCurParse->pDataBuf, pstJsonCur->unData.pcStrVal, pstCurParse->uiBufSize); + break; + } + case JSON_TYPE_BOOL: + { + *(grub_uint8_t *)(pstCurParse->pDataBuf) = (pstJsonCur->unData.lValue) > 0 ? 1 : 0; + break; + } + default : + { + break; + } + } + } + + return JSON_SUCCESS; +} + +int vtoy_json_scan_array +( + VTOY_JSON *pstJson, + const char *szKey, + VTOY_JSON **ppstArrayItem +) +{ + VTOY_JSON *pstJsonItem = NULL; + + pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_ARRAY, szKey); + if (NULL == pstJsonItem) + { + json_debug("Key %s is not found in json data.", szKey); + return JSON_NOT_FOUND; + } + + *ppstArrayItem = pstJsonItem; + + return JSON_SUCCESS; +} + +int vtoy_json_scan_array_ex +( + VTOY_JSON *pstJson, + const char *szKey, + VTOY_JSON **ppstArrayItem +) +{ + VTOY_JSON *pstJsonItem = NULL; + + pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_ARRAY, szKey); + if (NULL == pstJsonItem) + { + json_debug("Key %s is not found in json data.", szKey); + return JSON_NOT_FOUND; + } + + *ppstArrayItem = pstJsonItem->pstChild; + + return JSON_SUCCESS; +} + +int vtoy_json_scan_object +( + VTOY_JSON *pstJson, + const char *szKey, + VTOY_JSON **ppstObjectItem +) +{ + VTOY_JSON *pstJsonItem = NULL; + + pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_OBJECT, szKey); + if (NULL == pstJsonItem) + { + json_debug("Key %s is not found in json data.", szKey); + return JSON_NOT_FOUND; + } + + *ppstObjectItem = pstJsonItem; + + return JSON_SUCCESS; +} + +int vtoy_json_get_int +( + VTOY_JSON *pstJson, + const char *szKey, + int *piValue +) +{ + VTOY_JSON *pstJsonItem = NULL; + + pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey); + if (NULL == pstJsonItem) + { + json_debug("Key %s is not found in json data.", szKey); + return JSON_NOT_FOUND; + } + + *piValue = (int)pstJsonItem->unData.lValue; + + return JSON_SUCCESS; +} + +int vtoy_json_get_uint +( + VTOY_JSON *pstJson, + const char *szKey, + grub_uint32_t *puiValue +) +{ + VTOY_JSON *pstJsonItem = NULL; + + pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey); + if (NULL == pstJsonItem) + { + json_debug("Key %s is not found in json data.", szKey); + return JSON_NOT_FOUND; + } + + *puiValue = (grub_uint32_t)pstJsonItem->unData.lValue; + + return JSON_SUCCESS; +} + +int vtoy_json_get_uint64 +( + VTOY_JSON *pstJson, + const char *szKey, + grub_uint64_t *pui64Value +) +{ + VTOY_JSON *pstJsonItem = NULL; + + pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey); + if (NULL == pstJsonItem) + { + json_debug("Key %s is not found in json data.", szKey); + return JSON_NOT_FOUND; + } + + *pui64Value = (grub_uint64_t)pstJsonItem->unData.lValue; + + return JSON_SUCCESS; +} + +int vtoy_json_get_bool +( + VTOY_JSON *pstJson, + const char *szKey, + grub_uint8_t *pbValue +) +{ + VTOY_JSON *pstJsonItem = NULL; + + pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_BOOL, szKey); + if (NULL == pstJsonItem) + { + json_debug("Key %s is not found in json data.", szKey); + return JSON_NOT_FOUND; + } + + *pbValue = pstJsonItem->unData.lValue > 0 ? 1 : 0; + + return JSON_SUCCESS; +} + +int vtoy_json_get_string +( + VTOY_JSON *pstJson, + const char *szKey, + grub_uint32_t uiBufLen, + char *pcBuf +) +{ + VTOY_JSON *pstJsonItem = NULL; + + pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_STRING, szKey); + if (NULL == pstJsonItem) + { + json_debug("Key %s is not found in json data.", szKey); + return JSON_NOT_FOUND; + } + + grub_strncpy(pcBuf, pstJsonItem->unData.pcStrVal, uiBufLen); + + return JSON_SUCCESS; +} + +const char * vtoy_json_get_string_ex(VTOY_JSON *pstJson, const char *szKey) +{ + VTOY_JSON *pstJsonItem = NULL; + + if ((NULL == pstJson) || (NULL == szKey)) + { + return NULL; + } + + pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_STRING, szKey); + if (NULL == pstJsonItem) + { + json_debug("Key %s is not found in json data.", szKey); + return NULL; + } + + return pstJsonItem->unData.pcStrVal; +} + +int vtoy_json_destroy(VTOY_JSON *pstJson) +{ + if (NULL == pstJson) + { + return JSON_SUCCESS; + } + + if (NULL != pstJson->pstChild) + { + vtoy_json_free(pstJson->pstChild); + } + + if (NULL != pstJson->pstNext) + { + vtoy_json_free(pstJson->pstNext); + } + + grub_free(pstJson); + + return JSON_SUCCESS; +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c new file mode 100644 index 0000000..7ff18ff --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_linux.c @@ -0,0 +1,2120 @@ +/****************************************************************************** + * ventoy_linux.c + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ventoy_def.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define VTOY_APPEND_EXT_SIZE 4096 +static int g_append_ext_sector = 0; + +char * ventoy_get_line(char *start) +{ + if (start == NULL) + { + return NULL; + } + + while (*start && *start != '\n') + { + start++; + } + + if (*start == 0) + { + return NULL; + } + else + { + *start = 0; + return start + 1; + } +} + +static initrd_info * ventoy_find_initrd_by_name(initrd_info *list, const char *name) +{ + initrd_info *node = list; + + while (node) + { + if (grub_strcmp(node->name, name) == 0) + { + return node; + } + node = node->next; + } + + return NULL; +} + +grub_err_t ventoy_cmd_clear_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args) +{ + initrd_info *node = g_initrd_img_list; + initrd_info *next; + + (void)ctxt; + (void)argc; + (void)args; + + while (node) + { + next = node->next; + grub_free(node); + node = next; + } + + g_initrd_img_list = NULL; + g_initrd_img_tail = NULL; + g_initrd_img_count = 0; + g_valid_initrd_count = 0; + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_dump_initrd_list(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i = 0; + initrd_info *node = g_initrd_img_list; + + (void)ctxt; + (void)argc; + (void)args; + + grub_printf("###################\n"); + grub_printf("initrd info list: valid count:%d\n", g_valid_initrd_count); + + while (node) + { + grub_printf("%s ", node->size > 0 ? "*" : " "); + grub_printf("%02u %s offset:%llu size:%llu \n", i++, node->name, (unsigned long long)node->offset, + (unsigned long long)node->size); + node = node->next; + } + + grub_printf("###################\n"); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static void ventoy_parse_directory(char *path, char *dir, int buflen) +{ + int end; + char *pos; + + pos = grub_strstr(path, ")"); + if (!pos) + { + pos = path; + } + + end = grub_snprintf(dir, buflen, "%s", pos + 1); + while (end > 0) + { + if (dir[end] == '/') + { + dir[end + 1] = 0; + break; + } + end--; + } +} + +static grub_err_t ventoy_isolinux_initrd_collect(grub_file_t file, const char *prefix) +{ + int i = 0; + int offset; + int prefixlen = 0; + char *buf = NULL; + char *pos = NULL; + char *start = NULL; + char *nextline = NULL; + initrd_info *img = NULL; + + prefixlen = grub_strlen(prefix); + + buf = grub_zalloc(file->size + 2); + if (!buf) + { + return 0; + } + + grub_file_read(file, buf, file->size); + + for (start = buf; start; start = nextline) + { + nextline = ventoy_get_line(start); + + VTOY_SKIP_SPACE(start); + + offset = 7; // strlen("initrd=") or "INITRD " or "initrd " + pos = grub_strstr(start, "initrd="); + if (pos == NULL) + { + pos = start; + + if (grub_strncmp(start, "INITRD", 6) != 0 && grub_strncmp(start, "initrd", 6) != 0) + { + if (grub_strstr(start, "xen") && + ((pos = grub_strstr(start, "--- /install.img")) != NULL || + (pos = grub_strstr(start, "--- initrd.img")) != NULL + )) + { + offset = 4; // "--- " + } + else + { + continue; + } + } + } + + pos += offset; + + while (1) + { + i = 0; + img = grub_zalloc(sizeof(initrd_info)); + if (!img) + { + break; + } + + if (*pos != '/') + { + grub_strcpy(img->name, prefix); + i = prefixlen; + } + + while (i < 255 && (0 == ventoy_is_word_end(*pos))) + { + img->name[i++] = *pos++; + } + + if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name)) + { + grub_free(img); + } + else + { + if (g_initrd_img_list) + { + img->prev = g_initrd_img_tail; + g_initrd_img_tail->next = img; + } + else + { + g_initrd_img_list = img; + } + + g_initrd_img_tail = img; + g_initrd_img_count++; + } + + if (*pos == ',') + { + pos++; + } + else + { + break; + } + } + } + + grub_free(buf); + return GRUB_ERR_NONE; +} + +static int ventoy_isolinux_initrd_hook(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + grub_file_t file = NULL; + ventoy_initrd_ctx *ctx = (ventoy_initrd_ctx *)data; + + (void)info; + + if (NULL == grub_strstr(filename, ".cfg") && NULL == grub_strstr(filename, ".CFG")) + { + return 0; + } + + debug("init hook dir <%s%s>\n", ctx->path_prefix, filename); + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", ctx->path_prefix, filename); + if (!file) + { + return 0; + } + + ventoy_isolinux_initrd_collect(file, ctx->dir_prefix); + grub_file_close(file); + + return 0; +} + +grub_err_t ventoy_cmd_isolinux_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_fs_t fs; + grub_device_t dev = NULL; + char *device_name = NULL; + ventoy_initrd_ctx ctx; + char directory[256]; + + (void)ctxt; + (void)argc; + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + goto end; + } + + dev = grub_device_open(device_name); + if (!dev) + { + goto end; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + goto end; + } + + debug("isolinux initrd collect %s\n", args[0]); + + ventoy_parse_directory(args[0], directory, sizeof(directory) - 1); + ctx.path_prefix = args[0]; + ctx.dir_prefix = (argc > 1) ? args[1] : directory; + + debug("path_prefix=<%s> dir_prefix=<%s>\n", ctx.path_prefix, ctx.dir_prefix); + + fs->fs_dir(dev, directory, ventoy_isolinux_initrd_hook, &ctx); + +end: + check_free(device_name, grub_free); + check_free(dev, grub_device_close); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_linux_initrd_collect_hook(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + int len; + initrd_info *img = NULL; + + (void)data; + + if (0 == info->dir) + { + if (grub_strncmp(filename, "initrd", 6) == 0) + { + len = (int)grub_strlen(filename); + if (grub_strcmp(filename + len - 4, ".img") == 0) + { + img = grub_zalloc(sizeof(initrd_info)); + if (img) + { + grub_snprintf(img->name, sizeof(img->name), "/boot/%s", filename); + + if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name)) + { + grub_free(img); + } + else + { + if (g_initrd_img_list) + { + img->prev = g_initrd_img_tail; + g_initrd_img_tail->next = img; + } + else + { + g_initrd_img_list = img; + } + + g_initrd_img_tail = img; + g_initrd_img_count++; + } + } + } + } + } + + return 0; +} + +static int ventoy_linux_collect_boot_initrds(void) +{ + grub_fs_t fs; + grub_device_t dev = NULL; + + dev = grub_device_open("loop"); + if (!dev) + { + debug("failed to open device loop\n"); + goto end; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + debug("failed to probe fs %d\n", grub_errno); + goto end; + } + + fs->fs_dir(dev, "/boot", ventoy_linux_initrd_collect_hook, NULL); + +end: + return 0; +} + +static grub_err_t ventoy_grub_cfg_initrd_collect(const char *fileName) +{ + int i = 0; + int len = 0; + int dollar = 0; + int quotation = 0; + int initrd_dollar = 0; + grub_file_t file = NULL; + char *buf = NULL; + char *start = NULL; + char *nextline = NULL; + initrd_info *img = NULL; + + debug("grub initrd collect %s\n", fileName); + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", fileName); + if (!file) + { + return 0; + } + + buf = grub_zalloc(file->size + 2); + if (!buf) + { + grub_file_close(file); + return 0; + } + + grub_file_read(file, buf, file->size); + + for (start = buf; start; start = nextline) + { + nextline = ventoy_get_line(start); + + VTOY_SKIP_SPACE(start); + + if (grub_strncmp(start, "initrd", 6) != 0) + { + continue; + } + + start += 6; + while (*start && (!ventoy_isspace(*start))) + { + start++; + } + + VTOY_SKIP_SPACE(start); + + if (*start == '"') + { + quotation = 1; + start++; + } + + while (*start) + { + img = grub_zalloc(sizeof(initrd_info)); + if (!img) + { + break; + } + + dollar = 0; + for (i = 0; i < 255 && (0 == ventoy_is_word_end(*start)); i++) + { + img->name[i] = *start++; + if (img->name[i] == '$') + { + dollar = 1; + } + } + + if (quotation) + { + len = (int)grub_strlen(img->name); + if (len > 2 && img->name[len - 1] == '"') + { + img->name[len - 1] = 0; + } + debug("Remove quotation <%s>\n", img->name); + } + + /* special process for /boot/initrd$XXX.img */ + if (dollar == 1) + { + if (grub_strncmp(img->name, "/boot/initrd$", 13) == 0) + { + len = (int)grub_strlen(img->name); + if (grub_strcmp(img->name + len - 4, ".img") == 0) + { + initrd_dollar++; + } + } + } + + if (dollar == 1 || ventoy_find_initrd_by_name(g_initrd_img_list, img->name)) + { + grub_free(img); + } + else + { + if (g_initrd_img_list) + { + img->prev = g_initrd_img_tail; + g_initrd_img_tail->next = img; + } + else + { + g_initrd_img_list = img; + } + + g_initrd_img_tail = img; + g_initrd_img_count++; + } + + if (*start == ' ' || *start == '\t') + { + VTOY_SKIP_SPACE(start); + } + else + { + break; + } + } + } + + grub_free(buf); + grub_file_close(file); + + if (initrd_dollar > 0 && grub_strncmp(fileName, "(loop)/", 7) == 0) + { + debug("collect initrd variable %d\n", initrd_dollar); + ventoy_linux_collect_boot_initrds(); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_grub_initrd_hook(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + char filePath[256]; + ventoy_initrd_ctx *ctx = (ventoy_initrd_ctx *)data; + + (void)info; + + debug("ventoy_grub_initrd_hook %s\n", filename); + + if (NULL == grub_strstr(filename, ".cfg") && + NULL == grub_strstr(filename, ".CFG") && + NULL == grub_strstr(filename, ".conf")) + { + return 0; + } + + debug("init hook dir <%s%s>\n", ctx->path_prefix, filename); + + grub_snprintf(filePath, sizeof(filePath) - 1, "%s%s", ctx->dir_prefix, filename); + ventoy_grub_cfg_initrd_collect(filePath); + + return 0; +} + +grub_err_t ventoy_cmd_grub_initrd_collect(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_fs_t fs; + grub_device_t dev = NULL; + char *device_name = NULL; + ventoy_initrd_ctx ctx; + + (void)ctxt; + (void)argc; + + if (argc != 2) + { + return 0; + } + + debug("grub initrd collect %s %s\n", args[0], args[1]); + + if (grub_strcmp(args[0], "file") == 0) + { + return ventoy_grub_cfg_initrd_collect(args[1]); + } + + device_name = grub_file_get_device_name(args[1]); + if (!device_name) + { + debug("failed to get device name %s\n", args[1]); + goto end; + } + + dev = grub_device_open(device_name); + if (!dev) + { + debug("failed to open device %s\n", device_name); + goto end; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + debug("failed to probe fs %d\n", grub_errno); + goto end; + } + + ctx.dir_prefix = args[1]; + ctx.path_prefix = grub_strstr(args[1], device_name); + if (ctx.path_prefix) + { + ctx.path_prefix += grub_strlen(device_name) + 1; + } + else + { + ctx.path_prefix = args[1]; + } + + debug("ctx.path_prefix:<%s>\n", ctx.path_prefix); + + fs->fs_dir(dev, ctx.path_prefix, ventoy_grub_initrd_hook, &ctx); + +end: + check_free(device_name, grub_free); + check_free(dev, grub_device_close); + + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_specify_initrd_file(grub_extcmd_context_t ctxt, int argc, char **args) +{ + initrd_info *img = NULL; + + (void)ctxt; + (void)argc; + + debug("ventoy_cmd_specify_initrd_file %s\n", args[0]); + + img = grub_zalloc(sizeof(initrd_info)); + if (!img) + { + return 1; + } + + grub_strncpy(img->name, args[0], sizeof(img->name)); + if (ventoy_find_initrd_by_name(g_initrd_img_list, img->name)) + { + debug("%s is already exist\n", args[0]); + grub_free(img); + } + else + { + if (g_initrd_img_list) + { + img->prev = g_initrd_img_tail; + g_initrd_img_tail->next = img; + } + else + { + g_initrd_img_list = img; + } + + g_initrd_img_tail = img; + g_initrd_img_count++; + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_cpio_newc_get_int(char *value) +{ + char buf[16] = {0}; + + grub_memcpy(buf, value, 8); + return (int)grub_strtoul(buf, NULL, 16); +} + +static void ventoy_cpio_newc_fill_int(grub_uint32_t value, char *buf, int buflen) +{ + int i; + int len; + char intbuf[32]; + + len = grub_snprintf(intbuf, sizeof(intbuf), "%x", value); + + for (i = 0; i < buflen; i++) + { + buf[i] = '0'; + } + + if (len > buflen) + { + grub_printf("int buf len overflow %d %d\n", len, buflen); + } + else + { + grub_memcpy(buf + buflen - len, intbuf, len); + } +} + +int ventoy_cpio_newc_fill_head(void *buf, int filesize, const void *filedata, const char *name) +{ + int namelen = 0; + int headlen = 0; + static grub_uint32_t cpio_ino = 0xFFFFFFF0; + cpio_newc_header *cpio = (cpio_newc_header *)buf; + + namelen = grub_strlen(name) + 1; + headlen = sizeof(cpio_newc_header) + namelen; + headlen = ventoy_align(headlen, 4); + + grub_memset(cpio, '0', sizeof(cpio_newc_header)); + grub_memset(cpio + 1, 0, headlen - sizeof(cpio_newc_header)); + + grub_memcpy(cpio->c_magic, "070701", 6); + ventoy_cpio_newc_fill_int(cpio_ino--, cpio->c_ino, 8); + ventoy_cpio_newc_fill_int(0100777, cpio->c_mode, 8); + ventoy_cpio_newc_fill_int(1, cpio->c_nlink, 8); + ventoy_cpio_newc_fill_int(filesize, cpio->c_filesize, 8); + ventoy_cpio_newc_fill_int(namelen, cpio->c_namesize, 8); + grub_memcpy(cpio + 1, name, namelen); + + if (filedata) + { + grub_memcpy((char *)cpio + headlen, filedata, filesize); + } + + return headlen; +} + +static grub_uint32_t ventoy_linux_get_virt_chunk_count(void) +{ + int i; + grub_uint32_t count = g_valid_initrd_count; + + if (g_conf_replace_count > 0) + { + for (i = 0; i < g_conf_replace_count; i++) + { + if (g_conf_replace_offset[i] > 0) + { + count++; + } + } + } + + if (g_append_ext_sector > 0) + { + count++; + } + + return count; +} + +static grub_uint32_t ventoy_linux_get_virt_chunk_size(void) +{ + int i; + grub_uint32_t size; + + size = (sizeof(ventoy_virt_chunk) + g_ventoy_cpio_size) * g_valid_initrd_count; + + if (g_conf_replace_count > 0) + { + for (i = 0; i < g_conf_replace_count; i++) + { + if (g_conf_replace_offset[i] > 0) + { + size += sizeof(ventoy_virt_chunk) + g_conf_replace_new_len_align[i]; + } + } + } + + if (g_append_ext_sector > 0) + { + size += sizeof(ventoy_virt_chunk) + VTOY_APPEND_EXT_SIZE; + } + + return size; +} + +static void ventoy_linux_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain) +{ + int i = 0; + int id = 0; + int virtid = 0; + initrd_info *node; + grub_uint64_t sector; + grub_uint32_t offset; + grub_uint32_t cpio_secs; + grub_uint32_t initrd_secs; + char *override; + ventoy_virt_chunk *cur; + ventoy_grub_param_file_replace *replace = NULL; + char name[32]; + + override = (char *)chain + chain->virt_chunk_offset; + sector = (isosize + 2047) / 2048; + cpio_secs = g_ventoy_cpio_size / 2048; + + offset = ventoy_linux_get_virt_chunk_count() * sizeof(ventoy_virt_chunk); + cur = (ventoy_virt_chunk *)override; + + for (node = g_initrd_img_list; node; node = node->next) + { + if (node->size == 0) + { + continue; + } + + initrd_secs = (grub_uint32_t)((node->size + 2047) / 2048); + + cur->mem_sector_start = sector; + cur->mem_sector_end = cur->mem_sector_start + cpio_secs; + cur->mem_sector_offset = offset; + cur->remap_sector_start = cur->mem_sector_end; + cur->remap_sector_end = cur->remap_sector_start + initrd_secs; + cur->org_sector_start = (grub_uint32_t)(node->offset / 2048); + + grub_memcpy(g_ventoy_runtime_buf, &chain->os_param, sizeof(ventoy_os_param)); + + grub_memset(name, 0, 16); + grub_snprintf(name, sizeof(name), "initrd%03d", ++id); + + grub_memcpy(g_ventoy_initrd_head + 1, name, 16); + ventoy_cpio_newc_fill_int((grub_uint32_t)node->size, g_ventoy_initrd_head->c_filesize, 8); + + grub_memcpy(override + offset, g_ventoy_cpio_buf, g_ventoy_cpio_size); + + chain->virt_img_size_in_bytes += g_ventoy_cpio_size + initrd_secs * 2048; + + offset += g_ventoy_cpio_size; + sector += cpio_secs + initrd_secs; + cur++; + virtid++; + } + + /* Lenovo EasyStartup need an addional sector for boundary check */ + if (g_append_ext_sector > 0) + { + cpio_secs = VTOY_APPEND_EXT_SIZE / 2048; + + cur->mem_sector_start = sector; + cur->mem_sector_end = cur->mem_sector_start + cpio_secs; + cur->mem_sector_offset = offset; + cur->remap_sector_start = 0; + cur->remap_sector_end = 0; + cur->org_sector_start = 0; + + grub_memset(override + offset, 0, VTOY_APPEND_EXT_SIZE); + + chain->virt_img_size_in_bytes += VTOY_APPEND_EXT_SIZE; + + offset += VTOY_APPEND_EXT_SIZE; + sector += cpio_secs; + cur++; + virtid++; + } + + if (g_conf_replace_count > 0) + { + for (i = 0; i < g_conf_replace_count; i++) + { + if (g_conf_replace_offset[i] > 0) + { + cpio_secs = g_conf_replace_new_len_align[i] / 2048; + + cur->mem_sector_start = sector; + cur->mem_sector_end = cur->mem_sector_start + cpio_secs; + cur->mem_sector_offset = offset; + cur->remap_sector_start = 0; + cur->remap_sector_end = 0; + cur->org_sector_start = 0; + + grub_memcpy(override + offset, g_conf_replace_new_buf[i], g_conf_replace_new_len[i]); + + chain->virt_img_size_in_bytes += g_conf_replace_new_len_align[i]; + + replace = g_grub_param->img_replace + i; + if (replace->magic == GRUB_IMG_REPLACE_MAGIC) + { + replace->new_file_virtual_id = virtid; + } + + offset += g_conf_replace_new_len_align[i]; + sector += cpio_secs; + cur++; + virtid++; + } + } + } + + return; +} + +static grub_uint32_t ventoy_linux_get_override_chunk_count(void) +{ + int i; + grub_uint32_t count = g_valid_initrd_count; + + if (g_conf_replace_count > 0) + { + for (i = 0; i < g_conf_replace_count; i++) + { + if (g_conf_replace_offset[i] > 0) + { + count++; + } + } + } + + if (g_svd_replace_offset > 0) + { + count++; + } + + return count; +} + +static grub_uint32_t ventoy_linux_get_override_chunk_size(void) +{ + int i; + int count = g_valid_initrd_count; + + if (g_conf_replace_count > 0) + { + for (i = 0; i < g_conf_replace_count; i++) + { + if (g_conf_replace_offset[i] > 0) + { + count++; + } + } + } + + if (g_svd_replace_offset > 0) + { + count++; + } + + return sizeof(ventoy_override_chunk) * count; +} + +static void ventoy_linux_fill_override_data( grub_uint64_t isosize, void *override) +{ + int i; + initrd_info *node; + grub_uint32_t mod; + grub_uint32_t newlen; + grub_uint64_t sector; + ventoy_override_chunk *cur; + ventoy_iso9660_override *dirent; + ventoy_udf_override *udf; + + sector = (isosize + 2047) / 2048; + + cur = (ventoy_override_chunk *)override; + for (node = g_initrd_img_list; node; node = node->next) + { + if (node->size == 0) + { + continue; + } + + newlen = (grub_uint32_t)(node->size + g_ventoy_cpio_size); + mod = newlen % 4; + if (mod > 0) + { + newlen += 4 - mod; /* cpio must align with 4 */ + } + + if (node->iso_type == 0) + { + dirent = (ventoy_iso9660_override *)node->override_data; + + node->override_length = sizeof(ventoy_iso9660_override); + dirent->first_sector = (grub_uint32_t)sector; + dirent->size = newlen; + dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector); + dirent->size_be = grub_swap_bytes32(dirent->size); + + sector += (dirent->size + 2047) / 2048; + } + else + { + udf = (ventoy_udf_override *)node->override_data; + + node->override_length = sizeof(ventoy_udf_override); + udf->length = newlen; + udf->position = (grub_uint32_t)sector - node->udf_start_block; + + sector += (udf->length + 2047) / 2048; + } + + cur->img_offset = node->override_offset; + cur->override_size = node->override_length; + grub_memcpy(cur->override_data, node->override_data, cur->override_size); + cur++; + } + + if (g_conf_replace_count > 0) + { + for (i = 0; i < g_conf_replace_count; i++) + { + if (g_conf_replace_offset[i] > 0) + { + cur->img_offset = g_conf_replace_offset[i]; + cur->override_size = sizeof(ventoy_iso9660_override); + + newlen = (grub_uint32_t)(g_conf_replace_new_len[i]); + + dirent = (ventoy_iso9660_override *)cur->override_data; + dirent->first_sector = (grub_uint32_t)sector; + dirent->size = newlen; + dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector); + dirent->size_be = grub_swap_bytes32(dirent->size); + + sector += (dirent->size + 2047) / 2048; + cur++; + } + } + } + + if (g_svd_replace_offset > 0) + { + cur->img_offset = g_svd_replace_offset; + cur->override_size = 1; + cur->override_data[0] = 0xFF; + cur++; + } + + return; +} + +grub_err_t ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char buf[32] = {0}; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc == 1) + { + grub_snprintf(buf, sizeof(buf), "%d", g_initrd_img_count); + grub_env_set(args[0], buf); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char buf[32] = {0}; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc == 1) + { + grub_snprintf(buf, sizeof(buf), "%d", g_valid_initrd_count); + grub_env_set(args[0], buf); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_linux_locate_initrd(int filt, int *filtcnt) +{ + int data; + int filtbysize = 1; + int sizefilt = 0; + grub_file_t file; + initrd_info *node; + + debug("ventoy_linux_locate_initrd %d\n", filt); + + g_valid_initrd_count = 0; + + if (grub_env_get("INITRD_NO_SIZE_FILT")) + { + filtbysize = 0; + } + + for (node = g_initrd_img_list; node; node = node->next) + { + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", node->name); + if (!file) + { + continue; + } + + debug("file <%s> size:%d\n", node->name, (int)file->size); + + /* initrd file too small */ + if (filtbysize + && (NULL == grub_strstr(node->name, "minirt.gz")) + && (NULL == grub_strstr(node->name, "initrd.xz")) + && (NULL == grub_strstr(node->name, "initrd.gz")) + ) + { + if (filt > 0 && file->size <= g_ventoy_cpio_size + 2048) + { + debug("file size too small %d\n", (int)g_ventoy_cpio_size); + grub_file_close(file); + sizefilt++; + continue; + } + } + + /* skip hdt.img */ + if (file->size <= VTOY_SIZE_1MB && grub_strcmp(node->name, "/boot/hdt.img") == 0) + { + continue; + } + + if (grub_strcmp(file->fs->name, "iso9660") == 0) + { + node->iso_type = 0; + node->override_offset = grub_iso9660_get_last_file_dirent_pos(file) + 2; + + grub_file_read(file, &data, 1); // just read for hook trigger + node->offset = grub_iso9660_get_last_read_pos(file); + } + else + { + /* TBD */ + } + + node->size = file->size; + g_valid_initrd_count++; + + grub_file_close(file); + } + + *filtcnt = sizefilt; + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + + +grub_err_t ventoy_cmd_linux_get_main_initrd_index(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int index = 0; + char buf[32]; + initrd_info *node = NULL; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc != 1) + { + return 1; + } + + if (g_initrd_img_count == 1) + { + ventoy_set_env(args[0], "0"); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); + } + + for (node = g_initrd_img_list; node; node = node->next) + { + if (node->size <= 0) + { + continue; + } + + if (grub_strstr(node->name, "ucode") || grub_strstr(node->name, "-firmware")) + { + index++; + continue; + } + + grub_snprintf(buf, sizeof(buf), "%d", index); + ventoy_set_env(args[0], buf); + break; + } + + debug("main initrd index:%d\n", index); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_linux_locate_initrd(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int sizefilt = 0; + + (void)ctxt; + (void)argc; + (void)args; + + ventoy_linux_locate_initrd(1, &sizefilt); + + if (g_valid_initrd_count == 0 && sizefilt > 0) + { + ventoy_linux_locate_initrd(0, &sizefilt); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_cpio_busybox64(cpio_newc_header *head, const char *file) +{ + char *name; + int namelen; + int offset; + int count = 0; + char filepath[128]; + + grub_snprintf(filepath, sizeof(filepath), "ventoy/busybox/%s", file); + + name = (char *)(head + 1); + while (name[0] && count < 2) + { + if (grub_strcmp(name, "ventoy/busybox/ash") == 0) + { + grub_memcpy(name, "ventoy/busybox/32h", 18); + count++; + } + else if (grub_strcmp(name, filepath) == 0) + { + grub_memcpy(name, "ventoy/busybox/ash", 18); + count++; + } + + namelen = ventoy_cpio_newc_get_int(head->c_namesize); + offset = sizeof(cpio_newc_header) + namelen; + offset = ventoy_align(offset, 4); + offset += ventoy_cpio_newc_get_int(head->c_filesize); + offset = ventoy_align(offset, 4); + + head = (cpio_newc_header *)((char *)head + offset); + name = (char *)(head + 1); + } + + return 0; +} + + +grub_err_t ventoy_cmd_cpio_busybox_64(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + debug("ventoy_cmd_busybox_64 %d\n", argc); + ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, args[0]); + return 0; +} + +grub_err_t ventoy_cmd_skip_svd(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + grub_file_t file; + char buf[16]; + + (void)ctxt; + (void)argc; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s\n", args[0]); + } + + for (i = 0; i < 10; i++) + { + buf[0] = 0; + grub_file_seek(file, (17 + i) * 2048); + grub_file_read(file, buf, 16); + + if (buf[0] == 2 && grub_strncmp(buf + 1, "CD001", 5) == 0) + { + debug("Find SVD at VD %d\n", i); + g_svd_replace_offset = (17 + i) * 2048; + break; + } + } + + if (i >= 10) + { + debug("SVD not found %d\n", (int)g_svd_replace_offset); + } + + grub_file_close(file); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_append_ext_sector(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + if (args[0][0] == '1') + { + g_append_ext_sector = 1; + } + else + { + g_append_ext_sector = 0; + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int rc; + char *pos = NULL; + char *template_file = NULL; + char *template_buf = NULL; + char *persistent_buf = NULL; + char *injection_buf = NULL; + dud *dudnode = NULL; + char tmpname[128]; + const char *injection_file = NULL; + grub_uint8_t *buf = NULL; + grub_uint32_t mod; + grub_uint32_t headlen; + grub_uint32_t initrd_head_len; + grub_uint32_t padlen; + grub_uint32_t img_chunk_size; + grub_uint32_t template_size = 0; + grub_uint32_t persistent_size = 0; + grub_uint32_t injection_size = 0; + grub_uint32_t dud_size = 0; + grub_file_t file; + grub_file_t archfile; + grub_file_t tmpfile; + install_template *template_node = NULL; + ventoy_img_chunk_list chunk_list; + + (void)ctxt; + (void)argc; + + if (argc != 4) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s cpiofile\n", cmd_raw_name); + } + + if (g_img_chunk_list.chunk == NULL || g_img_chunk_list.cur_chunk == 0) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "image chunk is null\n"); + } + + img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk); + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/%s", args[0], VTOY_COMM_CPIO); + if (!file) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s/%s\n", args[0], VTOY_COMM_CPIO); + } + + archfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/%s", args[0], VTOY_ARCH_CPIO); + if (!archfile) + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't open file %s/%s\n", args[0], VTOY_ARCH_CPIO); + grub_file_close(file); + } + + debug("load %s %s success\n", VTOY_COMM_CPIO, VTOY_ARCH_CPIO); + + if (g_ventoy_cpio_buf) + { + grub_free(g_ventoy_cpio_buf); + g_ventoy_cpio_buf = NULL; + g_ventoy_cpio_size = 0; + } + + rc = ventoy_plugin_get_persistent_chunklist(args[1], -1, &chunk_list); + if (rc == 0 && chunk_list.cur_chunk > 0 && chunk_list.chunk) + { + persistent_size = chunk_list.cur_chunk * sizeof(ventoy_img_chunk); + persistent_buf = (char *)(chunk_list.chunk); + } + + template_file = ventoy_plugin_get_cur_install_template(args[1], &template_node); + if (template_file) + { + debug("auto install template: <%s> \n", + template_file, template_node->filebuf, template_node->filelen); + + template_size = template_node->filelen; + template_buf = grub_malloc(template_size); + if (template_buf) + { + grub_memcpy(template_buf, template_node->filebuf, template_size); + } + } + else + { + debug("auto install script skipped or not configed %s\n", args[1]); + } + + injection_file = ventoy_plugin_get_injection(args[1]); + if (injection_file) + { + debug("injection archive: <%s>\n", injection_file); + tmpfile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[2], injection_file); + if (tmpfile) + { + debug("injection archive size:%d\n", (int)tmpfile->size); + injection_size = tmpfile->size; + injection_buf = grub_malloc(injection_size); + if (injection_buf) + { + grub_file_read(tmpfile, injection_buf, injection_size); + } + + grub_file_close(tmpfile); + } + else + { + debug("Failed to open injection archive %s%s\n", args[2], injection_file); + } + } + else + { + debug("injection not configed %s\n", args[1]); + } + + dudnode = ventoy_plugin_find_dud(args[1]); + if (dudnode) + { + debug("dud file: <%d>\n", dudnode->dudnum); + ventoy_plugin_load_dud(dudnode, args[2]); + for (i = 0; i < dudnode->dudnum; i++) + { + if (dudnode->files[i].size > 0) + { + dud_size += dudnode->files[i].size + sizeof(cpio_newc_header); + } + } + } + else + { + debug("dud not configed %s\n", args[1]); + } + + g_ventoy_cpio_buf = grub_malloc(file->size + archfile->size + 40960 + template_size + + persistent_size + injection_size + dud_size + img_chunk_size); + if (NULL == g_ventoy_cpio_buf) + { + grub_file_close(file); + grub_file_close(archfile); + return grub_error(GRUB_ERR_BAD_ARGUMENT, "Can't alloc memory %llu\n", file->size); + } + + grub_file_read(file, g_ventoy_cpio_buf, file->size); + buf = (grub_uint8_t *)(g_ventoy_cpio_buf + file->size - 4); + while (*((grub_uint32_t *)buf) != 0x37303730) + { + buf -= 4; + } + + grub_file_read(archfile, buf, archfile->size); + buf += (archfile->size - 4); + while (*((grub_uint32_t *)buf) != 0x37303730) + { + buf -= 4; + } + + /* get initrd head len */ + initrd_head_len = ventoy_cpio_newc_fill_head(buf, 0, NULL, "initrd000.xx"); + + /* step1: insert image chunk data to cpio */ + headlen = ventoy_cpio_newc_fill_head(buf, img_chunk_size, g_img_chunk_list.chunk, "ventoy/ventoy_image_map"); + buf += headlen + ventoy_align(img_chunk_size, 4); + + if (template_buf) + { + headlen = ventoy_cpio_newc_fill_head(buf, template_size, template_buf, "ventoy/autoinstall"); + buf += headlen + ventoy_align(template_size, 4); + grub_check_free(template_buf); + } + + if (persistent_size > 0 && persistent_buf) + { + headlen = ventoy_cpio_newc_fill_head(buf, persistent_size, persistent_buf, "ventoy/ventoy_persistent_map"); + buf += headlen + ventoy_align(persistent_size, 4); + grub_check_free(persistent_buf); + } + + if (injection_size > 0 && injection_buf) + { + headlen = ventoy_cpio_newc_fill_head(buf, injection_size, injection_buf, "ventoy/ventoy_injection"); + buf += headlen + ventoy_align(injection_size, 4); + + grub_free(injection_buf); + injection_buf = NULL; + } + + if (dud_size > 0) + { + for (i = 0; i < dudnode->dudnum; i++) + { + pos = grub_strrchr(dudnode->dudpath[i].path, '.'); + grub_snprintf(tmpname, sizeof(tmpname), "ventoy/ventoy_dud%d%s", i, (pos ? pos : ".iso")); + dud_size = dudnode->files[i].size; + headlen = ventoy_cpio_newc_fill_head(buf, dud_size, dudnode->files[i].buf, tmpname); + buf += headlen + ventoy_align(dud_size, 4); + } + } + + /* step2: insert os param to cpio */ + headlen = ventoy_cpio_newc_fill_head(buf, 0, NULL, "ventoy/ventoy_os_param"); + padlen = sizeof(ventoy_os_param); + g_ventoy_cpio_size = (grub_uint32_t)(buf - g_ventoy_cpio_buf) + headlen + padlen + initrd_head_len; + mod = g_ventoy_cpio_size % 2048; + if (mod) + { + g_ventoy_cpio_size += 2048 - mod; + padlen += 2048 - mod; + } + + /* update os param data size, the data will be updated before chain boot */ + ventoy_cpio_newc_fill_int(padlen, ((cpio_newc_header *)buf)->c_filesize, 8); + g_ventoy_runtime_buf = (grub_uint8_t *)buf + headlen; + + /* step3: fill initrd cpio head, the file size will be updated before chain boot */ + g_ventoy_initrd_head = (cpio_newc_header *)(g_ventoy_runtime_buf + padlen); + ventoy_cpio_newc_fill_head(g_ventoy_initrd_head, 0, NULL, "initrd000.xx"); + + grub_file_close(file); + grub_file_close(archfile); + + if (grub_strcmp(args[3], "busybox=64") == 0) + { + debug("cpio busybox proc %s\n", args[3]); + ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "64h"); + } + else if (grub_strcmp(args[3], "busybox=a64") == 0) + { + debug("cpio busybox proc %s\n", args[3]); + ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "a64"); + } + else if (grub_strcmp(args[3], "busybox=m64") == 0) + { + debug("cpio busybox proc %s\n", args[3]); + ventoy_cpio_busybox64((cpio_newc_header *)g_ventoy_cpio_buf, "m64"); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int mod; + int bufsize; + int namelen; + int offset; + char *name; + grub_uint8_t *bufend; + cpio_newc_header *head; + grub_file_t file; + const grub_uint8_t trailler[124] = { + 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52, + 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00 + }; + + (void)ctxt; + (void)argc; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], args[1]); + if (!file) + { + return 1; + } + + grub_memset(g_ventoy_runtime_buf, 0, sizeof(ventoy_os_param)); + ventoy_fill_os_param(file, (ventoy_os_param *)g_ventoy_runtime_buf); + + grub_file_close(file); + + grub_memcpy(g_ventoy_initrd_head, trailler, sizeof(trailler)); + bufend = (grub_uint8_t *)g_ventoy_initrd_head + sizeof(trailler); + + bufsize = (int)(bufend - g_ventoy_cpio_buf); + mod = bufsize % 512; + if (mod) + { + grub_memset(bufend, 0, 512 - mod); + bufsize += 512 - mod; + } + + if (argc > 1 && grub_strcmp(args[2], "noinit") == 0) + { + head = (cpio_newc_header *)g_ventoy_cpio_buf; + name = (char *)(head + 1); + + while (grub_strcmp(name, "TRAILER!!!")) + { + if (grub_strcmp(name, "init") == 0) + { + grub_memcpy(name, "xxxx", 4); + } + else if (grub_strcmp(name, "linuxrc") == 0) + { + grub_memcpy(name, "vtoyxrc", 7); + } + else if (grub_strcmp(name, "sbin") == 0) + { + grub_memcpy(name, "vtoy", 4); + } + else if (grub_strcmp(name, "sbin/init") == 0) + { + grub_memcpy(name, "vtoy/vtoy", 9); + } + + namelen = ventoy_cpio_newc_get_int(head->c_namesize); + offset = sizeof(cpio_newc_header) + namelen; + offset = ventoy_align(offset, 4); + offset += ventoy_cpio_newc_get_int(head->c_filesize); + offset = ventoy_align(offset, 4); + + head = (cpio_newc_header *)((char *)head + offset); + name = (char *)(head + 1); + } + } + + ventoy_memfile_env_set("ventoy_cpio", g_ventoy_cpio_buf, (ulonglong)bufsize); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int len = 0; + int ventoy_compatible = 0; + grub_uint32_t size = 0; + grub_uint64_t isosize = 0; + grub_uint32_t boot_catlog = 0; + grub_uint32_t img_chunk_size = 0; + grub_uint32_t override_count = 0; + grub_uint32_t override_size = 0; + grub_uint32_t virt_chunk_count = 0; + grub_uint32_t virt_chunk_size = 0; + grub_file_t file; + grub_disk_t disk; + const char *pLastChain = NULL; + const char *compatible; + ventoy_chain_head *chain; + + (void)ctxt; + (void)argc; + + compatible = grub_env_get("ventoy_compatible"); + if (compatible && compatible[0] == 'Y') + { + ventoy_compatible = 1; + } + + if ((NULL == g_img_chunk_list.chunk) || (0 == ventoy_compatible && g_ventoy_cpio_buf == NULL)) + { + grub_printf("ventoy not ready\n"); + return 1; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + return 1; + } + + isosize = file->size; + + len = (int)grub_strlen(args[0]); + if (len >= 4 && 0 == grub_strcasecmp(args[0] + len - 4, ".img")) + { + debug("boot catlog %u for img file\n", boot_catlog); + } + else + { + boot_catlog = ventoy_get_iso_boot_catlog(file); + if (boot_catlog) + { + if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog))) + { + grub_env_set("LoadIsoEfiDriver", "on"); + } + } + else + { + if (ventoy_is_efi_os()) + { + grub_env_set("LoadIsoEfiDriver", "on"); + } + else + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]); + } + } + } + + img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk); + + override_count = ventoy_linux_get_override_chunk_count(); + virt_chunk_count = ventoy_linux_get_virt_chunk_count(); + + if (ventoy_compatible) + { + size = sizeof(ventoy_chain_head) + img_chunk_size; + } + else + { + override_size = ventoy_linux_get_override_chunk_size(); + virt_chunk_size = ventoy_linux_get_virt_chunk_size(); + size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size; + } + + pLastChain = grub_env_get("vtoy_chain_mem_addr"); + if (pLastChain) + { + chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16); + if (chain) + { + debug("free last chain memory %p\n", chain); + grub_free(chain); + } + } + + chain = ventoy_alloc_chain(size); + if (!chain) + { + grub_printf("Failed to alloc chain linux memory size %u\n", size); + grub_file_close(file); + return 1; + } + + ventoy_memfile_env_set("vtoy_chain_mem", chain, (ulonglong)size); + + grub_memset(chain, 0, sizeof(ventoy_chain_head)); + + /* part 1: os parameter */ + g_ventoy_chain_type = ventoy_chain_linux; + ventoy_fill_os_param(file, &(chain->os_param)); + + /* part 2: chain head */ + disk = file->device->disk; + chain->disk_drive = disk->id; + chain->disk_sector_size = (1 << disk->log_sector_size); + chain->real_img_size_in_bytes = file->size; + chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048; + chain->boot_catalog = boot_catlog; + + if (!ventoy_is_efi_os()) + { + grub_file_seek(file, boot_catlog * 2048); + grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector)); + } + + /* part 3: image chunk */ + chain->img_chunk_offset = sizeof(ventoy_chain_head); + chain->img_chunk_num = g_img_chunk_list.cur_chunk; + grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size); + + if (ventoy_compatible) + { + return 0; + } + + /* part 4: override chunk */ + if (override_count > 0) + { + chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size; + chain->override_chunk_num = override_count; + ventoy_linux_fill_override_data(isosize, (char *)chain + chain->override_chunk_offset); + } + + /* part 5: virt chunk */ + if (virt_chunk_count > 0) + { + chain->virt_chunk_offset = chain->override_chunk_offset + override_size; + chain->virt_chunk_num = virt_chunk_count; + ventoy_linux_fill_virt_data(isosize, chain); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static char *ventoy_systemd_conf_tag(char *buf, const char *tag, int optional) +{ + int taglen = 0; + char *start = NULL; + char *nextline = NULL; + + taglen = grub_strlen(tag); + for (start = buf; start; start = nextline) + { + nextline = ventoy_get_line(start); + VTOY_SKIP_SPACE(start); + + if (grub_strncmp(start, tag, taglen) == 0 && (start[taglen] == ' ' || start[taglen] == '\t')) + { + start += taglen; + VTOY_SKIP_SPACE(start); + return start; + } + } + + if (optional == 0) + { + debug("tag<%s> NOT found\n", tag); + } + return NULL; +} + +static int ventoy_systemd_conf_hook(const char *filename, const struct grub_dirhook_info *info, void *data) +{ + int oldpos = 0; + char *tag = NULL; + char *bkbuf = NULL; + char *filebuf = NULL; + grub_file_t file = NULL; + systemd_menu_ctx *ctx = (systemd_menu_ctx *)data; + + debug("ventoy_systemd_conf_hook %s\n", filename); + + if (info->dir || NULL == grub_strstr(filename, ".conf")) + { + return 0; + } + + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/loader/entries/%s", ctx->dev, filename); + if (!file) + { + return 0; + } + + filebuf = grub_zalloc(2 * file->size + 8); + if (!filebuf) + { + goto out; + } + + bkbuf = filebuf + file->size + 4; + grub_file_read(file, bkbuf, file->size); + + oldpos = ctx->pos; + + /* title --> menuentry */ + grub_memcpy(filebuf, bkbuf, file->size); + tag = ventoy_systemd_conf_tag(filebuf, "title", 0); + vtoy_check_goto_out(tag); + vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, "menuentry \"%s\" {\n", tag); + + /* linux xxx */ + grub_memcpy(filebuf, bkbuf, file->size); + tag = ventoy_systemd_conf_tag(filebuf, "linux", 0); + if (!tag) + { + ctx->pos = oldpos; + goto out; + } + vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, " echo \"Loading kernel ...\"\n linux %s ", tag); + + /* kernel options */ + grub_memcpy(filebuf, bkbuf, file->size); + tag = ventoy_systemd_conf_tag(filebuf, "options", 0); + vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, "%s \n", tag ? tag : ""); + + + /* initrd xxx xxx xxx */ + vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, " echo \"Loading initrd ...\"\n %s ", ctx->initrd_cmd); + grub_memcpy(filebuf, bkbuf, file->size); + tag = ventoy_systemd_conf_tag(filebuf, "initrd", 1); + while (tag) + { + vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, "%s ", tag); + tag = ventoy_systemd_conf_tag(tag + grub_strlen(tag) + 1, "initrd", 1); + } + + vtoy_len_ssprintf(ctx->buf, ctx->pos, ctx->len, "\n boot\n}\n"); + +out: + grub_check_free(filebuf); + grub_file_close(file); + return 0; +} + +grub_err_t ventoy_cmd_linux_initrd(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int pos = 0; + char *buf = NULL; + + (void)ctxt; + + buf = (char *)grub_malloc(VTOY_SIZE_4KB); + if (!buf) + { + return 1; + } + + pos += grub_snprintf(buf + pos, VTOY_SIZE_4KB - pos, "initrd mem:%s:size:%s", + grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size")); + + for (i = 0; i < argc; i++) + { + pos += grub_snprintf(buf + pos, VTOY_SIZE_4KB - pos, " newc:initrd%03d:%s", i + 1, args[i]); + } + + grub_script_execute_sourcecode(buf); + grub_free(buf); + + return 0; +} + +grub_err_t ventoy_cmd_linux_systemd_menu(grub_extcmd_context_t ctxt, int argc, char **args) +{ + static char *buf = NULL; + grub_fs_t fs; + char *device_name = NULL; + grub_device_t dev = NULL; + systemd_menu_ctx ctx; + + (void)ctxt; + (void)argc; + + if (!buf) + { + buf = grub_malloc(VTOY_LINUX_SYSTEMD_MENU_MAX_BUF); + if (!buf) + { + goto end; + } + } + + device_name = grub_file_get_device_name(args[0]); + if (!device_name) + { + debug("failed to get device name %s\n", args[0]); + goto end; + } + + dev = grub_device_open(device_name); + if (!dev) + { + debug("failed to open device %s\n", device_name); + goto end; + } + + fs = grub_fs_probe(dev); + if (!fs) + { + debug("failed to probe fs %d\n", grub_errno); + goto end; + } + + ctx.dev = args[0]; + ctx.buf = buf; + ctx.initrd_cmd = args[2] ? args[2] : "initrd"; + ctx.pos = 0; + ctx.len = VTOY_LINUX_SYSTEMD_MENU_MAX_BUF; + fs->fs_dir(dev, "/loader/entries", ventoy_systemd_conf_hook, &ctx); + + ventoy_memfile_env_set(args[1], buf, (ulonglong)(ctx.pos)); + +end: + grub_check_free(device_name); + check_free(dev, grub_device_close); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_limine_path_convert(char *path) +{ + char newpath[256] = {0}; + + if (grub_strncmp(path, "boot://2/", 9) == 0) + { + grub_snprintf(newpath, sizeof(newpath), "(vtimghd,2)/%s", path + 9); + } + else if (grub_strncmp(path, "boot://1/", 9) == 0) + { + grub_snprintf(newpath, sizeof(newpath), "(vtimghd,1)/%s", path + 9); + } + + if (newpath[0]) + { + grub_snprintf(path, 1024, "%s", newpath); + } + + return 0; +} + +grub_err_t ventoy_cmd_linux_limine_menu(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int pos = 0; + int sub = 0; + int len = VTOY_LINUX_SYSTEMD_MENU_MAX_BUF; + char *filebuf = NULL; + char *start = NULL; + char *nextline = NULL; + grub_file_t file = NULL; + char *title = NULL; + char *kernel = NULL; + char *initrd = NULL; + char *param = NULL; + static char *buf = NULL; + + (void)ctxt; + (void)argc; + + if (!buf) + { + buf = grub_malloc(len + 4 * 1024); + if (!buf) + { + goto end; + } + } + + title = buf + len; + kernel = title + 1024; + initrd = kernel + 1024; + param = initrd + 1024; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, args[0]); + if (!file) + { + return 0; + } + + filebuf = grub_zalloc(file->size + 8); + if (!filebuf) + { + goto end; + } + + grub_file_read(file, filebuf, file->size); + grub_file_close(file); + + + title[0] = kernel[0] = initrd[0] = param[0] = 0; + for (start = filebuf; start; start = nextline) + { + nextline = ventoy_get_line(start); + VTOY_SKIP_SPACE(start); + + if (start[0] == ':') + { + if (start[1] == ':') + { + grub_snprintf(title, 1024, "%s", start + 2); + } + else + { + if (sub) + { + vtoy_len_ssprintf(buf, pos, len, "}\n"); + sub = 0; + } + + if (nextline && nextline[0] == ':' && nextline[1] == ':') + { + vtoy_len_ssprintf(buf, pos, len, "submenu \"[+] %s\" {\n", start + 2); + sub = 1; + title[0] = 0; + } + else + { + grub_snprintf(title, 1024, "%s", start + 1); + } + } + } + else if (grub_strncmp(start, "KERNEL_PATH=", 12) == 0) + { + grub_snprintf(kernel, 1024, "%s", start + 12); + } + else if (grub_strncmp(start, "MODULE_PATH=", 12) == 0) + { + grub_snprintf(initrd, 1024, "%s", start + 12); + } + else if (grub_strncmp(start, "KERNEL_CMDLINE=", 15) == 0) + { + grub_snprintf(param, 1024, "%s", start + 15); + } + + if (title[0] && kernel[0] && initrd[0] && param[0]) + { + ventoy_limine_path_convert(kernel); + ventoy_limine_path_convert(initrd); + + vtoy_len_ssprintf(buf, pos, len, "menuentry \"%s\" {\n", title); + vtoy_len_ssprintf(buf, pos, len, " echo \"Downloading kernel ...\"\n linux %s %s\n", kernel, param); + vtoy_len_ssprintf(buf, pos, len, " echo \"Downloading initrd ...\"\n initrd %s\n", initrd); + vtoy_len_ssprintf(buf, pos, len, "}\n"); + + title[0] = kernel[0] = initrd[0] = param[0] = 0; + } + } + + if (sub) + { + vtoy_len_ssprintf(buf, pos, len, "}\n"); + sub = 0; + } + + ventoy_memfile_env_set(args[1], buf, (ulonglong)pos); + +end: + grub_check_free(filebuf); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c new file mode 100644 index 0000000..03441d4 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_plugin.c @@ -0,0 +1,3657 @@ +/****************************************************************************** + * ventoy_plugin.c + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ventoy_def.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +char g_arch_mode_suffix[64]; +static char g_iso_disk_name[128]; +static vtoy_password g_boot_pwd; +static vtoy_password g_file_type_pwd[img_type_max]; +static install_template *g_install_template_head = NULL; +static dud *g_dud_head = NULL; +static menu_password *g_pwd_head = NULL; +static persistence_config *g_persistence_head = NULL; +static menu_tip *g_menu_tip_head = NULL; +static menu_alias *g_menu_alias_head = NULL; +static menu_class *g_menu_class_head = NULL; +static custom_boot *g_custom_boot_head = NULL; +static injection_config *g_injection_head = NULL; +static auto_memdisk *g_auto_memdisk_head = NULL; +static image_list *g_image_list_head = NULL; +static conf_replace *g_conf_replace_head = NULL; +static VTOY_JSON *g_menu_lang_json = NULL; + +static int g_theme_id = 0; +static int g_theme_res_fit = 0; +static int g_theme_num = 0; +static theme_list *g_theme_head = NULL; +static int g_theme_random = vtoy_theme_random_boot_second; +static char g_theme_single_file[256]; +static char g_cur_menu_language[32] = {0}; +static char g_push_menu_language[32] = {0}; + +static int ventoy_plugin_is_parent(const char *pat, int patlen, const char *isopath) +{ + if (patlen > 1) + { + if (isopath[patlen] == '/' && ventoy_strncmp(pat, isopath, patlen) == 0 && + grub_strchr(isopath + patlen + 1, '/') == NULL) + { + return 1; + } + } + else + { + if (pat[0] == '/' && grub_strchr(isopath + 1, '/') == NULL) + { + return 1; + } + } + + return 0; +} + +static int ventoy_plugin_control_check(VTOY_JSON *json, const char *isodisk) +{ + int rc = 0; + VTOY_JSON *pNode = NULL; + VTOY_JSON *pChild = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array type %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->enDataType == JSON_TYPE_OBJECT) + { + pChild = pNode->pstChild; + if (pChild->enDataType == JSON_TYPE_STRING) + { + if (grub_strcmp(pChild->pcName, "VTOY_DEFAULT_IMAGE") == 0) + { + grub_printf("%s: %s [%s]\n", pChild->pcName, pChild->unData.pcStrVal, + ventoy_check_file_exist("%s%s", isodisk, pChild->unData.pcStrVal) ? "OK" : "NOT EXIST"); + } + else + { + grub_printf("%s: %s\n", pChild->pcName, pChild->unData.pcStrVal); + } + } + else + { + grub_printf("%s is NOT string type\n", pChild->pcName); + rc = 1; + } + } + else + { + grub_printf("%s is not an object\n", pNode->pcName); + rc = 1; + } + } + + return rc; +} + +static int ventoy_plugin_control_entry(VTOY_JSON *json, const char *isodisk) +{ + VTOY_JSON *pNode = NULL; + VTOY_JSON *pChild = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->enDataType == JSON_TYPE_OBJECT) + { + pChild = pNode->pstChild; + if (pChild->enDataType == JSON_TYPE_STRING && pChild->pcName && pChild->unData.pcStrVal) + { + ventoy_set_env(pChild->pcName, pChild->unData.pcStrVal); + } + } + } + + return 0; +} + +static int ventoy_plugin_theme_check(VTOY_JSON *json, const char *isodisk) +{ + int exist = 0; + const char *value; + VTOY_JSON *node; + + value = vtoy_json_get_string_ex(json->pstChild, "file"); + if (value) + { + grub_printf("file: %s\n", value); + if (value[0] == '/') + { + exist = ventoy_check_file_exist("%s%s", isodisk, value); + } + else + { + exist = ventoy_check_file_exist("%s/ventoy/%s", isodisk, value); + } + + if (exist == 0) + { + grub_printf("Theme file %s does NOT exist\n", value); + return 1; + } + } + else + { + node = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "file"); + if (node) + { + for (node = node->pstChild; node; node = node->pstNext) + { + value = node->unData.pcStrVal; + grub_printf("file: %s\n", value); + if (value[0] == '/') + { + exist = ventoy_check_file_exist("%s%s", isodisk, value); + } + else + { + exist = ventoy_check_file_exist("%s/ventoy/%s", isodisk, value); + } + + if (exist == 0) + { + grub_printf("Theme file %s does NOT exist\n", value); + return 1; + } + } + + value = vtoy_json_get_string_ex(json->pstChild, "random"); + if (value) + { + grub_printf("random: %s\n", value); + } + } + } + + value = vtoy_json_get_string_ex(json->pstChild, "gfxmode"); + if (value) + { + grub_printf("gfxmode: %s\n", value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "display_mode"); + if (value) + { + grub_printf("display_mode: %s\n", value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "serial_param"); + if (value) + { + grub_printf("serial_param %s\n", value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left"); + if (value) + { + grub_printf("ventoy_left: %s\n", value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "ventoy_top"); + if (value) + { + grub_printf("ventoy_top: %s\n", value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "ventoy_color"); + if (value) + { + grub_printf("ventoy_color: %s\n", value); + } + + node = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "fonts"); + if (node) + { + for (node = node->pstChild; node; node = node->pstNext) + { + if (node->enDataType == JSON_TYPE_STRING) + { + if (ventoy_check_file_exist("%s%s", isodisk, node->unData.pcStrVal)) + { + grub_printf("%s [OK]\n", node->unData.pcStrVal); + } + else + { + grub_printf("%s [NOT EXIST]\n", node->unData.pcStrVal); + } + } + } + } + else + { + grub_printf("fonts NOT found\n"); + } + + return 0; +} + +static int ventoy_plugin_theme_entry(VTOY_JSON *json, const char *isodisk) +{ + const char *value; + char val[64]; + char filepath[256]; + VTOY_JSON *node = NULL; + theme_list *tail = NULL; + theme_list *themenode = NULL; + + value = vtoy_json_get_string_ex(json->pstChild, "file"); + if (value) + { + if (value[0] == '/') + { + grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, value); + } + else + { + grub_snprintf(filepath, sizeof(filepath), "%s/ventoy/%s", isodisk, value); + } + + if (ventoy_check_file_exist(filepath) == 0) + { + debug("Theme file %s does not exist\n", filepath); + return 0; + } + + debug("vtoy_theme %s\n", filepath); + ventoy_env_export("vtoy_theme", filepath); + grub_snprintf(g_theme_single_file, sizeof(g_theme_single_file), "%s", filepath); + } + else + { + node = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "file"); + if (node) + { + for (node = node->pstChild; node; node = node->pstNext) + { + value = node->unData.pcStrVal; + if (value[0] == '/') + { + grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, value); + } + else + { + grub_snprintf(filepath, sizeof(filepath), "%s/ventoy/%s", isodisk, value); + } + + if (ventoy_check_file_exist(filepath) == 0) + { + continue; + } + + themenode = grub_zalloc(sizeof(theme_list)); + if (themenode) + { + grub_snprintf(themenode->theme.path, sizeof(themenode->theme.path), "%s", filepath); + if (g_theme_head) + { + tail->next = themenode; + } + else + { + g_theme_head = themenode; + } + tail = themenode; + g_theme_num++; + } + } + + ventoy_env_export("vtoy_theme", "random"); + value = vtoy_json_get_string_ex(json->pstChild, "random"); + if (value) + { + if (grub_strcmp(value, "boot_second") == 0) + { + g_theme_random = vtoy_theme_random_boot_second; + } + else if (grub_strcmp(value, "boot_day") == 0) + { + g_theme_random = vtoy_theme_random_boot_day; + } + else if (grub_strcmp(value, "boot_month") == 0) + { + g_theme_random = vtoy_theme_random_boot_month; + } + } + } + } + + grub_snprintf(val, sizeof(val), "%d", g_theme_num); + grub_env_set("VTOY_THEME_COUNT", val); + grub_env_export("VTOY_THEME_COUNT"); + if (g_theme_num > 0) + { + vtoy_json_get_int(json->pstChild, "default_file", &g_theme_id); + if (g_theme_id == 0) + { + vtoy_json_get_int(json->pstChild, "resolution_fit", &g_theme_res_fit); + if (g_theme_res_fit != 1) + { + g_theme_res_fit = 0; + } + + grub_snprintf(val, sizeof(val), "%d", g_theme_res_fit); + ventoy_env_export("vtoy_res_fit", val); + } + + if (g_theme_id > g_theme_num || g_theme_id < 0) + { + g_theme_id = 0; + } + } + + value = vtoy_json_get_string_ex(json->pstChild, "gfxmode"); + if (value) + { + debug("vtoy_gfxmode %s\n", value); + ventoy_env_export("vtoy_gfxmode", value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "display_mode"); + if (value) + { + debug("display_mode %s\n", value); + ventoy_env_export("vtoy_display_mode", value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "serial_param"); + if (value) + { + debug("serial_param %s\n", value); + ventoy_env_export("vtoy_serial_param", value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left"); + if (value) + { + ventoy_env_export(ventoy_left_key, value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "ventoy_top"); + if (value) + { + ventoy_env_export(ventoy_top_key, value); + } + + value = vtoy_json_get_string_ex(json->pstChild, "ventoy_color"); + if (value) + { + ventoy_env_export(ventoy_color_key, value); + } + + node = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "fonts"); + if (node) + { + for (node = node->pstChild; node; node = node->pstNext) + { + if (node->enDataType == JSON_TYPE_STRING && + ventoy_check_file_exist("%s%s", isodisk, node->unData.pcStrVal)) + { + grub_snprintf(filepath, sizeof(filepath), "%s%s", isodisk, node->unData.pcStrVal); + grub_font_load(filepath); + } + } + } + + return 0; +} + +static int ventoy_plugin_check_path(const char *path, const char *file) +{ + if (file[0] != '/') + { + grub_printf("%s is NOT begin with '/' \n", file); + return 1; + } + + if (grub_strchr(file, '\\')) + { + grub_printf("%s contains invalid '\\' \n", file); + return 1; + } + + if (grub_strstr(file, "//")) + { + grub_printf("%s contains invalid double slash\n", file); + return 1; + } + + if (grub_strstr(file, "../")) + { + grub_printf("%s contains invalid '../' \n", file); + return 1; + } + + if (!ventoy_check_file_exist("%s%s", path, file)) + { + grub_printf("%s%s does NOT exist\n", path, file); + return 1; + } + + return 0; +} + +static int ventoy_plugin_check_fullpath +( + VTOY_JSON *json, + const char *isodisk, + const char *key, + int *pathnum +) +{ + int rc = 0; + int ret = 0; + int cnt = 0; + VTOY_JSON *node = json; + VTOY_JSON *child = NULL; + + while (node) + { + if (0 == grub_strcmp(key, node->pcName)) + { + break; + } + node = node->pstNext; + } + + if (!node) + { + return 1; + } + + if (JSON_TYPE_STRING == node->enDataType) + { + cnt = 1; + ret = ventoy_plugin_check_path(isodisk, node->unData.pcStrVal); + grub_printf("%s: %s [%s]\n", key, node->unData.pcStrVal, ret ? "FAIL" : "OK"); + } + else if (JSON_TYPE_ARRAY == node->enDataType) + { + for (child = node->pstChild; child; child = child->pstNext) + { + if (JSON_TYPE_STRING != child->enDataType) + { + grub_printf("Non string json type\n"); + } + else + { + rc = ventoy_plugin_check_path(isodisk, child->unData.pcStrVal); + grub_printf("%s: %s [%s]\n", key, child->unData.pcStrVal, rc ? "FAIL" : "OK"); + ret += rc; + cnt++; + } + } + } + + *pathnum = cnt; + return ret; +} + +static int ventoy_plugin_parse_fullpath +( + VTOY_JSON *json, + const char *isodisk, + const char *key, + file_fullpath **fullpath, + int *pathnum +) +{ + int rc = 1; + int count = 0; + VTOY_JSON *node = json; + VTOY_JSON *child = NULL; + file_fullpath *path = NULL; + + while (node) + { + if (0 == grub_strcmp(key, node->pcName)) + { + break; + } + node = node->pstNext; + } + + if (!node) + { + return 1; + } + + if (JSON_TYPE_STRING == node->enDataType) + { + debug("%s is string type data\n", node->pcName); + + if ((node->unData.pcStrVal[0] != '/') || (!ventoy_check_file_exist("%s%s", isodisk, node->unData.pcStrVal))) + { + debug("%s%s file not found\n", isodisk, node->unData.pcStrVal); + return 1; + } + + path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath)); + if (path) + { + grub_snprintf(path->path, sizeof(path->path), "%s", node->unData.pcStrVal); + *fullpath = path; + *pathnum = 1; + rc = 0; + } + } + else if (JSON_TYPE_ARRAY == node->enDataType) + { + for (child = node->pstChild; child; child = child->pstNext) + { + if ((JSON_TYPE_STRING != child->enDataType) || (child->unData.pcStrVal[0] != '/')) + { + debug("Invalid data type:%d\n", child->enDataType); + return 1; + } + count++; + } + debug("%s is array type data, count=%d\n", node->pcName, count); + + path = (file_fullpath *)grub_zalloc(sizeof(file_fullpath) * count); + if (path) + { + *fullpath = path; + + for (count = 0, child = node->pstChild; child; child = child->pstNext) + { + if (ventoy_check_file_exist("%s%s", isodisk, child->unData.pcStrVal)) + { + grub_snprintf(path->path, sizeof(path->path), "%s", child->unData.pcStrVal); + path++; + count++; + } + } + + *pathnum = count; + rc = 0; + } + } + + return rc; +} + +static int ventoy_plugin_auto_install_check(VTOY_JSON *json, const char *isodisk) +{ + int pathnum = 0; + int autosel = 0; + int timeout = 0; + char *pos = NULL; + const char *iso = NULL; + VTOY_JSON *pNode = NULL; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array type %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->enDataType != JSON_TYPE_OBJECT) + { + grub_printf("NOT object type\n"); + } + + if ((iso = vtoy_json_get_string_ex(pNode->pstChild, "image")) != NULL) + { + pos = grub_strchr(iso, '*'); + if (pos || 0 == ventoy_plugin_check_path(isodisk, iso)) + { + grub_printf("image: %s [%s]\n", iso, (pos ? "*" : "OK")); + ventoy_plugin_check_fullpath(pNode->pstChild, isodisk, "template", &pathnum); + + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel)) + { + if (autosel >= 0 && autosel <= pathnum) + { + grub_printf("autosel: %d [OK]\n", autosel); + } + else + { + grub_printf("autosel: %d [FAIL]\n", autosel); + } + } + + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "timeout", &timeout)) + { + if (timeout >= 0) + { + grub_printf("timeout: %d [OK]\n", timeout); + } + else + { + grub_printf("timeout: %d [FAIL]\n", timeout); + } + } + } + else + { + grub_printf("image: %s [FAIL]\n", iso); + } + } + else if ((iso = vtoy_json_get_string_ex(pNode->pstChild, "parent")) != NULL) + { + if (ventoy_is_dir_exist("%s%s", isodisk, iso)) + { + grub_printf("parent: %s [OK]\n", iso); + ventoy_plugin_check_fullpath(pNode->pstChild, isodisk, "template", &pathnum); + + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel)) + { + if (autosel >= 0 && autosel <= pathnum) + { + grub_printf("autosel: %d [OK]\n", autosel); + } + else + { + grub_printf("autosel: %d [FAIL]\n", autosel); + } + } + + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "timeout", &timeout)) + { + if (timeout >= 0) + { + grub_printf("timeout: %d [OK]\n", timeout); + } + else + { + grub_printf("timeout: %d [FAIL]\n", timeout); + } + } + } + else + { + grub_printf("parent: %s [FAIL]\n", iso); + } + } + else + { + grub_printf("image not found\n"); + } + } + + return 0; +} + +static int ventoy_plugin_auto_install_entry(VTOY_JSON *json, const char *isodisk) +{ + int type = 0; + int pathnum = 0; + int autosel = 0; + int timeout = 0; + const char *iso = NULL; + VTOY_JSON *pNode = NULL; + install_template *node = NULL; + install_template *next = NULL; + file_fullpath *templatepath = NULL; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_install_template_head) + { + for (node = g_install_template_head; node; node = next) + { + next = node->next; + grub_check_free(node->templatepath); + grub_free(node); + } + + g_install_template_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + type = auto_install_type_file; + iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (!iso) + { + type = auto_install_type_parent; + iso = vtoy_json_get_string_ex(pNode->pstChild, "parent"); + } + + if (iso && iso[0] == '/') + { + if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "template", &templatepath, &pathnum)) + { + node = grub_zalloc(sizeof(install_template)); + if (node) + { + node->type = type; + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso); + node->templatepath = templatepath; + node->templatenum = pathnum; + + node->autosel = -1; + node->timeout = -1; + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel)) + { + if (autosel >= 0 && autosel <= pathnum) + { + node->autosel = autosel; + } + } + + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "timeout", &timeout)) + { + if (timeout >= 0) + { + node->timeout = timeout; + } + } + + if (g_install_template_head) + { + node->next = g_install_template_head; + } + + g_install_template_head = node; + } + } + } + } + + return 0; +} + +static int ventoy_plugin_dud_check(VTOY_JSON *json, const char *isodisk) +{ + int pathnum = 0; + char *pos = NULL; + const char *iso = NULL; + VTOY_JSON *pNode = NULL; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array type %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->enDataType != JSON_TYPE_OBJECT) + { + grub_printf("NOT object type\n"); + } + + iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (iso) + { + pos = grub_strchr(iso, '*'); + if (pos || 0 == ventoy_plugin_check_path(isodisk, iso)) + { + grub_printf("image: %s [%s]\n", iso, (pos ? "*" : "OK")); + ventoy_plugin_check_fullpath(pNode->pstChild, isodisk, "dud", &pathnum); + } + else + { + grub_printf("image: %s [FAIL]\n", iso); + } + } + else + { + grub_printf("image not found\n"); + } + } + + return 0; +} + +static int ventoy_plugin_dud_entry(VTOY_JSON *json, const char *isodisk) +{ + int pathnum = 0; + const char *iso = NULL; + VTOY_JSON *pNode = NULL; + dud *node = NULL; + dud *next = NULL; + file_fullpath *dudpath = NULL; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_dud_head) + { + for (node = g_dud_head; node; node = next) + { + next = node->next; + grub_check_free(node->dudpath); + grub_free(node); + } + + g_dud_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (iso && iso[0] == '/') + { + if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "dud", &dudpath, &pathnum)) + { + node = grub_zalloc(sizeof(dud)); + if (node) + { + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso); + node->dudpath = dudpath; + node->dudnum = pathnum; + node->files = grub_zalloc(sizeof(dudfile) * pathnum); + + if (node->files) + { + if (g_dud_head) + { + node->next = g_dud_head; + } + + g_dud_head = node; + } + else + { + grub_free(node); + } + } + } + } + } + + return 0; +} + +static int ventoy_plugin_parse_pwdstr(char *pwdstr, vtoy_password *pwd) +{ + int i; + int len; + char ch; + char *pos; + char bytes[3]; + vtoy_password tmpPwd; + + len = (int)grub_strlen(pwdstr); + if (len > 64) + { + if (NULL == pwd) grub_printf("Password too long %d\n", len); + return 1; + } + + grub_memset(&tmpPwd, 0, sizeof(tmpPwd)); + + if (grub_strncmp(pwdstr, "txt#", 4) == 0) + { + tmpPwd.type = VTOY_PASSWORD_TXT; + grub_snprintf(tmpPwd.text, sizeof(tmpPwd.text), "%s", pwdstr + 4); + } + else if (grub_strncmp(pwdstr, "md5#", 4) == 0) + { + if ((len - 4) == 32) + { + for (i = 0; i < 16; i++) + { + bytes[0] = pwdstr[4 + i * 2]; + bytes[1] = pwdstr[4 + i * 2 + 1]; + bytes[2] = 0; + + if (grub_isxdigit(bytes[0]) && grub_isxdigit(bytes[1])) + { + tmpPwd.md5[i] = (grub_uint8_t)grub_strtoul(bytes, NULL, 16); + } + else + { + if (NULL == pwd) grub_printf("Invalid md5 hex format %s %d\n", pwdstr, i); + return 1; + } + } + tmpPwd.type = VTOY_PASSWORD_MD5; + } + else if ((len - 4) > 32) + { + pos = grub_strchr(pwdstr + 4, '#'); + if (!pos) + { + if (NULL == pwd) grub_printf("Invalid md5 password format %s\n", pwdstr); + return 1; + } + + if (len - 1 - ((long)pos - (long)pwdstr) != 32) + { + if (NULL == pwd) grub_printf("Invalid md5 salt password format %s\n", pwdstr); + return 1; + } + + ch = *pos; + *pos = 0; + grub_snprintf(tmpPwd.salt, sizeof(tmpPwd.salt), "%s", pwdstr + 4); + *pos = ch; + + pos++; + for (i = 0; i < 16; i++) + { + bytes[0] = pos[i * 2]; + bytes[1] = pos[i * 2 + 1]; + bytes[2] = 0; + + if (grub_isxdigit(bytes[0]) && grub_isxdigit(bytes[1])) + { + tmpPwd.md5[i] = (grub_uint8_t)grub_strtoul(bytes, NULL, 16); + } + else + { + if (NULL == pwd) grub_printf("Invalid md5 hex format %s %d\n", pwdstr, i); + return 1; + } + } + + tmpPwd.type = VTOY_PASSWORD_SALT_MD5; + } + else + { + if (NULL == pwd) grub_printf("Invalid md5 password format %s\n", pwdstr); + return 1; + } + } + else + { + if (NULL == pwd) grub_printf("Invalid password format %s\n", pwdstr); + return 1; + } + + if (pwd) + { + grub_memcpy(pwd, &tmpPwd, sizeof(tmpPwd)); + } + + return 0; +} + +static int ventoy_plugin_get_pwd_type(const char *pwd) +{ + int i; + char pwdtype[64]; + + for (i = 0; pwd && i < (int)ARRAY_SIZE(g_menu_prefix); i++) + { + grub_snprintf(pwdtype, sizeof(pwdtype), "%spwd", g_menu_prefix[i]); + if (grub_strcmp(pwdtype, pwd) == 0) + { + return img_type_start + i; + } + } + + return -1; +} + +static int ventoy_plugin_pwd_entry(VTOY_JSON *json, const char *isodisk) +{ + int type = -1; + const char *iso = NULL; + const char *pwd = NULL; + VTOY_JSON *pNode = NULL; + VTOY_JSON *pCNode = NULL; + menu_password *node = NULL; + menu_password *tail = NULL; + menu_password *next = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_OBJECT) + { + debug("Not object %d\n", json->enDataType); + return 0; + } + + if (g_pwd_head) + { + for (node = g_pwd_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_pwd_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->pcName && grub_strcmp("bootpwd", pNode->pcName) == 0) + { + ventoy_plugin_parse_pwdstr(pNode->unData.pcStrVal, &g_boot_pwd); + } + else if ((type = ventoy_plugin_get_pwd_type(pNode->pcName)) >= 0) + { + ventoy_plugin_parse_pwdstr(pNode->unData.pcStrVal, g_file_type_pwd + type); + } + else if (pNode->pcName && grub_strcmp("menupwd", pNode->pcName) == 0) + { + for (pCNode = pNode->pstChild; pCNode; pCNode = pCNode->pstNext) + { + if (pCNode->enDataType != JSON_TYPE_OBJECT) + { + continue; + } + + type = vtoy_menu_pwd_file; + iso = vtoy_json_get_string_ex(pCNode->pstChild, "file"); + if (!iso) + { + type = vtoy_menu_pwd_parent; + iso = vtoy_json_get_string_ex(pCNode->pstChild, "parent"); + } + + pwd = vtoy_json_get_string_ex(pCNode->pstChild, "pwd"); + if (iso && pwd && iso[0] == '/') + { + node = grub_zalloc(sizeof(menu_password)); + if (node) + { + node->type = type; + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso); + + if (ventoy_plugin_parse_pwdstr((char *)pwd, &(node->password))) + { + grub_free(node); + continue; + } + + if (g_pwd_head) + { + tail->next = node; + } + else + { + g_pwd_head = node; + } + tail = node; + } + } + } + } + } + + return 0; +} + +static int ventoy_plugin_pwd_check(VTOY_JSON *json, const char *isodisk) +{ + int type = -1; + char *pos = NULL; + const char *iso = NULL; + const char *pwd = NULL; + VTOY_JSON *pNode = NULL; + VTOY_JSON *pCNode = NULL; + + if (json->enDataType != JSON_TYPE_OBJECT) + { + grub_printf("Not object %d\n", json->enDataType); + return 0; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->pcName && grub_strcmp("bootpwd", pNode->pcName) == 0) + { + if (0 == ventoy_plugin_parse_pwdstr(pNode->unData.pcStrVal, NULL)) + { + grub_printf("bootpwd:<%s>\n", pNode->unData.pcStrVal); + } + else + { + grub_printf("Invalid bootpwd.\n"); + } + } + else if ((type = ventoy_plugin_get_pwd_type(pNode->pcName)) >= 0) + { + if (0 == ventoy_plugin_parse_pwdstr(pNode->unData.pcStrVal, NULL)) + { + grub_printf("%s:<%s>\n", pNode->pcName, pNode->unData.pcStrVal); + } + else + { + grub_printf("Invalid pwd <%s>\n", pNode->unData.pcStrVal); + } + } + else if (pNode->pcName && grub_strcmp("menupwd", pNode->pcName) == 0) + { + grub_printf("\n"); + for (pCNode = pNode->pstChild; pCNode; pCNode = pCNode->pstNext) + { + if (pCNode->enDataType != JSON_TYPE_OBJECT) + { + grub_printf("Not object %d\n", pCNode->enDataType); + continue; + } + + if ((iso = vtoy_json_get_string_ex(pCNode->pstChild, "file")) != NULL) + { + pos = grub_strchr(iso, '*'); + if (pos || 0 == ventoy_plugin_check_path(isodisk, iso)) + { + pwd = vtoy_json_get_string_ex(pCNode->pstChild, "pwd"); + + if (0 == ventoy_plugin_parse_pwdstr((char *)pwd, NULL)) + { + grub_printf("file:<%s> [%s]\n", iso, (pos ? "*" : "OK")); + grub_printf("pwd:<%s>\n\n", pwd); + } + else + { + grub_printf("Invalid password for <%s>\n", iso); + } + } + else + { + grub_printf("<%s%s> not found\n", isodisk, iso); + } + } + else if ((iso = vtoy_json_get_string_ex(pCNode->pstChild, "parent")) != NULL) + { + if (ventoy_is_dir_exist("%s%s", isodisk, iso)) + { + pwd = vtoy_json_get_string_ex(pCNode->pstChild, "pwd"); + if (0 == ventoy_plugin_parse_pwdstr((char *)pwd, NULL)) + { + grub_printf("dir:<%s> [%s]\n", iso, (pos ? "*" : "OK")); + grub_printf("pwd:<%s>\n\n", pwd); + } + else + { + grub_printf("Invalid password for <%s>\n", iso); + } + } + else + { + grub_printf("<%s%s> not found\n", isodisk, iso); + } + } + else + { + grub_printf("No file item found in json.\n"); + } + } + } + } + + return 0; +} + +static int ventoy_plugin_persistence_check(VTOY_JSON *json, const char *isodisk) +{ + int autosel = 0; + int timeout = 0; + int pathnum = 0; + char *pos = NULL; + const char *iso = NULL; + VTOY_JSON *pNode = NULL; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array type %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->enDataType != JSON_TYPE_OBJECT) + { + grub_printf("NOT object type\n"); + } + + iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (iso) + { + pos = grub_strchr(iso, '*'); + if (pos || 0 == ventoy_plugin_check_path(isodisk, iso)) + { + grub_printf("image: %s [%s]\n", iso, (pos ? "*" : "OK")); + ventoy_plugin_check_fullpath(pNode->pstChild, isodisk, "backend", &pathnum); + + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel)) + { + if (autosel >= 0 && autosel <= pathnum) + { + grub_printf("autosel: %d [OK]\n", autosel); + } + else + { + grub_printf("autosel: %d [FAIL]\n", autosel); + } + } + + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "timeout", &timeout)) + { + if (timeout >= 0) + { + grub_printf("timeout: %d [OK]\n", timeout); + } + else + { + grub_printf("timeout: %d [FAIL]\n", timeout); + } + } + } + else + { + grub_printf("image: %s [FAIL]\n", iso); + } + } + else + { + grub_printf("image not found\n"); + } + } + + return 0; +} + +static int ventoy_plugin_persistence_entry(VTOY_JSON *json, const char *isodisk) +{ + int autosel = 0; + int timeout = 0; + int pathnum = 0; + const char *iso = NULL; + VTOY_JSON *pNode = NULL; + persistence_config *node = NULL; + persistence_config *next = NULL; + file_fullpath *backendpath = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_persistence_head) + { + for (node = g_persistence_head; node; node = next) + { + next = node->next; + grub_check_free(node->backendpath); + grub_free(node); + } + + g_persistence_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + iso = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (iso && iso[0] == '/') + { + if (0 == ventoy_plugin_parse_fullpath(pNode->pstChild, isodisk, "backend", &backendpath, &pathnum)) + { + node = grub_zalloc(sizeof(persistence_config)); + if (node) + { + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", iso); + node->backendpath = backendpath; + node->backendnum = pathnum; + + node->autosel = -1; + node->timeout = -1; + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "autosel", &autosel)) + { + if (autosel >= 0 && autosel <= pathnum) + { + node->autosel = autosel; + } + } + + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "timeout", &timeout)) + { + if (timeout >= 0) + { + node->timeout = timeout; + } + } + + if (g_persistence_head) + { + node->next = g_persistence_head; + } + + g_persistence_head = node; + } + } + } + } + + return 0; +} + +static int ventoy_plugin_menualias_check(VTOY_JSON *json, const char *isodisk) +{ + int type; + const char *path = NULL; + const char *alias = NULL; + VTOY_JSON *pNode = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + type = vtoy_alias_image_file; + path = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (!path) + { + path = vtoy_json_get_string_ex(pNode->pstChild, "dir"); + type = vtoy_alias_directory; + } + + alias = vtoy_json_get_string_ex(pNode->pstChild, "alias"); + if (path && path[0] == '/' && alias) + { + if (vtoy_alias_image_file == type) + { + if (grub_strchr(path, '*')) + { + grub_printf("image: <%s> [ * ]\n", path); + } + else if (ventoy_check_file_exist("%s%s", isodisk, path)) + { + grub_printf("image: <%s> [ OK ]\n", path); + } + else + { + grub_printf("image: <%s> [ NOT EXIST ]\n", path); + } + } + else + { + if (ventoy_is_dir_exist("%s%s", isodisk, path)) + { + grub_printf("dir: <%s> [ OK ]\n", path); + } + else + { + grub_printf("dir: <%s> [ NOT EXIST ]\n", path); + } + } + + grub_printf("alias: <%s>\n\n", alias); + } + } + + return 0; +} + +static int ventoy_plugin_menualias_entry(VTOY_JSON *json, const char *isodisk) +{ + int type; + const char *path = NULL; + const char *alias = NULL; + VTOY_JSON *pNode = NULL; + menu_alias *node = NULL; + menu_alias *next = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_menu_alias_head) + { + for (node = g_menu_alias_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_menu_alias_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + type = vtoy_alias_image_file; + path = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (!path) + { + path = vtoy_json_get_string_ex(pNode->pstChild, "dir"); + type = vtoy_alias_directory; + } + + alias = vtoy_json_get_string_ex(pNode->pstChild, "alias"); + if (path && path[0] == '/' && alias) + { + node = grub_zalloc(sizeof(menu_alias)); + if (node) + { + node->type = type; + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", path); + grub_snprintf(node->alias, sizeof(node->alias), "%s", alias); + + if (g_menu_alias_head) + { + node->next = g_menu_alias_head; + } + + g_menu_alias_head = node; + } + } + } + + return 0; +} + +static int ventoy_plugin_menutip_check(VTOY_JSON *json, const char *isodisk) +{ + int type; + const char *path = NULL; + const char *tip = NULL; + VTOY_JSON *pNode = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_OBJECT) + { + grub_printf("Not object %d\n", json->enDataType); + return 1; + } + + tip = vtoy_json_get_string_ex(json->pstChild, "left"); + if (tip) + { + grub_printf("left: <%s>\n", tip); + } + + tip = vtoy_json_get_string_ex(json->pstChild, "top"); + if (tip) + { + grub_printf("top: <%s>\n", tip); + } + + tip = vtoy_json_get_string_ex(json->pstChild, "color"); + if (tip) + { + grub_printf("color: <%s>\n", tip); + } + + pNode = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "tips"); + for (pNode = pNode->pstChild; pNode; pNode = pNode->pstNext) + { + type = vtoy_tip_image_file; + path = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (!path) + { + path = vtoy_json_get_string_ex(pNode->pstChild, "dir"); + type = vtoy_tip_directory; + } + + if (path && path[0] == '/') + { + if (vtoy_tip_image_file == type) + { + if (grub_strchr(path, '*')) + { + grub_printf("image: <%s> [ * ]\n", path); + } + else if (ventoy_check_file_exist("%s%s", isodisk, path)) + { + grub_printf("image: <%s> [ OK ]\n", path); + } + else + { + grub_printf("image: <%s> [ NOT EXIST ]\n", path); + } + } + else + { + if (ventoy_is_dir_exist("%s%s", isodisk, path)) + { + grub_printf("dir: <%s> [ OK ]\n", path); + } + else + { + grub_printf("dir: <%s> [ NOT EXIST ]\n", path); + } + } + + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip"); + if (tip) + { + grub_printf("tip: <%s>\n", tip); + } + else + { + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip1"); + if (tip) + grub_printf("tip1: <%s>\n", tip); + else + grub_printf("tip1: \n"); + + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip2"); + if (tip) + grub_printf("tip2: <%s>\n", tip); + else + grub_printf("tip2: \n"); + } + } + else + { + grub_printf("image: <%s> [ INVALID ]\n", path); + } + } + + return 0; +} + +static int ventoy_plugin_menutip_entry(VTOY_JSON *json, const char *isodisk) +{ + int type; + const char *path = NULL; + const char *tip = NULL; + VTOY_JSON *pNode = NULL; + menu_tip *node = NULL; + menu_tip *next = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_OBJECT) + { + debug("Not object %d\n", json->enDataType); + return 0; + } + + pNode = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "tips"); + if (pNode == NULL) + { + debug("Not tips found\n"); + return 0; + } + + if (g_menu_tip_head) + { + for (node = g_menu_tip_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_menu_tip_head = NULL; + } + + tip = vtoy_json_get_string_ex(json->pstChild, "left"); + if (tip) + { + grub_env_set("VTOY_TIP_LEFT", tip); + } + + tip = vtoy_json_get_string_ex(json->pstChild, "top"); + if (tip) + { + grub_env_set("VTOY_TIP_TOP", tip); + } + + tip = vtoy_json_get_string_ex(json->pstChild, "color"); + if (tip) + { + grub_env_set("VTOY_TIP_COLOR", tip); + } + + for (pNode = pNode->pstChild; pNode; pNode = pNode->pstNext) + { + type = vtoy_tip_image_file; + path = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (!path) + { + path = vtoy_json_get_string_ex(pNode->pstChild, "dir"); + type = vtoy_tip_directory; + } + + if (path && path[0] == '/') + { + node = grub_zalloc(sizeof(menu_tip)); + if (node) + { + node->type = type; + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", path); + + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip"); + if (tip) + { + grub_snprintf(node->tip1, 1000, "%s", tip); + } + else + { + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip1"); + if (tip) + grub_snprintf(node->tip1, 1000, "%s", tip); + + tip = vtoy_json_get_string_ex(pNode->pstChild, "tip2"); + if (tip) + grub_snprintf(node->tip2, 1000, "%s", tip); + } + + if (g_menu_tip_head) + { + node->next = g_menu_tip_head; + } + + g_menu_tip_head = node; + } + } + } + + return 0; +} + +static int ventoy_plugin_injection_check(VTOY_JSON *json, const char *isodisk) +{ + int type = 0; + const char *path = NULL; + const char *archive = NULL; + VTOY_JSON *pNode = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array %d\n", json->enDataType); + return 0; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + type = injection_type_file; + path = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (!path) + { + type = injection_type_parent; + path = vtoy_json_get_string_ex(pNode->pstChild, "parent"); + if (!path) + { + grub_printf("image/parent not found\n"); + continue; + } + } + + archive = vtoy_json_get_string_ex(pNode->pstChild, "archive"); + if (!archive) + { + grub_printf("archive not found\n"); + continue; + } + + if (type == injection_type_file) + { + if (grub_strchr(path, '*')) + { + grub_printf("image: <%s> [*]\n", path); + } + else + { + grub_printf("image: <%s> [%s]\n", path, ventoy_check_file_exist("%s%s", isodisk, path) ? "OK" : "NOT EXIST"); + } + } + else + { + grub_printf("parent: <%s> [%s]\n", path, + ventoy_is_dir_exist("%s%s", isodisk, path) ? "OK" : "NOT EXIST"); + } + + grub_printf("archive: <%s> [%s]\n\n", archive, ventoy_check_file_exist("%s%s", isodisk, archive) ? "OK" : "NOT EXIST"); + } + + return 0; +} + +static int ventoy_plugin_injection_entry(VTOY_JSON *json, const char *isodisk) +{ + int type = 0; + const char *path = NULL; + const char *archive = NULL; + VTOY_JSON *pNode = NULL; + injection_config *node = NULL; + injection_config *next = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_injection_head) + { + for (node = g_injection_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_injection_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + type = injection_type_file; + path = vtoy_json_get_string_ex(pNode->pstChild, "image"); + if (!path) + { + type = injection_type_parent; + path = vtoy_json_get_string_ex(pNode->pstChild, "parent"); + } + + archive = vtoy_json_get_string_ex(pNode->pstChild, "archive"); + if (path && path[0] == '/' && archive && archive[0] == '/') + { + node = grub_zalloc(sizeof(injection_config)); + if (node) + { + node->type = type; + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", path); + grub_snprintf(node->archive, sizeof(node->archive), "%s", archive); + + if (g_injection_head) + { + node->next = g_injection_head; + } + + g_injection_head = node; + } + } + } + + return 0; +} + +static int ventoy_plugin_menuclass_entry(VTOY_JSON *json, const char *isodisk) +{ + int type; + int parent = 0; + const char *key = NULL; + const char *class = NULL; + VTOY_JSON *pNode = NULL; + menu_class *tail = NULL; + menu_class *node = NULL; + menu_class *next = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_menu_class_head) + { + for (node = g_menu_class_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_menu_class_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + parent = 0; + type = vtoy_class_image_file; + key = vtoy_json_get_string_ex(pNode->pstChild, "key"); + if (!key) + { + key = vtoy_json_get_string_ex(pNode->pstChild, "parent"); + if (key) + { + parent = 1; + } + else + { + key = vtoy_json_get_string_ex(pNode->pstChild, "dir"); + type = vtoy_class_directory; + } + } + + class = vtoy_json_get_string_ex(pNode->pstChild, "class"); + if (key && class) + { + node = grub_zalloc(sizeof(menu_class)); + if (node) + { + node->type = type; + node->parent = parent; + node->patlen = grub_snprintf(node->pattern, sizeof(node->pattern), "%s", key); + grub_snprintf(node->class, sizeof(node->class), "%s", class); + + if (g_menu_class_head) + { + tail->next = node; + } + else + { + g_menu_class_head = node; + } + tail = node; + } + } + } + + return 0; +} + +static int ventoy_plugin_menuclass_check(VTOY_JSON *json, const char *isodisk) +{ + const char *name = NULL; + const char *key = NULL; + const char *class = NULL; + VTOY_JSON *pNode = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + name = "key"; + key = vtoy_json_get_string_ex(pNode->pstChild, "key"); + if (!key) + { + name = "parent"; + key = vtoy_json_get_string_ex(pNode->pstChild, "parent"); + if (!key) + { + name = "dir"; + key = vtoy_json_get_string_ex(pNode->pstChild, "dir"); + } + } + + class = vtoy_json_get_string_ex(pNode->pstChild, "class"); + if (key && class) + { + grub_printf("%s: <%s>\n", name, key); + grub_printf("class: <%s>\n\n", class); + } + } + + return 0; +} + +static int ventoy_plugin_custom_boot_entry(VTOY_JSON *json, const char *isodisk) +{ + int type; + int len; + const char *key = NULL; + const char *cfg = NULL; + VTOY_JSON *pNode = NULL; + custom_boot *tail = NULL; + custom_boot *node = NULL; + custom_boot *next = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_custom_boot_head) + { + for (node = g_custom_boot_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_custom_boot_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + type = vtoy_custom_boot_image_file; + key = vtoy_json_get_string_ex(pNode->pstChild, "file"); + if (!key) + { + key = vtoy_json_get_string_ex(pNode->pstChild, "dir"); + type = vtoy_custom_boot_directory; + } + + cfg = vtoy_json_get_string_ex(pNode->pstChild, "vcfg"); + if (key && cfg) + { + node = grub_zalloc(sizeof(custom_boot)); + if (node) + { + node->type = type; + node->pathlen = grub_snprintf(node->path, sizeof(node->path), "%s", key); + len = (int)grub_snprintf(node->cfg, sizeof(node->cfg), "%s", cfg); + + if (len >= 5 && grub_strncmp(node->cfg + len - 5, ".vcfg", 5) == 0) + { + if (g_custom_boot_head) + { + tail->next = node; + } + else + { + g_custom_boot_head = node; + } + tail = node; + } + else + { + grub_free(node); + } + } + } + } + + return 0; +} + +static int ventoy_plugin_custom_boot_check(VTOY_JSON *json, const char *isodisk) +{ + int type; + int len; + const char *key = NULL; + const char *cfg = NULL; + VTOY_JSON *pNode = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + type = vtoy_custom_boot_image_file; + key = vtoy_json_get_string_ex(pNode->pstChild, "file"); + if (!key) + { + key = vtoy_json_get_string_ex(pNode->pstChild, "dir"); + type = vtoy_custom_boot_directory; + } + + cfg = vtoy_json_get_string_ex(pNode->pstChild, "vcfg"); + len = (int)grub_strlen(cfg); + if (key && cfg) + { + if (len < 5 || grub_strncmp(cfg + len - 5, ".vcfg", 5)) + { + grub_printf("<%s> does not have \".vcfg\" suffix\n\n", cfg); + } + else + { + grub_printf("%s: <%s>\n", (type == vtoy_custom_boot_directory) ? "dir" : "file", key); + grub_printf("vcfg: <%s>\n\n", cfg); + } + } + } + + return 0; +} + +static int ventoy_plugin_conf_replace_entry(VTOY_JSON *json, const char *isodisk) +{ + int img = 0; + const char *isof = NULL; + const char *orgf = NULL; + const char *newf = NULL; + VTOY_JSON *pNode = NULL; + conf_replace *tail = NULL; + conf_replace *node = NULL; + conf_replace *next = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_conf_replace_head) + { + for (node = g_conf_replace_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_conf_replace_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + isof = vtoy_json_get_string_ex(pNode->pstChild, "iso"); + orgf = vtoy_json_get_string_ex(pNode->pstChild, "org"); + newf = vtoy_json_get_string_ex(pNode->pstChild, "new"); + if (isof && orgf && newf && isof[0] == '/' && orgf[0] == '/' && newf[0] == '/') + { + node = grub_zalloc(sizeof(conf_replace)); + if (node) + { + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "img", &img)) + { + node->img = img; + } + + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", isof); + grub_snprintf(node->orgconf, sizeof(node->orgconf), "%s", orgf); + grub_snprintf(node->newconf, sizeof(node->newconf), "%s", newf); + + if (g_conf_replace_head) + { + tail->next = node; + } + else + { + g_conf_replace_head = node; + } + tail = node; + } + } + } + + return 0; +} + +static int ventoy_plugin_conf_replace_check(VTOY_JSON *json, const char *isodisk) +{ + int img = 0; + const char *isof = NULL; + const char *orgf = NULL; + const char *newf = NULL; + VTOY_JSON *pNode = NULL; + grub_file_t file = NULL; + char cmd[256]; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + isof = vtoy_json_get_string_ex(pNode->pstChild, "iso"); + orgf = vtoy_json_get_string_ex(pNode->pstChild, "org"); + newf = vtoy_json_get_string_ex(pNode->pstChild, "new"); + if (isof && orgf && newf && isof[0] == '/' && orgf[0] == '/' && newf[0] == '/') + { + if (ventoy_check_file_exist("%s%s", isodisk, isof)) + { + grub_printf("iso:<%s> [OK]\n", isof); + + grub_snprintf(cmd, sizeof(cmd), "loopback vtisocheck \"%s%s\"", isodisk, isof); + grub_script_execute_sourcecode(cmd); + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(vtisocheck)/%s", orgf); + if (file) + { + if (grub_strcmp(file->fs->name, "iso9660") == 0) + { + grub_printf("org:<%s> [OK]\n", orgf); + } + else + { + grub_printf("org:<%s> [Exist But NOT ISO9660]\n", orgf); + } + grub_file_close(file); + } + else + { + grub_printf("org:<%s> [NOT Exist]\n", orgf); + } + + grub_script_execute_sourcecode("loopback -d vtisocheck"); + } + else if (grub_strchr(isof, '*')) + { + grub_printf("iso:<%s> [*]\n", isof); + grub_printf("org:<%s>\n", orgf); + } + else + { + grub_printf("iso:<%s> [NOT Exist]\n", isof); + grub_printf("org:<%s>\n", orgf); + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", isodisk, newf); + if (file) + { + if (file->size > vtoy_max_replace_file_size) + { + grub_printf("new:<%s> [Too Big %lu] \n", newf, (ulong)file->size); + } + else + { + grub_printf("new1:<%s> [OK]\n", newf); + } + grub_file_close(file); + } + else + { + grub_printf("new:<%s> [NOT Exist]\n", newf); + } + + if (JSON_SUCCESS == vtoy_json_get_int(pNode->pstChild, "img", &img)) + { + grub_printf("img:<%d>\n", img); + } + + grub_printf("\n"); + } + } + + return 0; +} + +static int ventoy_plugin_auto_memdisk_entry(VTOY_JSON *json, const char *isodisk) +{ + VTOY_JSON *pNode = NULL; + auto_memdisk *node = NULL; + auto_memdisk *next = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_auto_memdisk_head) + { + for (node = g_auto_memdisk_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_auto_memdisk_head = NULL; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->enDataType == JSON_TYPE_STRING) + { + node = grub_zalloc(sizeof(auto_memdisk)); + if (node) + { + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", pNode->unData.pcStrVal); + + if (g_auto_memdisk_head) + { + node->next = g_auto_memdisk_head; + } + + g_auto_memdisk_head = node; + } + } + } + + return 0; +} + +static int ventoy_plugin_auto_memdisk_check(VTOY_JSON *json, const char *isodisk) +{ + VTOY_JSON *pNode = NULL; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->enDataType == JSON_TYPE_STRING) + { + grub_printf("<%s> ", pNode->unData.pcStrVal); + + if (grub_strchr(pNode->unData.pcStrVal, '*')) + { + grub_printf(" [*]\n"); + } + else if (ventoy_check_file_exist("%s%s", isodisk, pNode->unData.pcStrVal)) + { + grub_printf(" [OK]\n"); + } + else + { + grub_printf(" [NOT EXIST]\n"); + } + } + } + + return 0; +} + +static int ventoy_plugin_image_list_entry(VTOY_JSON *json, const char *isodisk) +{ + VTOY_JSON *pNode = NULL; + image_list *node = NULL; + image_list *next = NULL; + image_list *tail = NULL; + + (void)isodisk; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + debug("Not array %d\n", json->enDataType); + return 0; + } + + if (g_image_list_head) + { + for (node = g_image_list_head; node; node = next) + { + next = node->next; + grub_free(node); + } + + g_image_list_head = NULL; + } + + if (grub_strncmp(json->pcName, "image_blacklist", 15) == 0) + { + g_plugin_image_list = VENTOY_IMG_BLACK_LIST; + } + else + { + g_plugin_image_list = VENTOY_IMG_WHITE_LIST; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->enDataType == JSON_TYPE_STRING) + { + node = grub_zalloc(sizeof(image_list)); + if (node) + { + node->pathlen = grub_snprintf(node->isopath, sizeof(node->isopath), "%s", pNode->unData.pcStrVal); + + if (g_image_list_head) + { + tail->next = node; + } + else + { + g_image_list_head = node; + } + tail = node; + } + } + } + + return 0; +} + +static int ventoy_plugin_image_list_check(VTOY_JSON *json, const char *isodisk) +{ + VTOY_JSON *pNode = NULL; + + if (json->enDataType != JSON_TYPE_ARRAY) + { + grub_printf("Not array %d\n", json->enDataType); + return 1; + } + + for (pNode = json->pstChild; pNode; pNode = pNode->pstNext) + { + if (pNode->enDataType == JSON_TYPE_STRING) + { + grub_printf("<%s> ", pNode->unData.pcStrVal); + + if (grub_strchr(pNode->unData.pcStrVal, '*')) + { + grub_printf(" [*]\n"); + } + else if (ventoy_check_file_exist("%s%s", isodisk, pNode->unData.pcStrVal)) + { + grub_printf(" [OK]\n"); + } + else + { + grub_printf(" [NOT EXIST]\n"); + } + } + } + + return 0; +} + +static plugin_entry g_plugin_entries[] = +{ + { "control", ventoy_plugin_control_entry, ventoy_plugin_control_check, 0 }, + { "theme", ventoy_plugin_theme_entry, ventoy_plugin_theme_check, 0 }, + { "auto_install", ventoy_plugin_auto_install_entry, ventoy_plugin_auto_install_check, 0 }, + { "persistence", ventoy_plugin_persistence_entry, ventoy_plugin_persistence_check, 0 }, + { "menu_alias", ventoy_plugin_menualias_entry, ventoy_plugin_menualias_check, 0 }, + { "menu_tip", ventoy_plugin_menutip_entry, ventoy_plugin_menutip_check, 0 }, + { "menu_class", ventoy_plugin_menuclass_entry, ventoy_plugin_menuclass_check, 0 }, + { "injection", ventoy_plugin_injection_entry, ventoy_plugin_injection_check, 0 }, + { "auto_memdisk", ventoy_plugin_auto_memdisk_entry, ventoy_plugin_auto_memdisk_check, 0 }, + { "image_list", ventoy_plugin_image_list_entry, ventoy_plugin_image_list_check, 0 }, + { "image_blacklist", ventoy_plugin_image_list_entry, ventoy_plugin_image_list_check, 0 }, + { "conf_replace", ventoy_plugin_conf_replace_entry, ventoy_plugin_conf_replace_check, 0 }, + { "dud", ventoy_plugin_dud_entry, ventoy_plugin_dud_check, 0 }, + { "password", ventoy_plugin_pwd_entry, ventoy_plugin_pwd_check, 0 }, + { "custom_boot", ventoy_plugin_custom_boot_entry, ventoy_plugin_custom_boot_check, 0 }, +}; + +static int ventoy_parse_plugin_config(VTOY_JSON *json, const char *isodisk) +{ + int i; + char key[128]; + VTOY_JSON *cur = NULL; + + grub_snprintf(g_iso_disk_name, sizeof(g_iso_disk_name), "%s", isodisk); + + for (cur = json; cur; cur = cur->pstNext) + { + for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++) + { + grub_snprintf(key, sizeof(key), "%s_%s", g_plugin_entries[i].key, g_arch_mode_suffix); + if (g_plugin_entries[i].flag == 0 && grub_strcmp(key, cur->pcName) == 0) + { + debug("Plugin entry for %s\n", g_plugin_entries[i].key); + g_plugin_entries[i].entryfunc(cur, isodisk); + g_plugin_entries[i].flag = 1; + break; + } + } + } + + + for (cur = json; cur; cur = cur->pstNext) + { + for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++) + { + if (g_plugin_entries[i].flag == 0 && grub_strcmp(g_plugin_entries[i].key, cur->pcName) == 0) + { + debug("Plugin entry for %s\n", g_plugin_entries[i].key); + g_plugin_entries[i].entryfunc(cur, isodisk); + g_plugin_entries[i].flag = 1; + break; + } + } + } + + return 0; +} + +grub_err_t ventoy_cmd_load_plugin(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret = 0; + int offset = 0; + char *buf = NULL; + grub_uint8_t *code = NULL; + grub_file_t file; + VTOY_JSON *json = NULL; + + (void)ctxt; + (void)argc; + + grub_env_set("VTOY_TIP_LEFT", "10%"); + grub_env_set("VTOY_TIP_TOP", "80%+5"); + grub_env_set("VTOY_TIP_COLOR", "blue"); + grub_env_set("VTOY_TIP_ALIGN", "left"); + + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy.json", args[0]); + if (!file) + { + return GRUB_ERR_NONE; + } + + debug("json configuration file size %d\n", (int)file->size); + + buf = grub_malloc(file->size + 1); + if (!buf) + { + grub_file_close(file); + return 1; + } + + buf[file->size] = 0; + grub_file_read(file, buf, file->size); + grub_file_close(file); + + json = vtoy_json_create(); + if (!json) + { + return 1; + } + + code = (grub_uint8_t *)buf; + if (code[0] == 0xef && code[1] == 0xbb && code[2] == 0xbf) + { + offset = 3; /* Skip UTF-8 BOM */ + } + else if ((code[0] == 0xff && code[1] == 0xfe) || (code[0] == 0xfe && code[1] == 0xff)) + { + grub_env_set("VTOY_PLUGIN_SYNTAX_ERROR", "1"); + grub_env_export("VTOY_PLUGIN_SYNTAX_ERROR"); + + grub_env_set("VTOY_PLUGIN_ENCODE_ERROR", "1"); + grub_env_export("VTOY_PLUGIN_ENCODE_ERROR"); + + debug("Failed to parse json string %d\n", ret); + grub_free(buf); + return 1; + } + + ret = vtoy_json_parse(json, buf + offset); + if (ret) + { + grub_env_set("VTOY_PLUGIN_SYNTAX_ERROR", "1"); + grub_env_export("VTOY_PLUGIN_SYNTAX_ERROR"); + + debug("Failed to parse json string %d\n", ret); + grub_free(buf); + return 1; + } + + ventoy_parse_plugin_config(json->pstChild, args[0]); + + vtoy_json_destroy(json); + + grub_free(buf); + + if (g_boot_pwd.type) + { + grub_printf("\n\n======= %s ======\n\n", grub_env_get("VTOY_TEXT_MENU_VER")); + if (ventoy_check_password(&g_boot_pwd, 3)) + { + grub_printf("\n!!! Password check failed, will exit after 5 seconds. !!!\n"); + grub_refresh(); + grub_sleep(5); + grub_exit(); + } + } + + if (g_menu_tip_head) + { + grub_env_set("VTOY_MENU_TIP_ENABLE", "1"); + } + else + { + grub_env_unset("VTOY_MENU_TIP_ENABLE"); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +void ventoy_plugin_dump_injection(void) +{ + injection_config *node = NULL; + + for (node = g_injection_head; node; node = node->next) + { + grub_printf("\n%s:<%s>\n", (node->type == injection_type_file) ? "IMAGE" : "PARENT", node->isopath); + grub_printf("ARCHIVE:<%s>\n", node->archive); + } + + return; +} + + +void ventoy_plugin_dump_auto_install(void) +{ + int i; + install_template *node = NULL; + + for (node = g_install_template_head; node; node = node->next) + { + grub_printf("\n%s:<%s> <%d>\n", + (node->type == auto_install_type_file) ? "IMAGE" : "PARENT", + node->isopath, node->templatenum); + for (i = 0; i < node->templatenum; i++) + { + grub_printf("SCRIPT %d:<%s>\n", i, node->templatepath[i].path); + } + } + + return; +} + +void ventoy_plugin_dump_persistence(void) +{ + int rc; + int i = 0; + persistence_config *node = NULL; + ventoy_img_chunk_list chunk_list; + + for (node = g_persistence_head; node; node = node->next) + { + grub_printf("\nIMAGE:<%s> <%d>\n", node->isopath, node->backendnum); + + for (i = 0; i < node->backendnum; i++) + { + grub_printf("PERSIST %d:<%s>", i, node->backendpath[i].path); + rc = ventoy_plugin_get_persistent_chunklist(node->isopath, i, &chunk_list); + if (rc == 0) + { + grub_printf(" [ SUCCESS ]\n"); + grub_free(chunk_list.chunk); + } + else + { + grub_printf(" [ FAILED ]\n"); + } + } + } + + return; +} + +install_template * ventoy_plugin_find_install_template(const char *isopath) +{ + int len; + install_template *node = NULL; + + if (!g_install_template_head) + { + return NULL; + } + + len = (int)grub_strlen(isopath); + for (node = g_install_template_head; node; node = node->next) + { + if (node->type == auto_install_type_file) + { + if (node->pathlen == len && ventoy_strcmp(node->isopath, isopath) == 0) + { + return node; + } + } + } + + for (node = g_install_template_head; node; node = node->next) + { + if (node->type == auto_install_type_parent) + { + if (node->pathlen < len && ventoy_plugin_is_parent(node->isopath, node->pathlen, isopath)) + { + return node; + } + } + } + + return NULL; +} + +char * ventoy_plugin_get_cur_install_template(const char *isopath, install_template **cur) +{ + install_template *node = NULL; + + if (cur) + { + *cur = NULL; + } + + node = ventoy_plugin_find_install_template(isopath); + if ((!node) || (!node->templatepath)) + { + return NULL; + } + + if (node->cursel < 0 || node->cursel >= node->templatenum) + { + return NULL; + } + + if (cur) + { + *cur = node; + } + + return node->templatepath[node->cursel].path; +} + +persistence_config * ventoy_plugin_find_persistent(const char *isopath) +{ + int len; + persistence_config *node = NULL; + + if (!g_persistence_head) + { + return NULL; + } + + len = (int)grub_strlen(isopath); + for (node = g_persistence_head; node; node = node->next) + { + if ((len == node->pathlen) && (ventoy_strcmp(node->isopath, isopath) == 0)) + { + return node; + } + } + + return NULL; +} + +int ventoy_plugin_get_persistent_chunklist(const char *isopath, int index, ventoy_img_chunk_list *chunk_list) +{ + int rc = 1; + int len = 0; + char *path = NULL; + grub_uint64_t start = 0; + grub_file_t file = NULL; + persistence_config *node = NULL; + + node = ventoy_plugin_find_persistent(isopath); + if ((!node) || (!node->backendpath)) + { + return 1; + } + + if (index < 0) + { + index = node->cursel; + } + + if (index < 0 || index >= node->backendnum) + { + return 1; + } + + path = node->backendpath[index].path; + + if (node->backendpath[index].vlnk_add == 0) + { + len = grub_strlen(path); + if (len > 9 && grub_strncmp(path + len - 9, ".vlnk.dat", 9) == 0) + { + ventoy_add_vlnk_file(NULL, path); + node->backendpath[index].vlnk_add = 1; + } + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", g_iso_disk_name, path); + if (!file) + { + debug("Failed to open file %s%s\n", g_iso_disk_name, path); + goto end; + } + + grub_memset(chunk_list, 0, sizeof(ventoy_img_chunk_list)); + chunk_list->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM); + if (NULL == chunk_list->chunk) + { + goto end; + } + + chunk_list->max_chunk = DEFAULT_CHUNK_NUM; + chunk_list->cur_chunk = 0; + + start = file->device->disk->partition->start; + ventoy_get_block_list(file, chunk_list, start); + + if (0 != ventoy_check_block_list(file, chunk_list, start, NULL, 0)) + { + grub_free(chunk_list->chunk); + chunk_list->chunk = NULL; + goto end; + } + + rc = 0; + +end: + if (file) + grub_file_close(file); + + return rc; +} + +const char * ventoy_plugin_get_injection(const char *isopath) +{ + int len; + injection_config *node = NULL; + + if (!g_injection_head) + { + return NULL; + } + + len = (int)grub_strlen(isopath); + for (node = g_injection_head; node; node = node->next) + { + if (node->type == injection_type_file) + { + if (node->pathlen == len && ventoy_strcmp(node->isopath, isopath) == 0) + { + return node->archive; + } + } + } + + for (node = g_injection_head; node; node = node->next) + { + if (node->type == injection_type_parent) + { + if (node->pathlen < len && ventoy_plugin_is_parent(node->isopath, node->pathlen, isopath)) + { + return node->archive; + } + } + } + + return NULL; +} + +const char * ventoy_plugin_get_menu_alias(int type, const char *isopath) +{ + int len; + menu_alias *node = NULL; + + if (!g_menu_alias_head) + { + return NULL; + } + + len = (int)grub_strlen(isopath); + for (node = g_menu_alias_head; node; node = node->next) + { + if (node->type == type && node->pathlen && + node->pathlen == len && ventoy_strcmp(node->isopath, isopath) == 0) + { + return node->alias; + } + } + + return NULL; +} + +const menu_tip * ventoy_plugin_get_menu_tip(int type, const char *isopath) +{ + int len; + menu_tip *node = NULL; + + if (!g_menu_tip_head) + { + return NULL; + } + + len = (int)grub_strlen(isopath); + for (node = g_menu_tip_head; node; node = node->next) + { + if (node->type == type && node->pathlen && + node->pathlen == len && ventoy_strcmp(node->isopath, isopath) == 0) + { + return node; + } + } + + return NULL; +} + +const char * ventoy_plugin_get_menu_class(int type, const char *name, const char *path) +{ + int namelen; + int pathlen; + menu_class *node = NULL; + + if (!g_menu_class_head) + { + return NULL; + } + + namelen = (int)grub_strlen(name); + pathlen = (int)grub_strlen(path); + + if (vtoy_class_image_file == type) + { + for (node = g_menu_class_head; node; node = node->next) + { + if (node->type != type) + { + continue; + } + + if (node->parent == 0) + { + if ((node->patlen < namelen) && grub_strstr(name, node->pattern)) + { + return node->class; + } + } + } + + for (node = g_menu_class_head; node; node = node->next) + { + if (node->type != type) + { + continue; + } + + if (node->parent) + { + if ((node->patlen < pathlen) && ventoy_plugin_is_parent(node->pattern, node->patlen, path)) + { + return node->class; + } + } + } + } + else + { + for (node = g_menu_class_head; node; node = node->next) + { + if (node->type == type && node->patlen == namelen && grub_strncmp(name, node->pattern, namelen) == 0) + { + return node->class; + } + } + } + + return NULL; +} + +int ventoy_plugin_add_custom_boot(const char *vcfgpath) +{ + int len; + custom_boot *node = NULL; + + node = grub_zalloc(sizeof(custom_boot)); + if (node) + { + node->type = vtoy_custom_boot_image_file; + node->pathlen = grub_snprintf(node->path, sizeof(node->path), "%s", vcfgpath); + grub_snprintf(node->cfg, sizeof(node->cfg), "%s", vcfgpath); + + /* .vcfg */ + len = node->pathlen - 5; + node->path[len] = 0; + node->pathlen = len; + + if (g_custom_boot_head) + { + node->next = g_custom_boot_head; + } + g_custom_boot_head = node; + } + + return 0; +} + +const char * ventoy_plugin_get_custom_boot(const char *isopath) +{ + int i; + int len; + custom_boot *node = NULL; + + if (!g_custom_boot_head) + { + return NULL; + } + + len = (int)grub_strlen(isopath); + + for (node = g_custom_boot_head; node; node = node->next) + { + if (node->type == vtoy_custom_boot_image_file) + { + if (node->pathlen == len && grub_strncmp(isopath, node->path, len) == 0) + { + return node->cfg; + } + } + else + { + if (node->pathlen < len && isopath[node->pathlen] == '/' && + grub_strncmp(isopath, node->path, node->pathlen) == 0) + { + for (i = node->pathlen + 1; i < len; i++) + { + if (isopath[i] == '/') + { + break; + } + } + + if (i >= len) + { + return node->cfg; + } + } + } + } + + return NULL; +} + +grub_err_t ventoy_cmd_dump_custom_boot(grub_extcmd_context_t ctxt, int argc, char **args) +{ + custom_boot *node = NULL; + + (void)argc; + (void)ctxt; + (void)args; + + for (node = g_custom_boot_head; node; node = node->next) + { + grub_printf("[%s] <%s>:<%s>\n", (node->type == vtoy_custom_boot_directory) ? "dir" : "file", + node->path, node->cfg); + } + + return 0; +} + +int ventoy_plugin_check_memdisk(const char *isopath) +{ + int len; + auto_memdisk *node = NULL; + + if (!g_auto_memdisk_head) + { + return 0; + } + + len = (int)grub_strlen(isopath); + for (node = g_auto_memdisk_head; node; node = node->next) + { + if (node->pathlen == len && ventoy_strncmp(node->isopath, isopath, len) == 0) + { + return 1; + } + } + + return 0; +} + +int ventoy_plugin_get_image_list_index(int type, const char *name) +{ + int len; + int index = 1; + image_list *node = NULL; + + if (!g_image_list_head) + { + return 0; + } + + len = (int)grub_strlen(name); + + for (node = g_image_list_head; node; node = node->next, index++) + { + if (vtoy_class_directory == type) + { + if (len < node->pathlen && ventoy_strncmp(node->isopath, name, len) == 0) + { + return index; + } + } + else + { + if (len == node->pathlen && ventoy_strncmp(node->isopath, name, len) == 0) + { + return index; + } + } + } + + return 0; +} + +int ventoy_plugin_find_conf_replace(const char *iso, conf_replace *nodes[VTOY_MAX_CONF_REPLACE]) +{ + int n = 0; + int len; + conf_replace *node; + + if (!g_conf_replace_head) + { + return 0; + } + + len = (int)grub_strlen(iso); + + for (node = g_conf_replace_head; node; node = node->next) + { + if (node->pathlen == len && ventoy_strncmp(node->isopath, iso, len) == 0) + { + nodes[n++] = node; + if (n >= VTOY_MAX_CONF_REPLACE) + { + return n; + } + } + } + + return n; +} + +dud * ventoy_plugin_find_dud(const char *iso) +{ + int len; + dud *node; + + if (!g_dud_head) + { + return NULL; + } + + len = (int)grub_strlen(iso); + for (node = g_dud_head; node; node = node->next) + { + if (node->pathlen == len && ventoy_strncmp(node->isopath, iso, len) == 0) + { + return node; + } + } + + return NULL; +} + +int ventoy_plugin_load_dud(dud *node, const char *isopart) +{ + int i; + char *buf; + grub_file_t file; + + for (i = 0; i < node->dudnum; i++) + { + if (node->files[i].size > 0) + { + debug("file %d has been loaded\n", i); + continue; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", isopart, node->dudpath[i].path); + if (file) + { + buf = grub_malloc(file->size); + if (buf) + { + grub_file_read(file, buf, file->size); + node->files[i].size = (int)file->size; + node->files[i].buf = buf; + } + grub_file_close(file); + } + } + + return 0; +} + +static const vtoy_password * ventoy_plugin_get_password(const char *isopath) +{ + int i; + int len; + const char *pos = NULL; + menu_password *node = NULL; + + if (!isopath) + { + return NULL; + } + + if (g_pwd_head) + { + len = (int)grub_strlen(isopath); + for (node = g_pwd_head; node; node = node->next) + { + if (node->type == vtoy_menu_pwd_file) + { + if (node->pathlen == len && ventoy_strncmp(node->isopath, isopath, len) == 0) + { + return &(node->password); + } + } + } + + for (node = g_pwd_head; node; node = node->next) + { + if (node->type == vtoy_menu_pwd_parent) + { + if (node->pathlen < len && ventoy_plugin_is_parent(node->isopath, node->pathlen, isopath)) + { + return &(node->password); + } + } + } + } + + while (*isopath) + { + if (*isopath == '.') + { + pos = isopath; + } + isopath++; + } + + if (pos) + { + for (i = 0; i < (int)ARRAY_SIZE(g_menu_prefix); i++) + { + if (g_file_type_pwd[i].type && 0 == grub_strcasecmp(pos + 1, g_menu_prefix[i])) + { + return g_file_type_pwd + i; + } + } + } + + return NULL; +} + +grub_err_t ventoy_cmd_check_password(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret; + const vtoy_password *pwd = NULL; + + (void)ctxt; + (void)argc; + + pwd = ventoy_plugin_get_password(args[0]); + if (pwd) + { + if (0 == ventoy_check_password(pwd, 1)) + { + ret = 1; + } + else + { + ret = 0; + } + } + else + { + ret = 1; + } + + grub_errno = 0; + return ret; +} + +grub_err_t ventoy_cmd_plugin_check_json(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i = 0; + int ret = 0; + char *buf = NULL; + char key[128]; + grub_file_t file; + VTOY_JSON *node = NULL; + VTOY_JSON *json = NULL; + + (void)ctxt; + + if (argc != 3) + { + return 0; + } + + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy.json", args[0]); + if (!file) + { + grub_printf("Plugin json file /ventoy/ventoy.json does NOT exist.\n"); + grub_printf("Attention: directory name and filename are both case-sensitive.\n"); + goto end; + } + + buf = grub_malloc(file->size + 1); + if (!buf) + { + grub_printf("Failed to malloc memory %lu.\n", (ulong)(file->size + 1)); + goto end; + } + + buf[file->size] = 0; + grub_file_read(file, buf, file->size); + + json = vtoy_json_create(); + if (!json) + { + grub_printf("Failed to create json\n"); + goto end; + } + + ret = vtoy_json_parse(json, buf); + if (ret) + { + grub_printf("Syntax error detected in ventoy.json, please check it.\n"); + goto end; + } + + grub_snprintf(key, sizeof(key), "%s_%s", args[1], g_arch_mode_suffix); + for (node = json->pstChild; node; node = node->pstNext) + { + if (grub_strcmp(node->pcName, key) == 0) + { + break; + } + } + + if (!node) + { + for (node = json->pstChild; node; node = node->pstNext) + { + if (grub_strcmp(node->pcName, args[1]) == 0) + { + break; + } + } + + if (!node) + { + grub_printf("%s is NOT found in ventoy.json\n", args[1]); + goto end; + } + } + + for (i = 0; i < (int)ARRAY_SIZE(g_plugin_entries); i++) + { + if (grub_strcmp(g_plugin_entries[i].key, args[1]) == 0) + { + if (g_plugin_entries[i].checkfunc) + { + ret = g_plugin_entries[i].checkfunc(node, args[2]); + } + break; + } + } + +end: + check_free(file, grub_file_close); + check_free(json, vtoy_json_destroy); + grub_check_free(buf); + + return 0; +} + +grub_err_t ventoy_cmd_select_theme_cfg(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int pos = 0; + int bufsize = 0; + char *name = NULL; + char *buf = NULL; + theme_list *node = NULL; + + (void)argc; + (void)args; + (void)ctxt; + + if (g_theme_single_file[0]) + { + return 0; + } + + if (g_theme_num < 2) + { + return 0; + } + + bufsize = (g_theme_num + 1) * 1024; + buf = grub_malloc(bufsize); + if (!buf) + { + return 0; + } + + for (node = g_theme_head; node; node = node->next) + { + name = grub_strstr(node->theme.path, ")/"); + if (name) + { + name++; + } + else + { + name = node->theme.path; + } + + pos += grub_snprintf(buf + pos, bufsize - pos, + "menuentry \"%s\" --class=debug_theme_item --class=debug_theme_select --class=F5tool {\n" + "vt_set_theme_path \"%s\"\n" + "}\n", + name, node->theme.path); + } + + pos += grub_snprintf(buf + pos, bufsize - pos, + "menuentry \"$VTLANG_RETURN_PREVIOUS\" --class=vtoyret VTOY_RET {\n" + "echo 'Return ...'\n" + "}\n"); + + grub_script_execute_sourcecode(buf); + grub_free(buf); + + return 0; +} + +extern char g_ventoy_theme_path[256]; + +grub_err_t ventoy_cmd_set_theme(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint32_t i = 0; + grub_uint32_t mod = 0; + grub_uint32_t theme_num = 0; + theme_list *node = g_theme_head; + struct grub_datetime datetime; + struct grub_video_mode_info info; + char buf[64]; + char **pThemePath = NULL; + + (void)argc; + (void)args; + (void)ctxt; + + if (g_theme_single_file[0]) + { + debug("single theme %s\n", g_theme_single_file); + grub_env_set("theme", g_theme_single_file); + goto end; + } + + debug("g_theme_num = %d\n", g_theme_num); + + if (g_theme_num == 0) + { + goto end; + } + + if (g_theme_id > 0 && g_theme_id <= g_theme_num) + { + for (i = 0; i < (grub_uint32_t)(g_theme_id - 1) && node; i++) + { + node = node->next; + } + + grub_env_set("theme", node->theme.path); + goto end; + } + + pThemePath = (char **)grub_zalloc(sizeof(char *) * g_theme_num); + if (!pThemePath) + { + goto end; + } + + if (g_theme_res_fit) + { + if (grub_video_get_info(&info) == GRUB_ERR_NONE) + { + debug("get video info success %ux%u\n", info.width, info.height); + grub_snprintf(buf, sizeof(buf), "%ux%u", info.width, info.height); + for (node = g_theme_head; node; node = node->next) + { + if (grub_strstr(node->theme.path, buf)) + { + pThemePath[theme_num++] = node->theme.path; + } + } + } + } + + if (theme_num == 0) + { + for (node = g_theme_head; node; node = node->next) + { + pThemePath[theme_num++] = node->theme.path; + } + } + + if (theme_num == 1) + { + mod = 0; + debug("Only 1 theme match, no need to random.\n"); + } + else + { + grub_memset(&datetime, 0, sizeof(datetime)); + grub_get_datetime(&datetime); + + if (g_theme_random == vtoy_theme_random_boot_second) + { + grub_divmod32((grub_uint32_t)datetime.second, theme_num, &mod); + } + else if (g_theme_random == vtoy_theme_random_boot_day) + { + grub_divmod32((grub_uint32_t)datetime.day, theme_num, &mod); + } + else if (g_theme_random == vtoy_theme_random_boot_month) + { + grub_divmod32((grub_uint32_t)datetime.month, theme_num, &mod); + } + + debug("%04d/%02d/%02d %02d:%02d:%02d theme_num:%d mod:%d\n", + datetime.year, datetime.month, datetime.day, + datetime.hour, datetime.minute, datetime.second, + theme_num, mod); + } + + if (argc > 0 && grub_strcmp(args[0], "switch") == 0) + { + grub_snprintf(g_ventoy_theme_path, sizeof(g_ventoy_theme_path), "%s", pThemePath[mod]); + } + else + { + debug("random theme %s\n", pThemePath[mod]); + grub_env_set("theme", pThemePath[mod]); + } + g_ventoy_menu_refresh = 1; + +end: + + grub_check_free(pThemePath); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_set_theme_path(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)argc; + (void)ctxt; + + if (argc == 0) + { + g_ventoy_theme_path[0] = 0; + } + else + { + grub_snprintf(g_ventoy_theme_path, sizeof(g_ventoy_theme_path), "%s", args[0]); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +const char *ventoy_get_vmenu_title(const char *vMenu) +{ + return vtoy_json_get_string_ex(g_menu_lang_json->pstChild, vMenu); +} + +int ventoy_plugin_load_menu_lang(int init, const char *lang) +{ + int ret = 1; + grub_file_t file = NULL; + char *buf = NULL; + + if (grub_strcmp(lang, g_cur_menu_language) == 0) + { + debug("Same menu lang %s\n", lang); + return 0; + } + grub_snprintf(g_cur_menu_language, sizeof(g_cur_menu_language), "%s", lang); + + debug("Load menu lang %s\n", g_cur_menu_language); + + if (g_menu_lang_json) + { + vtoy_json_destroy(g_menu_lang_json); + g_menu_lang_json = NULL; + } + + g_menu_lang_json = vtoy_json_create(); + if (!g_menu_lang_json) + { + goto end; + } + + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(vt_menu_tarfs)/menu/%s.json", lang); + if (!file) + { + goto end; + } + + buf = grub_malloc(file->size + 1); + if (!buf) + { + grub_printf("Failed to malloc memory %lu.\n", (ulong)(file->size + 1)); + goto end; + } + + buf[file->size] = 0; + grub_file_read(file, buf, file->size); + + vtoy_json_parse(g_menu_lang_json, buf); + + if (g_default_menu_mode == 0) + { + grub_snprintf(g_ventoy_hotkey_tip, sizeof(g_ventoy_hotkey_tip), "%s", ventoy_get_vmenu_title("VTLANG_STR_HOTKEY_TREE")); + } + else + { + grub_snprintf(g_ventoy_hotkey_tip, sizeof(g_ventoy_hotkey_tip), "%s", ventoy_get_vmenu_title("VTLANG_STR_HOTKEY_LIST")); + } + + if (init == 0) + { + ventoy_menu_push_key(GRUB_TERM_ESC); + ventoy_menu_push_key(GRUB_TERM_ESC); + g_ventoy_menu_refresh = 1; + } + ret = 0; + +end: + + check_free(file, grub_file_close); + grub_check_free(buf); + + return ret; +} + +grub_err_t ventoy_cmd_cur_menu_lang(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + + if (argc > 0) + { + grub_env_set(args[0], g_cur_menu_language); + } + else + { + grub_printf("%s\n", g_cur_menu_language); + grub_printf("%s\n", g_ventoy_hotkey_tip); + grub_refresh(); + } + + VENTOY_CMD_RETURN(0); +} + +grub_err_t ventoy_cmd_push_menulang(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)argc; + (void)ctxt; + + if (g_push_menu_language[0] == 0) + { + grub_memcpy(g_push_menu_language, g_cur_menu_language, sizeof(g_push_menu_language)); + ventoy_plugin_load_menu_lang(0, args[0]); + } + + VENTOY_CMD_RETURN(0); +} + +grub_err_t ventoy_cmd_pop_menulang(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)argc; + (void)ctxt; + (void)args; + + if (g_push_menu_language[0]) + { + ventoy_plugin_load_menu_lang(0, g_push_menu_language); + g_push_menu_language[0] = 0; + } + + VENTOY_CMD_RETURN(0); +} + + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_unix.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_unix.c new file mode 100644 index 0000000..442cf67 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_unix.c @@ -0,0 +1,1264 @@ +/****************************************************************************** + * ventoy_unix.c + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ventoy_def.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +char g_ko_mod_path[256]; +int g_conf_new_len = 0; +char *g_conf_new_data = NULL; + +int g_mod_new_len = 0; +char *g_mod_new_data = NULL; + +int g_mod_search_magic = 0; +int g_unix_vlnk_boot = 0; + +int g_ko_fillmap_len = 0; +char *g_ko_fillmap_data = NULL; + +grub_uint64_t g_mod_override_offset = 0; +grub_uint64_t g_conf_override_offset = 0; + +static int ventoy_get_file_override(const char *filename, grub_uint64_t *offset) +{ + grub_file_t file; + + *offset = 0; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", filename); + if (!file) + { + return 1; + } + + *offset = grub_iso9660_get_last_file_dirent_pos(file) + 2; + + grub_file_close(file); + + return 0; +} + +static grub_uint32_t ventoy_unix_get_override_chunk_count(void) +{ + grub_uint32_t count = 0; + + if (g_conf_new_len > 0) + { + count++; + } + + if (g_mod_new_len > 0) + { + count++; + } + + if (g_ko_fillmap_len > 0) + { + count += (g_ko_fillmap_len / 512); + if ((g_ko_fillmap_len % 512) > 0) + { + count++; + } + } + + return count; +} + +static grub_uint32_t ventoy_unix_get_virt_chunk_count(void) +{ + grub_uint32_t count = 0; + + if (g_conf_new_len > 0) + { + count++; + } + + if (g_mod_new_len > 0) + { + count++; + } + + return count; +} +static grub_uint32_t ventoy_unix_get_virt_chunk_size(void) +{ + grub_uint32_t size; + + size = sizeof(ventoy_virt_chunk) * ventoy_unix_get_virt_chunk_count(); + + if (g_conf_new_len > 0) + { + size += ventoy_align_2k(g_conf_new_len); + } + + if (g_mod_new_len > 0) + { + size += ventoy_align_2k(g_mod_new_len); + } + + return size; +} + +static void ventoy_unix_fill_map_data(ventoy_chain_head *chain, struct g_ventoy_map *map) +{ + grub_uint32_t i; + ventoy_img_chunk *chunk = NULL; + + debug("Fill unix map data: <%llu> <%u> %p\n", + (unsigned long long)chain->os_param.vtoy_disk_size, g_img_chunk_list.cur_chunk, map); + + map->magic1[0] = map->magic2[0] = VENTOY_UNIX_SEG_MAGIC0; + map->magic1[1] = map->magic2[1] = VENTOY_UNIX_SEG_MAGIC1; + map->magic1[2] = map->magic2[2] = VENTOY_UNIX_SEG_MAGIC2; + map->magic1[3] = map->magic2[3] = VENTOY_UNIX_SEG_MAGIC3; + + map->disksize = chain->os_param.vtoy_disk_size; + grub_memcpy(map->diskuuid, chain->os_param.vtoy_disk_guid, 16); + + map->segnum = g_img_chunk_list.cur_chunk; + if (g_img_chunk_list.cur_chunk > VENTOY_UNIX_MAX_SEGNUM) + { + debug("####[FAIL] Too many segments for the ISO file %u\n", g_img_chunk_list.cur_chunk); + map->segnum = VENTOY_UNIX_MAX_SEGNUM; + } + + for (i = 0; i < (grub_uint32_t)(map->segnum); i++) + { + chunk = g_img_chunk_list.chunk + i; + map->seglist[i].seg_start_bytes = chunk->disk_start_sector * 512ULL; + map->seglist[i].seg_end_bytes = (chunk->disk_end_sector + 1) * 512ULL; + } +} + +static void ventoy_unix_fill_override_data( grub_uint64_t isosize, ventoy_chain_head *chain) +{ + int i; + int left; + char *data = NULL; + grub_uint64_t offset; + grub_uint64_t sector; + ventoy_override_chunk *cur; + ventoy_iso9660_override *dirent; + + sector = (isosize + 2047) / 2048; + + cur = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset); + + if (g_conf_new_len > 0) + { + /* loader.conf */ + cur->img_offset = g_conf_override_offset; + cur->override_size = sizeof(ventoy_iso9660_override); + dirent = (ventoy_iso9660_override *)cur->override_data; + dirent->first_sector = (grub_uint32_t)sector; + dirent->size = (grub_uint32_t)g_conf_new_len; + dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector); + dirent->size_be = grub_swap_bytes32(dirent->size); + sector += (dirent->size + 2047) / 2048; + cur++; + } + + if (g_mod_new_len > 0) + { + /* mod.ko */ + cur->img_offset = g_mod_override_offset; + cur->override_size = sizeof(ventoy_iso9660_override); + dirent = (ventoy_iso9660_override *)cur->override_data; + dirent->first_sector = (grub_uint32_t)sector; + dirent->size = (grub_uint32_t)g_mod_new_len; + dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector); + dirent->size_be = grub_swap_bytes32(dirent->size); + sector += (dirent->size + 2047) / 2048; + cur++; + } + + if (g_ko_fillmap_len > 0) + { + data = g_ko_fillmap_data; + offset = g_mod_override_offset; + + ventoy_unix_fill_map_data(chain, (struct g_ventoy_map *)data); + + for (i = 0; i < g_ko_fillmap_len / 512; i++) + { + cur->img_offset = offset; + cur->override_size = 512; + grub_memcpy(cur->override_data, data, 512); + + offset += 512; + data += 512; + cur++; + } + + left = (g_ko_fillmap_len % 512); + if (left > 0) + { + cur->img_offset = offset; + cur->override_size = left; + grub_memcpy(cur->override_data, data, left); + + offset += left; + cur++; + } + } + + return; +} + +static void ventoy_unix_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain) +{ + grub_uint64_t sector; + grub_uint32_t offset; + grub_uint32_t data_secs; + char *override; + ventoy_virt_chunk *cur; + + override = (char *)chain + chain->virt_chunk_offset; + cur = (ventoy_virt_chunk *)override; + + sector = (isosize + 2047) / 2048; + offset = 2 * sizeof(ventoy_virt_chunk); + + if (g_conf_new_len > 0) + { + ventoy_unix_fill_virt(g_conf_new_data, g_conf_new_len); + } + + if (g_mod_new_len > 0) + { + if (g_mod_search_magic > 0) + { + ventoy_unix_fill_map_data(chain, (struct g_ventoy_map *)(g_mod_new_data + g_mod_search_magic)); + } + + ventoy_unix_fill_virt(g_mod_new_data, g_mod_new_len); + } + + return; +} + +static int ventoy_freebsd_append_conf(char *buf, const char *isopath, const char *alias) +{ + int pos = 0; + grub_uint32_t i; + grub_disk_t disk; + grub_file_t isofile; + char uuid[64] = {0}; + const char *val = NULL; + ventoy_img_chunk *chunk; + grub_uint8_t disk_sig[4]; + grub_uint8_t disk_guid[16]; + + debug("ventoy_freebsd_append_conf %s\n", isopath); + + isofile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", isopath); + if (!isofile) + { + return 1; + } + + vtoy_ssprintf(buf, pos, "ventoy_load=\"%s\"\n", "YES"); + vtoy_ssprintf(buf, pos, "ventoy_name=\"%s\"\n", g_ko_mod_path); + + if (alias) + { + vtoy_ssprintf(buf, pos, "hint.ventoy.0.alias=\"%s\"\n", alias); + } + + if (g_unix_vlnk_boot) + { + vtoy_ssprintf(buf, pos, "hint.ventoy.0.vlnk=%d\n", 1); + } + + val = ventoy_get_env("VTOY_UNIX_REMOUNT"); + if (val && val[0] == '1' && val[1] == 0) + { + vtoy_ssprintf(buf, pos, "hint.ventoy.0.remount=%d\n", 1); + } + + if (g_mod_search_magic) + { + debug("hint.ventoy NO need\n"); + goto out; + } + + debug("Fill hint.ventoy info\n"); + + disk = isofile->device->disk; + + ventoy_get_disk_guid(isofile->name, disk_guid, disk_sig); + + for (i = 0; i < 16; i++) + { + grub_snprintf(uuid + i * 2, sizeof(uuid), "%02x", disk_guid[i]); + } + + vtoy_ssprintf(buf, pos, "hint.ventoy.0.disksize=%llu\n", (ulonglong)(disk->total_sectors * (1 << disk->log_sector_size))); + vtoy_ssprintf(buf, pos, "hint.ventoy.0.diskuuid=\"%s\"\n", uuid); + 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]); + vtoy_ssprintf(buf, pos, "hint.ventoy.0.segnum=%u\n", g_img_chunk_list.cur_chunk); + + for (i = 0; i < g_img_chunk_list.cur_chunk; i++) + { + chunk = g_img_chunk_list.chunk + i; + vtoy_ssprintf(buf, pos, "hint.ventoy.%u.seg=\"0x%llx@0x%llx\"\n", + i, (ulonglong)(chunk->disk_start_sector * 512), + (ulonglong)((chunk->disk_end_sector + 1) * 512)); + } + +out: + grub_file_close(isofile); + return pos; +} + +static int ventoy_dragonfly_append_conf(char *buf, const char *isopath) +{ + int pos = 0; + + debug("ventoy_dragonfly_append_conf %s\n", isopath); + + vtoy_ssprintf(buf, pos, "tmpfs_load=\"%s\"\n", "YES"); + vtoy_ssprintf(buf, pos, "dm_target_linear_load=\"%s\"\n", "YES"); + vtoy_ssprintf(buf, pos, "initrd.img_load=\"%s\"\n", "YES"); + vtoy_ssprintf(buf, pos, "initrd.img_type=\"%s\"\n", "md_image"); + vtoy_ssprintf(buf, pos, "vfs.root.mountfrom=\"%s\"\n", "ufs:md0s0"); + + return pos; +} + +grub_err_t ventoy_cmd_unix_reset(grub_extcmd_context_t ctxt, int argc, char **args) +{ + (void)ctxt; + (void)argc; + (void)args; + + g_unix_vlnk_boot = 0; + g_mod_search_magic = 0; + g_conf_new_len = 0; + g_mod_new_len = 0; + g_mod_override_offset = 0; + g_conf_override_offset = 0; + g_ko_fillmap_len = 0; + + check_free(g_mod_new_data, grub_free); + check_free(g_conf_new_data, grub_free); + check_free(g_ko_fillmap_data, grub_free); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_unix_check_vlnk(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_file_t file; + + (void)ctxt; + + if (argc != 1) + { + return 1; + } + + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (file) + { + g_unix_vlnk_boot = file->vlnk; + grub_file_close(file); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_parse_freenas_ver(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_file_t file; + const char *ver = NULL; + char *buf = NULL; + VTOY_JSON *json = NULL; + + (void)ctxt; + (void)argc; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + debug("Failed to open file %s\n", args[0]); + return 1; + } + + buf = grub_malloc(file->size + 2); + if (!buf) + { + grub_file_close(file); + return 0; + } + grub_file_read(file, buf, file->size); + buf[file->size] = 0; + + json = vtoy_json_create(); + if (!json) + { + goto end; + } + + if (vtoy_json_parse(json, buf)) + { + goto end; + } + + ver = vtoy_json_get_string_ex(json->pstChild, "Version"); + if (ver) + { + debug("NAS version:<%s>\n", ver); + if (grub_strncmp(ver, "TrueNAS-", 8) == 0) + { + ver += 8; + } + ventoy_set_env(args[1], ver); + } + else + { + debug("NAS version:<%s>\n", "NOT FOUND"); + grub_env_unset(args[1]); + } + +end: + grub_check_free(buf); + check_free(json, vtoy_json_destroy); + grub_file_close(file); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_unix_freebsd_ver(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_file_t file; + char *buf; + char *start = NULL; + char *nextline = NULL; + + (void)ctxt; + (void)argc; + (void)args; + + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]); + if (!file) + { + debug("Failed to open file %s\n", args[0]); + return 1; + } + + buf = grub_zalloc(file->size + 2); + if (!buf) + { + grub_file_close(file); + return 0; + } + grub_file_read(file, buf, file->size); + + for (start = buf; start; start = nextline) + { + if (grub_strncmp(start, "USERLAND_VERSION", 16) == 0) + { + nextline = start; + while (*nextline && *nextline != '\r' && *nextline != '\n') + { + nextline++; + } + + *nextline = 0; + break; + } + nextline = ventoy_get_line(start); + } + + if (start) + { + debug("freebsd version:<%s>\n", start); + ventoy_set_env(args[1], start); + } + else + { + debug("freebsd version:<%s>\n", "NOT FOUND"); + grub_env_unset(args[1]); + } + + grub_free(buf); + grub_file_close(file); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_freebsd_ver_elf(int bit64, grub_elf_t elf, const char *section, const char *env, char *data) +{ + int j = 0; + int k = 0; + int ret = 1; + char *str = NULL; + void *hdr = NULL; + grub_off_t offset = 0; + grub_uint32_t len = 0; + char ver[64] = {0}; + + if (bit64) + { + Elf64_Ehdr *e = &(elf->ehdr.ehdr64); + Elf64_Shdr *h; + Elf64_Shdr *s; + Elf64_Shdr *t; + Elf64_Half i; + + h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize); + if (!h) + { + goto out; + } + + debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx); + grub_file_seek(elf->file, e->e_shoff); + grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize); + + s = (Elf64_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize); + str = grub_malloc(s->sh_size + 1); + if (!str) + { + goto out; + } + str[s->sh_size] = 0; + + debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size); + grub_file_seek(elf->file, s->sh_offset); + grub_file_read(elf->file, str, s->sh_size); + + for (t = h, i = 0; i < e->e_shnum; i++) + { + if (grub_strcmp(str + t->sh_name, section) == 0) + { + offset = t->sh_offset; + len = t->sh_size; + debug("find %s section at %u %u\n", section, (grub_uint32_t)offset, len); + break; + } + t = (Elf64_Shdr *)((char *)t + e->e_shentsize); + } + } + else + { + Elf32_Ehdr *e = &(elf->ehdr.ehdr32); + Elf32_Shdr *h; + Elf32_Shdr *s; + Elf32_Shdr *t; + Elf32_Half i; + + h = hdr = grub_zalloc(e->e_shnum * e->e_shentsize); + if (!h) + { + goto out; + } + + debug("read section header %u %u %u\n", e->e_shnum, e->e_shentsize, e->e_shstrndx); + grub_file_seek(elf->file, e->e_shoff); + grub_file_read(elf->file, h, e->e_shnum * e->e_shentsize); + + s = (Elf32_Shdr *)((char *)h + e->e_shstrndx * e->e_shentsize); + str = grub_malloc(s->sh_size + 1); + if (!str) + { + goto out; + } + str[s->sh_size] = 0; + + debug("read string table %u %u\n", (grub_uint32_t)s->sh_offset, (grub_uint32_t)s->sh_size); + grub_file_seek(elf->file, s->sh_offset); + grub_file_read(elf->file, str, s->sh_size); + + for (t = h, i = 0; i < e->e_shnum; i++) + { + if (grub_strcmp(str + t->sh_name, section) == 0) + { + offset = t->sh_offset; + len = t->sh_size; + debug("find %s section at %u %u\n", section, (grub_uint32_t)offset, len); + break; + } + t = (Elf32_Shdr *)((char *)t + e->e_shentsize); + } + } + + if (offset == 0 || len == 0) + { + debug("%s section not found\n", section); + goto out; + } + + grub_file_seek(elf->file, offset + len - 8192); + grub_file_read(elf->file, data, 8192); + + for (j = 0; j < 8192 - 12; j++) + { + if (grub_strncmp(data + j, "@(#)FreeBSD ", 12) == 0) + { + for (k = j + 12; k < 8192; k++) + { + if (0 == grub_isdigit(data[k]) && data[k] != '.') + { + data[k] = 0; + break; + } + } + + grub_snprintf(ver, sizeof(ver), "%s", data + j + 12); + break; + } + } + + + if (ver[0]) + { + k = (int)grub_strtoul(ver, NULL, 10); + debug("%s freebsd version:<%s> <%d.x>\n", section, ver, k); + grub_snprintf(ver, sizeof(ver), "%d.x", k); + ventoy_set_env(env, ver); + ret = 0; + } + else + { + debug("%s freebsd version:<%s>\n", section, "NOT FOUND"); + ret = 1; + } + +out: + grub_check_free(str); + grub_check_free(hdr); + return ret; +} + +grub_err_t ventoy_cmd_unix_freebsd_ver_elf(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret = 0; + int bit64 = 0; + char *data = NULL; + grub_elf_t elf = NULL; + + (void)ctxt; + + if (argc != 3) + { + debug("Invalid argc %d\n", argc); + return 1; + } + + data = grub_zalloc(8192); + if (!data) + { + goto out; + } + + elf = grub_elf_open(args[0], GRUB_FILE_TYPE_LINUX_INITRD); + if (!elf) + { + debug("Failed to open file %s\n", args[0]); + goto out; + } + + bit64 = (args[1][0] == '6') ? 1 : 0; + + ret = ventoy_freebsd_ver_elf(bit64, elf, ".data", args[2], data); + if (ret != 0) + { + ret = ventoy_freebsd_ver_elf(bit64, elf, ".rodata", args[2], data); + } + +out: + grub_check_free(data); + check_free(elf, grub_elf_close); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_unix_replace_grub_conf(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int len = 0; + grub_uint32_t i; + char *data; + char *pos; + const char *val = NULL; + grub_uint64_t offset; + grub_file_t file; + char extcfg[512]; + const char *confile = NULL; + const char * loader_conf[] = + { + "/boot/grub/grub.cfg", + }; + + (void)ctxt; + + if (argc != 1 && argc != 2) + { + debug("Replace conf invalid argc %d\n", argc); + return 1; + } + + for (i = 0; i < sizeof(loader_conf) / sizeof(loader_conf[0]); i++) + { + if (ventoy_get_file_override(loader_conf[i], &offset) == 0) + { + confile = loader_conf[i]; + g_conf_override_offset = offset; + break; + } + } + + if (confile == NULL) + { + debug("Can't find grub.cfg file from %u locations\n", i); + return 1; + } + + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(loop)/%s", confile); + if (!file) + { + debug("Failed to open %s \n", confile); + return 1; + } + + debug("old grub2 conf file size:%d\n", (int)file->size); + + data = grub_malloc(VTOY_MAX_SCRIPT_BUF); + if (!data) + { + grub_file_close(file); + return 1; + } + + grub_file_read(file, data, file->size); + grub_file_close(file); + + g_conf_new_data = data; + g_conf_new_len = (int)file->size; + + pos = grub_strstr(data, "kfreebsd /boot/kernel/kernel"); + if (pos) + { + pos += grub_strlen("kfreebsd /boot/kernel/kernel"); + if (grub_strncmp(pos, ".gz", 3) == 0) + { + pos += 3; + } + + if (argc == 2) + { + vtoy_ssprintf(extcfg, len, ";kfreebsd_module_elf %s; set kFreeBSD.hint.ventoy.0.alias=\"%s\"", args[0], args[1]); + } + else + { + vtoy_ssprintf(extcfg, len, ";kfreebsd_module_elf %s", args[0]); + } + + if (g_unix_vlnk_boot) + { + vtoy_ssprintf(extcfg, len, ";set kFreeBSD.hint.ventoy.0.vlnk=%d", 1); + } + + val = ventoy_get_env("VTOY_UNIX_REMOUNT"); + if (val && val[0] == '1' && val[1] == 0) + { + vtoy_ssprintf(extcfg, len, ";set kFreeBSD.hint.ventoy.0.remount=%d", 1); + } + + grub_memmove(pos + len, pos, (int)(file->size - (pos - data))); + grub_memcpy(pos, extcfg, len); + g_conf_new_len += len; + } + else + { + debug("no kfreebsd found\n"); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_unix_replace_conf(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint32_t i; + char *data; + grub_uint64_t offset; + grub_file_t file; + const char *confile = NULL; + const char * loader_conf[] = + { + "/boot/loader.conf", + "/boot/defaults/loader.conf", + }; + + (void)ctxt; + + if (argc != 2 && argc != 3) + { + debug("Replace conf invalid argc %d\n", argc); + return 1; + } + + for (i = 0; i < sizeof(loader_conf) / sizeof(loader_conf[0]); i++) + { + if (ventoy_get_file_override(loader_conf[i], &offset) == 0) + { + confile = loader_conf[i]; + g_conf_override_offset = offset; + break; + } + } + + if (confile == NULL) + { + debug("Can't find loader.conf file from %u locations\n", i); + return 1; + } + + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(loop)/%s", confile); + if (!file) + { + debug("Failed to open %s \n", confile); + return 1; + } + + debug("old conf file <%s> size:%d\n", confile, (int)file->size); + + data = grub_malloc(VTOY_MAX_SCRIPT_BUF); + if (!data) + { + grub_file_close(file); + return 1; + } + + grub_file_read(file, data, file->size); + grub_file_close(file); + + g_conf_new_data = data; + g_conf_new_len = (int)file->size; + + if (grub_strcmp(args[0], "FreeBSD") == 0) + { + g_conf_new_len += ventoy_freebsd_append_conf(data + file->size, args[1], (argc > 2) ? args[2] : NULL); + } + else if (grub_strcmp(args[0], "DragonFly") == 0) + { + g_conf_new_len += ventoy_dragonfly_append_conf(data + file->size, args[1]); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static int ventoy_unix_search_magic(char *data, int len) +{ + int i; + grub_uint32_t *magic = NULL; + + for (i = 0; i < len; i += 4096) + { + magic = (grub_uint32_t *)(data + i); + if (magic[0] == VENTOY_UNIX_SEG_MAGIC0 && magic[1] == VENTOY_UNIX_SEG_MAGIC1 && + magic[2] == VENTOY_UNIX_SEG_MAGIC2 && magic[3] == VENTOY_UNIX_SEG_MAGIC3) + { + debug("unix find search magic at 0x%x loop:%d\n", i, (i >> 12)); + g_mod_search_magic = i; + return 0; + } + } + + debug("unix can not find search magic\n"); + return 1; +} + +grub_err_t ventoy_cmd_unix_replace_ko(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char *data; + grub_uint64_t offset; + grub_file_t file; + + (void)ctxt; + + if (argc != 2) + { + debug("Replace ko invalid argc %d\n", argc); + return 1; + } + + debug("replace ko %s\n", args[0]); + + if (ventoy_get_file_override(args[0], &offset) == 0) + { + grub_snprintf(g_ko_mod_path, sizeof(g_ko_mod_path), "%s", args[0]); + g_mod_override_offset = offset; + } + else + { + debug("Can't find replace ko file from %s\n", args[0]); + return 1; + } + + file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[1]); + if (!file) + { + debug("Failed to open %s \n", args[1]); + return 1; + } + + debug("new ko file size:%d\n", (int)file->size); + + data = grub_malloc(file->size); + if (!data) + { + debug("Failed to alloc memory for new ko %d\n", (int)file->size); + grub_file_close(file); + return 1; + } + + grub_file_read(file, data, file->size); + grub_file_close(file); + + g_mod_new_data = data; + g_mod_new_len = (int)file->size; + + ventoy_unix_search_magic(g_mod_new_data, g_mod_new_len); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_unix_ko_fillmap(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + grub_file_t file; + grub_uint32_t magic[4]; + grub_uint32_t len; + + (void)ctxt; + + if (argc != 1) + { + debug("Fillmap ko invalid argc %d\n", argc); + return 1; + } + + debug("Fillmap ko %s\n", args[0]); + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", args[0]); + if (file) + { + grub_file_read(file, magic, 4); /* read for trigger */ + g_mod_override_offset = grub_iso9660_get_last_read_pos(file); + } + else + { + debug("Can't find replace ko file from %s\n", args[0]); + return 1; + } + + for (i = 0; i < (int)(file->size); i += 65536) + { + magic[0] = 0; + grub_file_seek(file, i); + grub_file_read(file, magic, sizeof(magic)); + + if (magic[0] == VENTOY_UNIX_SEG_MAGIC0 && magic[1] == VENTOY_UNIX_SEG_MAGIC1 && + magic[2] == VENTOY_UNIX_SEG_MAGIC2 && magic[3] == VENTOY_UNIX_SEG_MAGIC3) + { + debug("unix find search magic at 0x%x loop:%d\n", i, (i >> 16)); + g_mod_override_offset += i; + break; + } + } + + len = (grub_uint32_t)OFFSET_OF(struct g_ventoy_map, seglist) + + (sizeof(struct g_ventoy_seg) * g_img_chunk_list.cur_chunk); + + g_ko_fillmap_len = (int)len; + g_ko_fillmap_data = grub_malloc(len); + if (!g_ko_fillmap_data) + { + g_ko_fillmap_len = 0; + debug("Failed to malloc fillmap data\n"); + } + + debug("Fillmap ko segnum:%u, override len:%u data:%p\n", g_img_chunk_list.cur_chunk, len, g_ko_fillmap_data); + + grub_file_close(file); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_unix_fill_image_desc(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + grub_uint8_t *byte; + grub_uint32_t memsize; + ventoy_image_desc *desc; + grub_uint8_t flag[32] = { + 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF + }; + + (void)ctxt; + (void)argc; + (void)args; + + debug("ventoy_cmd_unix_fill_image_desc %p\n", g_mod_new_data); + + if (!g_mod_new_data) + { + goto end; + } + + byte = (grub_uint8_t *)g_mod_new_data; + for (i = 0; i < g_mod_new_len - 32; i += 16) + { + if (byte[i] == 0xFF && byte[i + 1] == 0xEE) + { + if (grub_memcmp(flag, byte + i, 32) == 0) + { + debug("Find position flag at %d(0x%x)\n", i, i); + break; + } + } + } + + if (i >= g_mod_new_len - 32) + { + debug("Failed to find position flag %d\n", i); + goto end; + } + + desc = (ventoy_image_desc *)(byte + i); + desc->disk_size = g_ventoy_disk_size; + desc->part1_size = g_ventoy_disk_part_size[0]; + grub_memcpy(desc->disk_uuid, g_ventoy_part_info->MBR.BootCode + 0x180, 16); + grub_memcpy(desc->disk_signature, g_ventoy_part_info->MBR.BootCode + 0x1B8, 4); + + desc->img_chunk_count = g_img_chunk_list.cur_chunk; + memsize = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk); + + debug("image chunk count:%u memsize:%u\n", desc->img_chunk_count, memsize); + + if (memsize >= VTOY_SIZE_1MB * 8) + { + grub_printf("image chunk count:%u memsize:%u too big\n", desc->img_chunk_count, memsize); + goto end; + } + + grub_memcpy(desc + 1, g_img_chunk_list.chunk, memsize); + +end: + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_unix_gzip_newko(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int newlen; + grub_uint8_t *buf; + + (void)ctxt; + (void)argc; + (void)args; + + debug("ventoy_cmd_unix_gzip_newko %p\n", g_mod_new_data); + + if (!g_mod_new_data) + { + goto end; + } + + buf = grub_malloc(g_mod_new_len); + if (!buf) + { + goto end; + } + + newlen = ventoy_gzip_compress(g_mod_new_data, g_mod_new_len, buf, g_mod_new_len); + + grub_free(g_mod_new_data); + + debug("gzip org len:%d newlen:%d\n", g_mod_new_len, newlen); + + g_mod_new_data = (char *)buf; + g_mod_new_len = newlen; + +end: + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_unix_chain_data(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ventoy_compatible = 0; + grub_uint32_t size = 0; + grub_uint64_t isosize = 0; + grub_uint32_t boot_catlog = 0; + grub_uint32_t img_chunk_size = 0; + grub_uint32_t override_count = 0; + grub_uint32_t override_size = 0; + grub_uint32_t virt_chunk_size = 0; + grub_file_t file; + grub_disk_t disk; + const char *pLastChain = NULL; + const char *compatible; + ventoy_chain_head *chain; + + (void)ctxt; + (void)argc; + + compatible = grub_env_get("ventoy_compatible"); + if (compatible && compatible[0] == 'Y') + { + ventoy_compatible = 1; + } + + if (NULL == g_img_chunk_list.chunk) + { + grub_printf("ventoy not ready\n"); + return 1; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + return 1; + } + + isosize = file->size; + + boot_catlog = ventoy_get_iso_boot_catlog(file); + if (boot_catlog) + { + if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog))) + { + grub_env_set("LoadIsoEfiDriver", "on"); + } + } + else + { + if (ventoy_is_efi_os()) + { + grub_env_set("LoadIsoEfiDriver", "on"); + } + else + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]); + } + } + + img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk); + + if (ventoy_compatible) + { + size = sizeof(ventoy_chain_head) + img_chunk_size; + } + else + { + override_count = ventoy_unix_get_override_chunk_count(); + override_size = override_count * sizeof(ventoy_override_chunk); + + virt_chunk_size = ventoy_unix_get_virt_chunk_size(); + size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size; + } + + pLastChain = grub_env_get("vtoy_chain_mem_addr"); + if (pLastChain) + { + chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16); + if (chain) + { + debug("free last chain memory %p\n", chain); + grub_free(chain); + } + } + + chain = ventoy_alloc_chain(size); + if (!chain) + { + grub_printf("Failed to alloc chain unix memory size %u\n", size); + grub_file_close(file); + return 1; + } + + ventoy_memfile_env_set("vtoy_chain_mem", chain, (ulonglong)size); + + grub_memset(chain, 0, sizeof(ventoy_chain_head)); + + /* part 1: os parameter */ + g_ventoy_chain_type = ventoy_chain_linux; + ventoy_fill_os_param(file, &(chain->os_param)); + + /* part 2: chain head */ + disk = file->device->disk; + chain->disk_drive = disk->id; + chain->disk_sector_size = (1 << disk->log_sector_size); + chain->real_img_size_in_bytes = file->size; + chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048; + chain->boot_catalog = boot_catlog; + + if (!ventoy_is_efi_os()) + { + grub_file_seek(file, boot_catlog * 2048); + grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector)); + } + + /* part 3: image chunk */ + chain->img_chunk_offset = sizeof(ventoy_chain_head); + chain->img_chunk_num = g_img_chunk_list.cur_chunk; + grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size); + + if (ventoy_compatible) + { + return 0; + } + + /* part 4: override chunk */ + chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size; + chain->override_chunk_num = override_count; + ventoy_unix_fill_override_data(isosize, chain); + + /* part 5: virt chunk */ + chain->virt_chunk_offset = chain->override_chunk_offset + override_size; + chain->virt_chunk_num = ventoy_unix_get_virt_chunk_count(); + ventoy_unix_fill_virt_data(isosize, chain); + + grub_file_close(file); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_vhd.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_vhd.c new file mode 100644 index 0000000..b96c618 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_vhd.c @@ -0,0 +1,754 @@ +/****************************************************************************** + * ventoy_vhd.c + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef GRUB_MACHINE_EFI +#include +#endif +#include +#include "ventoy_def.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +static int g_vhdboot_isolen = 0; +static char *g_vhdboot_totbuf = NULL; +static char *g_vhdboot_isobuf = NULL; +static grub_uint64_t g_img_trim_head_secnum = 0; + +static int ventoy_vhd_find_bcd(int *bcdoffset, int *bcdlen, const char *path) +{ + grub_uint32_t offset; + grub_file_t file; + char cmdbuf[128]; + + grub_snprintf(cmdbuf, sizeof(cmdbuf), "loopback vhdiso mem:0x%lx:size:%d", (ulong)g_vhdboot_isobuf, g_vhdboot_isolen); + + grub_script_execute_sourcecode(cmdbuf); + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(vhdiso)%s", path); + if (!file) + { + return 1; + } + + grub_file_read(file, &offset, 4); + offset = (grub_uint32_t)grub_iso9660_get_last_read_pos(file); + + *bcdoffset = (int)offset; + *bcdlen = (int)file->size; + + debug("vhdiso bcd file offset:%d len:%d\n", *bcdoffset, *bcdlen); + + grub_file_close(file); + + grub_script_execute_sourcecode("loopback -d vhdiso"); + + return 0; +} + +static int ventoy_vhd_patch_path(char *vhdpath, ventoy_patch_vhd *patch1, ventoy_patch_vhd *patch2, + int bcdoffset, int bcdlen) +{ + int i; + int cnt = 0; + char *pos; + grub_size_t pathlen; + const char *plat; + char *newpath = NULL; + grub_uint16_t *unicode_path; + const grub_uint8_t winloadexe[] = + { + 0x77, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x61, 0x00, 0x64, 0x00, 0x2E, 0x00, + 0x65, 0x00, 0x78, 0x00, 0x65, 0x00 + }; + + while ((*vhdpath) != '/') + { + vhdpath++; + } + + pathlen = sizeof(grub_uint16_t) * (grub_strlen(vhdpath) + 1); + debug("unicode path for <%s> len:%d\n", vhdpath, (int)pathlen); + + unicode_path = grub_zalloc(pathlen); + if (!unicode_path) + { + return 0; + } + + plat = grub_env_get("grub_platform"); + + if (plat && (plat[0] == 'e')) /* UEFI */ + { + pos = g_vhdboot_isobuf + bcdoffset; + + /* winload.exe ==> winload.efi */ + for (i = 0; i + (int)sizeof(winloadexe) < bcdlen; i++) + { + if (*((grub_uint32_t *)(pos + i)) == 0x00690077 && + grub_memcmp(pos + i, winloadexe, sizeof(winloadexe)) == 0) + { + pos[i + sizeof(winloadexe) - 4] = 0x66; + pos[i + sizeof(winloadexe) - 2] = 0x69; + cnt++; + } + } + + debug("winload patch %d times\n", cnt); + } + + newpath = grub_strdup(vhdpath); + for (pos = newpath; *pos; pos++) + { + if (*pos == '/') + { + *pos = '\\'; + } + } + + grub_utf8_to_utf16(unicode_path, pathlen, (grub_uint8_t *)newpath, -1, NULL); + grub_memcpy(patch1->vhd_file_path, unicode_path, pathlen); + grub_memcpy(patch2->vhd_file_path, unicode_path, pathlen); + + grub_free(newpath); + return 0; +} + +static int ventoy_vhd_read_parttbl(const char *filename, ventoy_gpt_info *gpt, int *index, grub_uint64_t *poffset) +{ + int i; + int find = 0; + int ret = 1; + grub_uint64_t start; + grub_file_t file = NULL; + grub_disk_t disk = NULL; + grub_uint8_t zeroguid[16] = {0}; + + file = grub_file_open(filename, VENTOY_FILE_TYPE); + if (!file) + { + goto end; + } + + disk = grub_disk_open(file->device->disk->name); + if (!disk) + { + goto end; + } + + grub_disk_read(disk, 0, 0, sizeof(ventoy_gpt_info), gpt); + + start = file->device->disk->partition->start; + + if (grub_memcmp(gpt->Head.Signature, "EFI PART", 8) == 0) + { + debug("GPT part start: %llu\n", (ulonglong)start); + for (i = 0; i < 128; i++) + { + if (grub_memcmp(gpt->PartTbl[i].PartGuid, zeroguid, 16)) + { + if (start == gpt->PartTbl[i].StartLBA) + { + *index = i; + find = 1; + break; + } + } + } + } + else + { + debug("MBR part start: %llu\n", (ulonglong)start); + for (i = 0; i < 4; i++) + { + if ((grub_uint32_t)start == gpt->MBR.PartTbl[i].StartSectorId) + { + *index = i; + find = 1; + break; + } + } + } + + if (find == 0) // MBR Logical partition + { + if (file->device->disk->partition->number > 0) + { + *index = file->device->disk->partition->number; + debug("Fall back part number: %d\n", *index); + } + } + + *poffset = start; + ret = 0; + +end: + check_free(file, grub_file_close); + check_free(disk, grub_disk_close); + + return ret; +} + +static int ventoy_vhd_patch_disk(const char *vhdpath, ventoy_patch_vhd *patch1, ventoy_patch_vhd *patch2) +{ + int partIndex = 0; + grub_uint64_t offset = 0; + char efipart[16] = {0}; + ventoy_gpt_info *gpt = NULL; + + if (vhdpath[0] == '/') + { + gpt = g_ventoy_part_info; + partIndex = 0; + debug("This is Ventoy ISO partIndex %d %s\n", partIndex, vhdpath); + } + else + { + gpt = grub_zalloc(sizeof(ventoy_gpt_info)); + ventoy_vhd_read_parttbl(vhdpath, gpt, &partIndex, &offset); + debug("This is HDD partIndex %d %s\n", partIndex, vhdpath); + } + + grub_memcpy(efipart, gpt->Head.Signature, sizeof(gpt->Head.Signature)); + + grub_memset(patch1, 0, OFFSET_OF(ventoy_patch_vhd, vhd_file_path)); + grub_memset(patch2, 0, OFFSET_OF(ventoy_patch_vhd, vhd_file_path)); + + if (grub_strncmp(efipart, "EFI PART", 8) == 0) + { + ventoy_debug_dump_guid("GPT disk GUID: ", gpt->Head.DiskGuid); + ventoy_debug_dump_guid("GPT partIndex GUID: ", gpt->PartTbl[partIndex].PartGuid); + + grub_memcpy(patch1->disk_signature_or_guid, gpt->Head.DiskGuid, 16); + grub_memcpy(patch1->part_offset_or_guid, gpt->PartTbl[partIndex].PartGuid, 16); + grub_memcpy(patch2->disk_signature_or_guid, gpt->Head.DiskGuid, 16); + grub_memcpy(patch2->part_offset_or_guid, gpt->PartTbl[partIndex].PartGuid, 16); + + patch1->part_type = patch2->part_type = 0; + } + else + { + if (offset == 0) + { + offset = gpt->MBR.PartTbl[partIndex].StartSectorId; + } + offset *= 512; + debug("MBR disk signature: %02x%02x%02x%02x Part(%d) offset:%llu\n", + gpt->MBR.BootCode[0x1b8 + 0], gpt->MBR.BootCode[0x1b8 + 1], + gpt->MBR.BootCode[0x1b8 + 2], gpt->MBR.BootCode[0x1b8 + 3], + partIndex + 1, offset); + + grub_memcpy(patch1->part_offset_or_guid, &offset, 8); + grub_memcpy(patch2->part_offset_or_guid, &offset, 8); + + grub_memcpy(patch1->disk_signature_or_guid, gpt->MBR.BootCode + 0x1b8, 4); + grub_memcpy(patch2->disk_signature_or_guid, gpt->MBR.BootCode + 0x1b8, 4); + + patch1->part_type = patch2->part_type = 1; + } + + if (gpt != g_ventoy_part_info) + { + grub_free(gpt); + } + + return 0; +} + +static int ventoy_find_vhdpatch_offset(int bcdoffset, int bcdlen, int *offset) +{ + int i; + int cnt = 0; + grub_uint8_t *buf = (grub_uint8_t *)(g_vhdboot_isobuf + bcdoffset); + grub_uint8_t magic[16] = { + 0x5C, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00 + }; + + for (i = 0; i < bcdlen - 16 && cnt < 2; i++) + { + if (*(grub_uint32_t *)(buf + i) == 0x0058005C) + { + if (grub_memcmp(magic, buf + i, 16) == 0) + { + *offset++ = i - (int)OFFSET_OF(ventoy_patch_vhd, vhd_file_path); + cnt++; + } + } + } + + return 0; +} + +grub_err_t ventoy_cmd_patch_vhdboot(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int rc; + int bcdoffset, bcdlen; + int patchoffset[2]; + ventoy_patch_vhd *patch1; + ventoy_patch_vhd *patch2; + + (void)ctxt; + (void)argc; + + grub_env_unset("vtoy_vhd_buf_addr"); + + debug("patch vhd <%s>\n", args[0]); + + if ((!g_vhdboot_enable) || (!g_vhdboot_totbuf)) + { + debug("vhd boot not ready %d %p\n", g_vhdboot_enable, g_vhdboot_totbuf); + return 0; + } + + rc = ventoy_vhd_find_bcd(&bcdoffset, &bcdlen, "/boot/bcd"); + if (rc) + { + debug("failed to get bcd location %d\n", rc); + } + else + { + ventoy_find_vhdpatch_offset(bcdoffset, bcdlen, patchoffset); + patch1 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + bcdoffset + patchoffset[0]); + patch2 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + bcdoffset + patchoffset[1]); + + debug("Find /boot/bcd (%d %d) now patch it (offset: 0x%x 0x%x) ...\n", + bcdoffset, bcdlen, patchoffset[0], patchoffset[1]); + ventoy_vhd_patch_disk(args[0], patch1, patch2); + ventoy_vhd_patch_path(args[0], patch1, patch2, bcdoffset, bcdlen); + } + + rc = ventoy_vhd_find_bcd(&bcdoffset, &bcdlen, "/boot/BCD"); + if (rc) + { + debug("No file /boot/BCD \n"); + } + else + { + ventoy_find_vhdpatch_offset(bcdoffset, bcdlen, patchoffset); + patch1 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + bcdoffset + patchoffset[0]); + patch2 = (ventoy_patch_vhd *)(g_vhdboot_isobuf + bcdoffset + patchoffset[1]); + + debug("Find /boot/BCD (%d %d) now patch it (offset: 0x%x 0x%x) ...\n", + bcdoffset, bcdlen, patchoffset[0], patchoffset[1]); + ventoy_vhd_patch_disk(args[0], patch1, patch2); + ventoy_vhd_patch_path(args[0], patch1, patch2, bcdoffset, bcdlen); + } + + /* set buffer and size */ +#ifdef GRUB_MACHINE_EFI + ventoy_memfile_env_set("vtoy_vhd_buf", g_vhdboot_totbuf, (ulonglong)(g_vhdboot_isolen + sizeof(ventoy_chain_head))); +#else + ventoy_memfile_env_set("vtoy_vhd_buf", g_vhdboot_isobuf, (ulonglong)g_vhdboot_isolen); +#endif + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_load_vhdboot(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int buflen; + grub_file_t file; + + (void)ctxt; + (void)argc; + + g_vhdboot_enable = 0; + grub_check_free(g_vhdboot_totbuf); + + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (!file) + { + return 0; + } + + debug("load vhd boot: <%s> <%lu>\n", args[0], (ulong)file->size); + + if (file->size < VTOY_SIZE_1KB * 32) + { + grub_file_close(file); + return 0; + } + + g_vhdboot_isolen = (int)file->size; + + buflen = (int)(file->size + sizeof(ventoy_chain_head)); + +#ifdef GRUB_MACHINE_EFI + g_vhdboot_totbuf = (char *)grub_efi_allocate_iso_buf(buflen); +#else + g_vhdboot_totbuf = (char *)grub_malloc(buflen); +#endif + + if (!g_vhdboot_totbuf) + { + grub_file_close(file); + return 0; + } + + g_vhdboot_isobuf = g_vhdboot_totbuf + sizeof(ventoy_chain_head); + + grub_file_read(file, g_vhdboot_isobuf, file->size); + grub_file_close(file); + + g_vhdboot_enable = 1; + + return 0; +} + +static int ventoy_raw_trim_head(grub_uint64_t offset) +{ + grub_uint32_t i; + grub_uint32_t memsize; + grub_uint32_t imgstart = 0; + grub_uint32_t imgsecs = 0; + grub_uint64_t sectors = 0; + grub_uint64_t cursecs = 0; + grub_uint64_t delta = 0; + + if ((!g_img_chunk_list.chunk) || (!offset)) + { + debug("image chunk not ready %p %lu\n", g_img_chunk_list.chunk, (ulong)offset); + return 0; + } + + debug("image trim head %lu\n", (ulong)offset); + + for (i = 0; i < g_img_chunk_list.cur_chunk; i++) + { + cursecs = g_img_chunk_list.chunk[i].disk_end_sector + 1 - g_img_chunk_list.chunk[i].disk_start_sector; + sectors += cursecs; + if (sectors >= offset) + { + delta = cursecs - (sectors - offset); + break; + } + } + + if (sectors < offset || i >= g_img_chunk_list.cur_chunk) + { + debug("Invalid size %lu %lu\n", (ulong)sectors, (ulong)offset); + return 0; + } + + if (sectors == offset) + { + memsize = (g_img_chunk_list.cur_chunk - (i + 1)) * sizeof(ventoy_img_chunk); + grub_memmove(g_img_chunk_list.chunk, g_img_chunk_list.chunk + i + 1, memsize); + g_img_chunk_list.cur_chunk -= (i + 1); + } + else + { + g_img_chunk_list.chunk[i].disk_start_sector += delta; + g_img_chunk_list.chunk[i].img_start_sector += (grub_uint32_t)(delta / 4); + + if (i > 0) + { + memsize = (g_img_chunk_list.cur_chunk - i) * sizeof(ventoy_img_chunk); + grub_memmove(g_img_chunk_list.chunk, g_img_chunk_list.chunk + i, memsize); + g_img_chunk_list.cur_chunk -= i; + } + } + + for (i = 0; i < g_img_chunk_list.cur_chunk; i++) + { + imgsecs = g_img_chunk_list.chunk[i].img_end_sector + 1 - g_img_chunk_list.chunk[i].img_start_sector; + g_img_chunk_list.chunk[i].img_start_sector = imgstart; + g_img_chunk_list.chunk[i].img_end_sector = imgstart + (imgsecs - 1); + imgstart += imgsecs; + } + + return 0; +} + +grub_err_t ventoy_cmd_get_vtoy_type(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int altboot = 0; + int offset = -1; + grub_file_t file; + grub_uint8_t data = 0; + vhd_footer_t vhdfoot; + VDIPREHEADER vdihdr; + char type[16] = {0}; + ventoy_gpt_info *gpt = NULL; + + (void)ctxt; + + g_img_trim_head_secnum = 0; + + if (argc != 4) + { + return 0; + } + + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (!file) + { + debug("Failed to open file %s\n", args[0]); + return 0; + } + + grub_snprintf(type, sizeof(type), "unknown"); + + grub_file_seek(file, file->size - 512); + grub_file_read(file, &vhdfoot, sizeof(vhdfoot)); + + if (grub_strncmp(vhdfoot.cookie, "conectix", 8) == 0) + { + offset = 0; + grub_snprintf(type, sizeof(type), "vhd%u", grub_swap_bytes32(vhdfoot.disktype)); + } + else + { + grub_file_seek(file, 0); + grub_file_read(file, &vdihdr, sizeof(vdihdr)); + if (vdihdr.u32Signature == VDI_IMAGE_SIGNATURE) + { + grub_snprintf(type, sizeof(type), "vdi"); + if (grub_strncmp(vdihdr.szFileInfo, VDI_IMAGE_FILE_INFO, grub_strlen(VDI_IMAGE_FILE_INFO)) == 0) + { + offset = 2 * 1048576; + g_img_trim_head_secnum = offset / 512; + debug("VDI V1\n"); + } + else if (grub_strncmp(vdihdr.szFileInfo, VDI_IMAGE_FILE_INFO2, grub_strlen(VDI_IMAGE_FILE_INFO2)) == 0) + { + offset = 2 * 1048576; + g_img_trim_head_secnum = offset / 512; + debug("VDI V2\n"); + } + else + { + debug("invalid file info <%s>\n", vdihdr.szFileInfo); + } + } + else + { + offset = 0; + grub_snprintf(type, sizeof(type), "raw"); + } + } + + grub_env_set(args[1], type); + debug("<%s> vtoy type: <%s> offset:%d\n", args[0], type, offset); + + if (offset >= 0) + { + gpt = grub_zalloc(sizeof(ventoy_gpt_info)); + if (!gpt) + { + grub_env_set(args[1], "unknown"); + goto end; + } + + grub_file_seek(file, offset); + grub_file_read(file, gpt, sizeof(ventoy_gpt_info)); + + if (gpt->MBR.Byte55 != 0x55 || gpt->MBR.ByteAA != 0xAA) + { + grub_env_set(args[1], "unknown"); + debug("invalid mbr signature: 0x%x 0x%x offset=%d\n", gpt->MBR.Byte55, gpt->MBR.ByteAA, offset); + goto end; + } + + if (grub_memcmp(gpt->Head.Signature, "EFI PART", 8) == 0) + { + grub_env_set(args[2], "gpt"); + debug("part type: %s\n", "GPT"); + + if (gpt->MBR.PartTbl[0].FsFlag == 0xEE) + { + for (i = 0; i < 128; i++) + { + if (grub_memcmp(gpt->PartTbl[i].PartType, "Hah!IdontNeedEFI", 16) == 0) + { + debug("part %d is grub_bios part\n", i); + altboot = 1; + grub_env_set(args[3], "1"); + break; + } + else if (gpt->PartTbl[i].LastLBA == 0) + { + break; + } + } + } + + if (!altboot) + { + if (gpt->MBR.BootCode[92] == 0x22) + { + grub_file_seek(file, offset + 17908); + grub_file_read(file, &data, 1); + if (data == 0x23) + { + altboot = 1; + grub_env_set(args[3], "1"); + } + else + { + debug("offset data=0x%x\n", data); + } + } + else + { + debug("BootCode: 0x%x\n", gpt->MBR.BootCode[92]); + } + } + } + else + { + grub_env_set(args[2], "mbr"); + debug("part type: %s\n", "MBR"); + + for (i = 0; i < 4; i++) + { + if (gpt->MBR.PartTbl[i].FsFlag == 0xEF) + { + debug("part %d is esp part in MBR mode\n", i); + altboot = 1; + grub_env_set(args[3], "1"); + break; + } + } + } + } + else + { + debug("part type: %s\n", "xxx"); + } + +end: + grub_check_free(gpt); + grub_file_close(file); + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_raw_chain_data(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint32_t size = 0; + grub_uint32_t img_chunk_size = 0; + grub_file_t file; + grub_disk_t disk; + const char *pLastChain = NULL; + ventoy_chain_head *chain; + + (void)ctxt; + (void)argc; + + if (NULL == g_img_chunk_list.chunk) + { + grub_printf("ventoy not ready\n"); + return 1; + } + + if (g_img_trim_head_secnum > 0) + { + ventoy_raw_trim_head(g_img_trim_head_secnum); + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + return 1; + } + + if (grub_strncmp(args[0], g_iso_path, grub_strlen(g_iso_path))) + { + file->vlnk = 1; + } + + img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk); + + size = sizeof(ventoy_chain_head) + img_chunk_size; + + pLastChain = grub_env_get("vtoy_chain_mem_addr"); + if (pLastChain) + { + chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16); + if (chain) + { + debug("free last chain memory %p\n", chain); + grub_free(chain); + } + } + + chain = ventoy_alloc_chain(size); + if (!chain) + { + grub_printf("Failed to alloc chain raw memory size %u\n", size); + grub_file_close(file); + return 1; + } + + ventoy_memfile_env_set("vtoy_chain_mem", chain, (ulonglong)size); + + grub_env_export("vtoy_chain_mem_addr"); + grub_env_export("vtoy_chain_mem_size"); + + grub_memset(chain, 0, sizeof(ventoy_chain_head)); + + /* part 1: os parameter */ + g_ventoy_chain_type = ventoy_chain_linux; + ventoy_fill_os_param(file, &(chain->os_param)); + + /* part 2: chain head */ + disk = file->device->disk; + chain->disk_drive = disk->id; + chain->disk_sector_size = (1 << disk->log_sector_size); + + chain->real_img_size_in_bytes = file->size; + if (g_img_trim_head_secnum > 0) + { + chain->real_img_size_in_bytes -= g_img_trim_head_secnum * 512; + } + + chain->virt_img_size_in_bytes = chain->real_img_size_in_bytes; + chain->boot_catalog = 0; + + /* part 3: image chunk */ + chain->img_chunk_offset = sizeof(ventoy_chain_head); + chain->img_chunk_num = g_img_chunk_list.cur_chunk; + grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size); + + grub_file_seek(file, g_img_trim_head_secnum * 512); + grub_file_read(file, chain->boot_catalog_sector, 512); + + grub_file_close(file); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_windows.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_windows.c new file mode 100644 index 0000000..5d2a664 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/ventoy_windows.c @@ -0,0 +1,2781 @@ +/****************************************************************************** + * ventoy_windows.c + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ventoy_def.h" + +GRUB_MOD_LICENSE ("GPLv3+"); + +static int g_iso_fs_type = 0; +static int g_wim_total_patch_count = 0; +static int g_wim_valid_patch_count = 0; +static wim_patch *g_wim_patch_head = NULL; + +static grub_uint64_t g_suppress_wincd_override_offset = 0; +static grub_uint32_t g_suppress_wincd_override_data = 0; + +grub_uint8_t g_temp_buf[512]; + +grub_ssize_t lzx_decompress ( const void *data, grub_size_t len, void *buf ); +grub_ssize_t xca_decompress ( const void *data, grub_size_t len, void *buf ); + +static wim_patch *ventoy_find_wim_patch(const char *path) +{ + int len = (int)grub_strlen(path); + wim_patch *node = g_wim_patch_head; + + while (node) + { + if (len == node->pathlen && 0 == grub_strcmp(path, node->path)) + { + return node; + } + node = node->next; + } + + return NULL; +} + +static int ventoy_collect_wim_patch(const char *bcdfile) +{ + int i, j, k; + int rc = 1; + grub_uint64_t magic; + grub_file_t file = NULL; + char *buf = NULL; + wim_patch *node = NULL; + char c; + grub_uint8_t byte; + char valid; + char path[256]; + + g_ventoy_case_insensitive = 1; + file = grub_file_open(bcdfile, VENTOY_FILE_TYPE); + g_ventoy_case_insensitive = 0; + if (!file) + { + debug("Failed to open file %s\n", bcdfile); + grub_errno = 0; + goto end; + } + + buf = grub_malloc(file->size + 8); + if (!buf) + { + goto end; + } + + grub_file_read(file, buf, file->size); + + for (i = 0; i < (int)file->size - 8; i++) + { + if (buf[i + 8] != 0) + { + continue; + } + + magic = *(grub_uint64_t *)(buf + i); + + /* .wim .WIM .Wim */ + if ((magic == 0x006D00690077002EULL) || + (magic == 0x004D00490057002EULL) || + (magic == 0x006D00690057002EULL)) + { + for (j = i; j > 0; j-= 2) + { + if (*(grub_uint16_t *)(buf + j) == 0) + { + break; + } + } + + if (j > 0) + { + byte = (grub_uint8_t)(*(grub_uint16_t *)(buf + j + 2)); + if (byte != '/' && byte != '\\') + { + continue; + } + + valid = 1; + for (k = 0, j += 2; k < (int)sizeof(path) - 1 && j < i + 8; j += 2) + { + byte = (grub_uint8_t)(*(grub_uint16_t *)(buf + j)); + c = (char)byte; + if (byte > '~' || byte < ' ') /* not printable */ + { + valid = 0; + break; + } + else if (c == '\\') + { + c = '/'; + } + + path[k++] = c; + } + path[k++] = 0; + + debug("@@@@ Find wim flag:<%s>\n", path); + + if (0 == valid) + { + debug("Invalid wim file %d\n", k); + } + else if (NULL == ventoy_find_wim_patch(path)) + { + node = grub_zalloc(sizeof(wim_patch)); + if (node) + { + node->pathlen = grub_snprintf(node->path, sizeof(node->path), "%s", path); + + debug("add patch <%s>\n", path); + + if (g_wim_patch_head) + { + node->next = g_wim_patch_head; + } + g_wim_patch_head = node; + + g_wim_total_patch_count++; + } + } + else + { + debug("wim <%s> already exist\n", path); + } + } + } + } + +end: + check_free(file, grub_file_close); + grub_check_free(buf); + return rc; +} + +grub_err_t ventoy_cmd_wim_patch_count(grub_extcmd_context_t ctxt, int argc, char **args) +{ + char buf[32]; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc == 1) + { + grub_snprintf(buf, sizeof(buf), "%d", g_wim_total_patch_count); + ventoy_set_env(args[0], buf); + } + + return 0; +} + +grub_err_t ventoy_cmd_collect_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args) +{ + wim_patch *node = NULL; + + (void)ctxt; + (void)argc; + (void)args; + + if (argc != 2) + { + return 1; + } + + debug("ventoy_cmd_collect_wim_patch %s %s\n", args[0], args[1]); + + if (grub_strcmp(args[0], "bcd") == 0) + { + ventoy_collect_wim_patch(args[1]); + return 0; + } + + if (NULL == ventoy_find_wim_patch(args[1])) + { + node = grub_zalloc(sizeof(wim_patch)); + if (node) + { + node->pathlen = grub_snprintf(node->path, sizeof(node->path), "%s", args[1]); + + debug("add patch <%s>\n", args[1]); + + if (g_wim_patch_head) + { + node->next = g_wim_patch_head; + } + g_wim_patch_head = node; + + g_wim_total_patch_count++; + } + } + + return 0; +} + + +grub_err_t ventoy_cmd_dump_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i = 0; + wim_patch *node = NULL; + + (void)ctxt; + (void)argc; + (void)args; + + for (node = g_wim_patch_head; node; node = node->next) + { + grub_printf("%d %s [%s]\n", i++, node->path, node->valid ? "SUCCESS" : "FAIL"); + } + + return 0; +} + + +static int wim_name_cmp(const char *search, grub_uint16_t *name, grub_uint16_t namelen) +{ + char c1 = vtoy_to_upper(*search); + char c2 = vtoy_to_upper(*name); + + while (namelen > 0 && (c1 == c2)) + { + search++; + name++; + namelen--; + + c1 = vtoy_to_upper(*search); + c2 = vtoy_to_upper(*name); + } + + if (namelen == 0 && *search == 0) + { + return 0; + } + + return 1; +} + +static int ventoy_is_pe64(grub_uint8_t *buffer) +{ + grub_uint32_t pe_off; + + if (buffer[0] != 'M' || buffer[1] != 'Z') + { + return 0; + } + + pe_off = *(grub_uint32_t *)(buffer + 60); + + if (buffer[pe_off] != 'P' || buffer[pe_off + 1] != 'E') + { + return 0; + } + + if (*(grub_uint16_t *)(buffer + pe_off + 24) == 0x020b) + { + return 1; + } + + return 0; +} + +grub_err_t ventoy_cmd_is_pe64(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int ret = 1; + grub_file_t file; + grub_uint8_t buf[512]; + + (void)ctxt; + (void)argc; + + file = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (!file) + { + return 1; + } + + grub_memset(buf, 0, 512); + grub_file_read(file, buf, 512); + if (ventoy_is_pe64(buf)) + { + debug("%s is PE64\n", args[0]); + ret = 0; + } + else + { + debug("%s is PE32\n", args[0]); + } + grub_file_close(file); + + return ret; +} + +grub_err_t ventoy_cmd_sel_wimboot(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int size; + char *buf = NULL; + char configfile[128]; + + (void)ctxt; + (void)argc; + (void)args; + + debug("select wimboot argc:%d\n", argc); + + buf = (char *)grub_malloc(8192); + if (!buf) + { + return 0; + } + + size = (int)grub_snprintf(buf, 8192, + "menuentry \"Windows Setup (32-bit)\" {\n" + " set vtoy_wimboot_sel=32\n" + "}\n" + "menuentry \"Windows Setup (64-bit)\" {\n" + " set vtoy_wimboot_sel=64\n" + "}\n" + ); + buf[size] = 0; + + g_ventoy_menu_esc = 1; + g_ventoy_suppress_esc = 1; + g_ventoy_suppress_esc_default = 1; + + grub_snprintf(configfile, sizeof(configfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)buf, size); + grub_script_execute_sourcecode(configfile); + + g_ventoy_menu_esc = 0; + g_ventoy_suppress_esc = 0; + + grub_free(buf); + + if (g_ventoy_last_entry == 0) + { + debug("last entry=%d %s=32\n", g_ventoy_last_entry, args[0]); + grub_env_set(args[0], "32"); + } + else + { + debug("last entry=%d %s=64\n", g_ventoy_last_entry, args[0]); + grub_env_set(args[0], "64"); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_wimdows_reset(grub_extcmd_context_t ctxt, int argc, char **args) +{ + wim_patch *next = NULL; + wim_patch *node = g_wim_patch_head; + + (void)ctxt; + (void)argc; + (void)args; + + while (node) + { + next = node->next; + grub_free(node); + node = next; + } + + g_wim_patch_head = NULL; + g_wim_total_patch_count = 0; + g_wim_valid_patch_count = 0; + + return 0; +} + +static int ventoy_load_jump_exe(const char *path, grub_uint8_t **data, grub_uint32_t *size, wim_hash *hash) +{ + grub_uint32_t i; + grub_uint32_t align; + grub_file_t file; + + debug("windows load jump %s\n", path); + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", path); + if (!file) + { + debug("Can't open file %s\n", path); + return 1; + } + + align = ventoy_align((int)file->size, 2048); + + debug("file %s size:%d align:%u\n", path, (int)file->size, align); + + *size = (grub_uint32_t)file->size; + *data = (grub_uint8_t *)grub_malloc(align); + if ((*data) == NULL) + { + debug("Failed to alloc memory size %u\n", align); + goto end; + } + + grub_file_read(file, (*data), file->size); + + if (hash) + { + grub_crypto_hash(GRUB_MD_SHA1, hash->sha1, (*data), file->size); + + if (g_ventoy_debug) + { + debug("%s", "jump bin 64 hash: "); + for (i = 0; i < sizeof(hash->sha1); i++) + { + ventoy_debug("%02x ", hash->sha1[i]); + } + ventoy_debug("\n"); + } + } + +end: + + grub_file_close(file); + return 0; +} + +static int ventoy_get_override_info(grub_file_t file, wim_tail *wim_data) +{ + grub_uint32_t start_block; + grub_uint64_t file_offset; + grub_uint64_t override_offset; + grub_uint32_t override_len; + grub_uint64_t fe_entry_size_offset; + + if (grub_strcmp(file->fs->name, "iso9660") == 0) + { + g_iso_fs_type = wim_data->iso_type = 0; + override_len = sizeof(ventoy_iso9660_override); + override_offset = grub_iso9660_get_last_file_dirent_pos(file) + 2; + + grub_file_read(file, &start_block, 1); // just read for hook trigger + file_offset = grub_iso9660_get_last_read_pos(file); + + debug("iso9660 wim size:%llu override_offset:%llu file_offset:%llu\n", + (ulonglong)file->size, (ulonglong)override_offset, (ulonglong)file_offset); + } + else + { + g_iso_fs_type = wim_data->iso_type = 1; + override_len = sizeof(ventoy_udf_override); + override_offset = grub_udf_get_last_file_attr_offset(file, &start_block, &fe_entry_size_offset); + + file_offset = grub_udf_get_file_offset(file); + + debug("UDF wim size:%llu override_offset:%llu file_offset:%llu start_block=%u\n", + (ulonglong)file->size, (ulonglong)override_offset, (ulonglong)file_offset, start_block); + } + + wim_data->file_offset = file_offset; + wim_data->udf_start_block = start_block; + wim_data->fe_entry_size_offset = fe_entry_size_offset; + wim_data->override_offset = override_offset; + wim_data->override_len = override_len; + + return 0; +} + +static int ventoy_read_resource(grub_file_t fp, wim_header *wimhdr, wim_resource_header *head, void **buffer) +{ + int decompress_len = 0; + int total_decompress = 0; + grub_uint32_t i = 0; + grub_uint32_t chunk_num = 0; + grub_uint32_t chunk_size = 0; + grub_uint32_t last_chunk_size = 0; + grub_uint32_t last_decompress_size = 0; + grub_uint32_t cur_offset = 0; + grub_uint8_t *cur_dst = NULL; + grub_uint8_t *buffer_compress = NULL; + grub_uint8_t *buffer_decompress = NULL; + grub_uint32_t *chunk_offset = NULL; + + buffer_decompress = (grub_uint8_t *)grub_malloc(head->raw_size + head->size_in_wim); + if (NULL == buffer_decompress) + { + return 0; + } + + grub_file_seek(fp, head->offset); + + if (head->size_in_wim == head->raw_size) + { + grub_file_read(fp, buffer_decompress, head->size_in_wim); + *buffer = buffer_decompress; + return 0; + } + + buffer_compress = buffer_decompress + head->raw_size; + grub_file_read(fp, buffer_compress, head->size_in_wim); + + chunk_num = (head->raw_size + WIM_CHUNK_LEN - 1) / WIM_CHUNK_LEN; + cur_offset = (chunk_num - 1) * 4; + chunk_offset = (grub_uint32_t *)buffer_compress; + + //debug("%llu %llu chunk_num=%lu", (ulonglong)head->size_in_wim, (ulonglong)head->raw_size, chunk_num); + + cur_dst = buffer_decompress; + + for (i = 0; i < chunk_num - 1; i++) + { + chunk_size = (i == 0) ? chunk_offset[i] : chunk_offset[i] - chunk_offset[i - 1]; + + if (WIM_CHUNK_LEN == chunk_size) + { + grub_memcpy(cur_dst, buffer_compress + cur_offset, chunk_size); + decompress_len = (int)chunk_size; + } + else + { + if (wimhdr->flags & FLAG_HEADER_COMPRESS_XPRESS) + { + decompress_len = (int)xca_decompress(buffer_compress + cur_offset, chunk_size, cur_dst); + } + else + { + decompress_len = (int)lzx_decompress(buffer_compress + cur_offset, chunk_size, cur_dst); + } + } + + //debug("chunk_size:%u decompresslen:%d\n", chunk_size, decompress_len); + + total_decompress += decompress_len; + cur_dst += decompress_len; + cur_offset += chunk_size; + } + + /* last chunk */ + last_chunk_size = (grub_uint32_t)(head->size_in_wim - cur_offset); + last_decompress_size = head->raw_size - total_decompress; + + if (last_chunk_size < WIM_CHUNK_LEN && last_chunk_size == last_decompress_size) + { + debug("Last chunk %u uncompressed\n", last_chunk_size); + grub_memcpy(cur_dst, buffer_compress + cur_offset, last_chunk_size); + decompress_len = (int)last_chunk_size; + } + else + { + if (wimhdr->flags & FLAG_HEADER_COMPRESS_XPRESS) + { + decompress_len = (int)xca_decompress(buffer_compress + cur_offset, head->size_in_wim - cur_offset, cur_dst); + } + else + { + decompress_len = (int)lzx_decompress(buffer_compress + cur_offset, head->size_in_wim - cur_offset, cur_dst); + } + } + + cur_dst += decompress_len; + total_decompress += decompress_len; + + //debug("last chunk_size:%u decompresslen:%d tot:%d\n", last_chunk_size, decompress_len, total_decompress); + + if (cur_dst != buffer_decompress + head->raw_size) + { + debug("head->size_in_wim:%llu head->raw_size:%llu cur_dst:%p buffer_decompress:%p total_decompress:%d\n", + (ulonglong)head->size_in_wim, (ulonglong)head->raw_size, cur_dst, buffer_decompress, total_decompress); + grub_free(buffer_decompress); + return 1; + } + + *buffer = buffer_decompress; + return 0; +} + + +static wim_directory_entry * search_wim_dirent(wim_directory_entry *dir, const char *search_name) +{ + do + { + if (dir->len && dir->name_len) + { + if (wim_name_cmp(search_name, (grub_uint16_t *)(dir + 1), dir->name_len / 2) == 0) + { + return dir; + } + } + dir = (wim_directory_entry *)((grub_uint8_t *)dir + dir->len); + } while(dir->len); + + return NULL; +} + +static wim_directory_entry * search_full_wim_dirent +( + void *meta_data, + wim_directory_entry *dir, + const char **path +) +{ + wim_directory_entry *subdir = NULL; + wim_directory_entry *search = dir; + + while (*path) + { + subdir = (wim_directory_entry *)((char *)meta_data + search->subdir); + search = search_wim_dirent(subdir, *path); + path++; + } + + return search; +} + + + +static wim_lookup_entry * ventoy_find_look_entry(wim_header *header, wim_lookup_entry *lookup, wim_hash *hash) +{ + grub_uint32_t i = 0; + + for (i = 0; i < (grub_uint32_t)header->lookup.raw_size / sizeof(wim_lookup_entry); i++) + { + if (grub_memcmp(&lookup[i].hash, hash, sizeof(wim_hash)) == 0) + { + return lookup + i; + } + } + + return NULL; +} + +static int parse_registry_setup_cmdline +( + grub_file_t file, + wim_header *head, + wim_lookup_entry *lookup, + void *meta_data, + wim_directory_entry *dir, + char *buf, + grub_uint32_t buflen +) +{ + char c; + int ret = 0; + grub_uint32_t i = 0; + grub_uint32_t reglen = 0; + wim_hash zerohash; + reg_vk *regvk = NULL; + wim_lookup_entry *look = NULL; + wim_directory_entry *wim_dirent = NULL; + char *decompress_data = NULL; + const char *reg_path[] = { "Windows", "System32", "config", "SYSTEM", NULL }; + + wim_dirent = search_full_wim_dirent(meta_data, dir, reg_path); + debug("search reg SYSTEM %p\n", wim_dirent); + if (!wim_dirent) + { + return 1; + } + + grub_memset(&zerohash, 0, sizeof(zerohash)); + if (grub_memcmp(&zerohash, wim_dirent->hash.sha1, sizeof(wim_hash)) == 0) + { + return 2; + } + + look = ventoy_find_look_entry(head, lookup, &wim_dirent->hash); + if (!look) + { + return 3; + } + + reglen = (grub_uint32_t)look->resource.raw_size; + debug("find system lookup entry_id:%ld raw_size:%u\n", + ((long)look - (long)lookup) / sizeof(wim_lookup_entry), reglen); + + if (0 != ventoy_read_resource(file, head, &(look->resource), (void **)&(decompress_data))) + { + return 4; + } + + if (grub_strncmp(decompress_data + 0x1000, "hbin", 4)) + { + ret_goto_end(5); + } + + for (i = 0x1000; i + sizeof(reg_vk) < reglen; i += 8) + { + regvk = (reg_vk *)(decompress_data + i); + if (regvk->sig == 0x6B76 && regvk->namesize == 7 && + regvk->datatype == 1 && regvk->flag == 1) + { + if (grub_strncasecmp((char *)(regvk + 1), "cmdline", 7) == 0) + { + debug("find registry cmdline i:%u offset:(0x%x)%u size:(0x%x)%u\n", + i, regvk->dataoffset, regvk->dataoffset, regvk->datasize, regvk->datasize); + break; + } + } + } + + if (i + sizeof(reg_vk) >= reglen || regvk == NULL) + { + ret_goto_end(6); + } + + if (regvk->datasize == 0 || (regvk->datasize & 0x80000000) > 0 || + regvk->dataoffset == 0 || regvk->dataoffset == 0xFFFFFFFF) + { + ret_goto_end(7); + } + + if (regvk->datasize / 2 >= buflen) + { + ret_goto_end(8); + } + + debug("start offset is 0x%x(%u)\n", 0x1000 + regvk->dataoffset + 4, 0x1000 + regvk->dataoffset + 4); + + for (i = 0; i < regvk->datasize; i+=2) + { + c = (char)(*(grub_uint16_t *)(decompress_data + 0x1000 + regvk->dataoffset + 4 + i)); + *buf++ = c; + } + + ret = 0; + +end: + grub_check_free(decompress_data); + return ret; +} + +static int parse_custom_setup_path(char *cmdline, const char **path, char *exefile) +{ + int i = 0; + int len = 0; + char *pos1 = NULL; + char *pos2 = NULL; + + if ((cmdline[0] == 'x' || cmdline[0] == 'X') && cmdline[1] == ':') + { + pos1 = pos2 = cmdline + 3; + + while (i < VTOY_MAX_DIR_DEPTH && *pos2) + { + while (*pos2 && *pos2 != '\\' && *pos2 != '/') + { + pos2++; + } + + path[i++] = pos1; + + if (*pos2 == 0) + { + break; + } + + *pos2 = 0; + pos1 = pos2 + 1; + pos2 = pos1; + } + + if (i == 0 || i >= VTOY_MAX_DIR_DEPTH) + { + return 1; + } + } + else + { + path[i++] = "Windows"; + path[i++] = "System32"; + path[i++] = cmdline; + } + + pos1 = (char *)path[i - 1]; + while (*pos1 != ' ' && *pos1 != '\t' && *pos1) + { + pos1++; + } + *pos1 = 0; + + len = (int)grub_strlen(path[i - 1]); + if (len < 4 || grub_strcasecmp(path[i - 1] + len - 4, ".exe") != 0) + { + grub_snprintf(exefile, 256, "%s.exe", path[i - 1]); + path[i - 1] = exefile; + } + + + debug("custom setup: %d <%s>\n", i, path[i - 1]); + return 0; +} + +static wim_directory_entry * search_replace_wim_dirent +( + grub_file_t file, + wim_header *head, + wim_lookup_entry *lookup, + void *meta_data, + wim_directory_entry *dir +) +{ + int ret; + char exefile[256] = {0}; + char cmdline[256] = {0}; + wim_directory_entry *wim_dirent = NULL; + wim_directory_entry *pecmd_dirent = NULL; + const char *peset_path[] = { "Windows", "System32", "peset.exe", NULL }; + const char *pecmd_path[] = { "Windows", "System32", "pecmd.exe", NULL }; + const char *winpeshl_path[] = { "Windows", "System32", "winpeshl.exe", NULL }; + const char *custom_path[VTOY_MAX_DIR_DEPTH + 1] = { NULL }; + + pecmd_dirent = search_full_wim_dirent(meta_data, dir, pecmd_path); + debug("search pecmd.exe %p\n", pecmd_dirent); + + if (pecmd_dirent) + { + ret = parse_registry_setup_cmdline(file, head, lookup, meta_data, dir, cmdline, sizeof(cmdline) - 1); + if (0 == ret) + { + debug("registry setup cmdline:<%s>\n", cmdline); + + if (grub_strncasecmp(cmdline, "PECMD", 5) == 0) + { + wim_dirent = pecmd_dirent; + } + else if (grub_strncasecmp(cmdline, "PESET", 5) == 0) + { + wim_dirent = search_full_wim_dirent(meta_data, dir, peset_path); + debug("search peset.exe %p\n", wim_dirent); + } + else if (grub_strncasecmp(cmdline, "WINPESHL", 8) == 0) + { + wim_dirent = search_full_wim_dirent(meta_data, dir, winpeshl_path); + debug("search winpeshl.exe %p\n", wim_dirent); + } + else if (0 == parse_custom_setup_path(cmdline, custom_path, exefile)) + { + wim_dirent = search_full_wim_dirent(meta_data, dir, custom_path); + debug("search custom path %p\n", wim_dirent); + } + + if (wim_dirent) + { + return wim_dirent; + } + } + else + { + debug("registry setup cmdline failed : %d\n", ret); + } + } + + wim_dirent = pecmd_dirent; + if (wim_dirent) + { + return wim_dirent; + } + + wim_dirent = search_full_wim_dirent(meta_data, dir, winpeshl_path); + debug("search winpeshl.exe %p\n", wim_dirent); + if (wim_dirent) + { + return wim_dirent; + } + + return NULL; +} + + +static wim_lookup_entry * ventoy_find_meta_entry(wim_header *header, wim_lookup_entry *lookup) +{ + grub_uint32_t i = 0; + grub_uint32_t index = 0;; + + if ((header == NULL) || (lookup == NULL)) + { + return NULL; + } + + for (i = 0; i < (grub_uint32_t)header->lookup.raw_size / sizeof(wim_lookup_entry); i++) + { + if (lookup[i].resource.flags & RESHDR_FLAG_METADATA) + { + index++; + if (index == header->boot_index) + { + return lookup + i; + } + } + } + + return NULL; +} + +static grub_uint64_t ventoy_get_stream_len(wim_directory_entry *dir) +{ + grub_uint16_t i; + grub_uint64_t offset = 0; + wim_stream_entry *stream = (wim_stream_entry *)((char *)dir + dir->len); + + for (i = 0; i < dir->streams; i++) + { + offset += stream->len; + stream = (wim_stream_entry *)((char *)stream + stream->len); + } + + return offset; +} + +static int ventoy_update_stream_hash(wim_patch *patch, wim_directory_entry *dir) +{ + grub_uint16_t i; + grub_uint64_t offset = 0; + wim_stream_entry *stream = (wim_stream_entry *)((char *)dir + dir->len); + + for (i = 0; i < dir->streams; i++) + { + if (grub_memcmp(stream->hash.sha1, patch->old_hash.sha1, sizeof(wim_hash)) == 0) + { + debug("find target stream %u, name_len:%u upadte hash\n", i, stream->name_len); + grub_memcpy(stream->hash.sha1, &(patch->wim_data.bin_hash), sizeof(wim_hash)); + } + + offset += stream->len; + stream = (wim_stream_entry *)((char *)stream + stream->len); + } + + return offset; +} + +static int ventoy_update_all_hash(wim_patch *patch, void *meta_data, wim_directory_entry *dir) +{ + if ((meta_data == NULL) || (dir == NULL)) + { + return 0; + } + + if (dir->len < sizeof(wim_directory_entry)) + { + return 0; + } + + do + { + if (dir->subdir == 0 && grub_memcmp(dir->hash.sha1, patch->old_hash.sha1, sizeof(wim_hash)) == 0) + { + debug("find target file, name_len:%u upadte hash\n", dir->name_len); + grub_memcpy(dir->hash.sha1, &(patch->wim_data.bin_hash), sizeof(wim_hash)); + } + + if (dir->subdir) + { + ventoy_update_all_hash(patch, meta_data, (wim_directory_entry *)((char *)meta_data + dir->subdir)); + } + + if (dir->streams) + { + ventoy_update_stream_hash(patch, dir); + dir = (wim_directory_entry *)((char *)dir + dir->len + ventoy_get_stream_len(dir)); + } + else + { + dir = (wim_directory_entry *)((char *)dir + dir->len); + } + } while (dir->len >= sizeof(wim_directory_entry)); + + return 0; +} + +static int ventoy_cat_exe_file_data(wim_tail *wim_data, grub_uint32_t exe_len, grub_uint8_t *exe_data, int windatalen) +{ + int pe64 = 0; + char file[256]; + grub_uint32_t jump_len = 0; + grub_uint32_t jump_align = 0; + grub_uint8_t *jump_data = NULL; + + pe64 = ventoy_is_pe64(exe_data); + + grub_snprintf(file, sizeof(file), "%s/vtoyjump%d.exe", grub_env_get("vtoy_path"), pe64 ? 64 : 32); + ventoy_load_jump_exe(file, &jump_data, &jump_len, NULL); + jump_align = ventoy_align(jump_len, 16); + + wim_data->jump_exe_len = jump_len; + wim_data->bin_raw_len = jump_align + sizeof(ventoy_os_param) + windatalen + exe_len; + wim_data->bin_align_len = ventoy_align(wim_data->bin_raw_len, 2048); + + wim_data->jump_bin_data = grub_malloc(wim_data->bin_align_len); + if (wim_data->jump_bin_data) + { + grub_memcpy(wim_data->jump_bin_data, jump_data, jump_len); + grub_memcpy(wim_data->jump_bin_data + jump_align + sizeof(ventoy_os_param) + windatalen, exe_data, exe_len); + } + + debug("jump_exe_len:%u bin_raw_len:%u bin_align_len:%u\n", + wim_data->jump_exe_len, wim_data->bin_raw_len, wim_data->bin_align_len); + + return 0; +} + +static int ventoy_get_windows_rtdata_len(const char *iso, int *flag) +{ + int size = 0; + int template_file_len = 0; + char *pos = NULL; + char *script = NULL; + install_template *template_node = NULL; + + *flag = 0; + size = (int)sizeof(ventoy_windows_data); + + pos = grub_strstr(iso, "/"); + if (!pos) + { + return size; + } + + script = ventoy_plugin_get_cur_install_template(pos, &template_node); + if (script) + { + (*flag) |= WINDATA_FLAG_TEMPLATE; + template_file_len = template_node->filelen; + } + + return size + template_file_len; +} + +static int ventoy_fill_windows_rtdata(void *buf, char *isopath, int dataflag) +{ + int template_len = 0; + char *pos = NULL; + char *end = NULL; + char *script = NULL; + const char *env = NULL; + install_template *template_node = NULL; + ventoy_windows_data *data = (ventoy_windows_data *)buf; + + grub_memset(data, 0, sizeof(ventoy_windows_data)); + + env = grub_env_get("VTOY_WIN11_BYPASS_CHECK"); + if (env && env[0] == '1' && env[1] == 0) + { + data->windows11_bypass_check = 1; + } + + env = grub_env_get("VTOY_WIN11_BYPASS_NRO"); + if (env && env[0] == '1' && env[1] == 0) + { + data->windows11_bypass_nro = 1; + } + + pos = grub_strstr(isopath, "/"); + if (!pos) + { + return 1; + } + + if (dataflag & WINDATA_FLAG_TEMPLATE) + { + script = ventoy_plugin_get_cur_install_template(pos, &template_node); + if (script) + { + data->auto_install_len = template_len = template_node->filelen; + debug("auto install script OK <%s> \n", script, template_len); + end = ventoy_str_last(script, '/'); + grub_snprintf(data->auto_install_script, sizeof(data->auto_install_script) - 1, "%s", end ? end + 1 : script); + grub_memcpy(data + 1, template_node->filebuf, template_len); + } + } + else + { + debug("auto install script skipped or not configed %s\n", pos); + } + + script = (char *)ventoy_plugin_get_injection(pos); + if (script) + { + if (ventoy_check_file_exist("%s%s", ventoy_get_env("vtoy_iso_part"), script)) + { + debug("injection archive <%s> OK\n", script); + grub_snprintf(data->injection_archive, sizeof(data->injection_archive) - 1, "%s", script); + } + else + { + debug("injection archive <%s> NOT exist\n", script); + } + } + else + { + debug("injection archive not configed %s\n", pos); + } + + return 0; +} + +static int ventoy_update_before_chain(ventoy_os_param *param, char *isopath) +{ + grub_uint32_t jump_align = 0; + wim_lookup_entry *meta_look = NULL; + wim_security_header *security = NULL; + wim_directory_entry *rootdir = NULL; + wim_header *head = NULL; + wim_lookup_entry *lookup = NULL; + wim_patch *node = NULL; + wim_tail *wim_data = NULL; + + for (node = g_wim_patch_head; node; node = node->next) + { + if (0 == node->valid) + { + continue; + } + + wim_data = &node->wim_data; + head = &wim_data->wim_header; + lookup = (wim_lookup_entry *)wim_data->new_lookup_data; + + jump_align = ventoy_align(wim_data->jump_exe_len, 16); + if (wim_data->jump_bin_data) + { + grub_memcpy(wim_data->jump_bin_data + jump_align, param, sizeof(ventoy_os_param)); + ventoy_fill_windows_rtdata(wim_data->jump_bin_data + jump_align + sizeof(ventoy_os_param), isopath, wim_data->windata_flag); + } + + grub_crypto_hash(GRUB_MD_SHA1, wim_data->bin_hash.sha1, wim_data->jump_bin_data, wim_data->bin_raw_len); + + security = (wim_security_header *)wim_data->new_meta_data; + if (security->len > 0) + { + rootdir = (wim_directory_entry *)(wim_data->new_meta_data + ((security->len + 7) & 0xFFFFFFF8U)); + } + else + { + rootdir = (wim_directory_entry *)(wim_data->new_meta_data + 8); + } + + /* update all winpeshl.exe dirent entry's hash */ + ventoy_update_all_hash(node, wim_data->new_meta_data, rootdir); + + /* update winpeshl.exe lookup entry data (hash/offset/length) */ + if (node->replace_look) + { + debug("update replace lookup entry_id:%ld\n", ((long)node->replace_look - (long)lookup) / sizeof(wim_lookup_entry)); + node->replace_look->resource.raw_size = wim_data->bin_raw_len; + node->replace_look->resource.size_in_wim = wim_data->bin_raw_len; + node->replace_look->resource.flags = 0; + node->replace_look->resource.offset = wim_data->wim_align_size; + + grub_memcpy(node->replace_look->hash.sha1, wim_data->bin_hash.sha1, sizeof(wim_hash)); + } + + /* update metadata's hash */ + meta_look = ventoy_find_meta_entry(head, lookup); + if (meta_look) + { + debug("find meta lookup entry_id:%ld\n", ((long)meta_look - (long)lookup) / sizeof(wim_lookup_entry)); + grub_memcpy(&meta_look->resource, &head->metadata, sizeof(wim_resource_header)); + grub_crypto_hash(GRUB_MD_SHA1, meta_look->hash.sha1, wim_data->new_meta_data, wim_data->new_meta_len); + } + } + + return 0; +} + +static int ventoy_wimdows_locate_wim(const char *disk, wim_patch *patch, int windatalen) +{ + int rc; + grub_uint16_t i; + grub_file_t file; + grub_uint32_t exe_len; + grub_uint8_t *exe_data = NULL; + grub_uint8_t *decompress_data = NULL; + wim_lookup_entry *lookup = NULL; + wim_security_header *security = NULL; + wim_directory_entry *rootdir = NULL; + wim_directory_entry *search = NULL; + wim_stream_entry *stream = NULL; + wim_header *head = &(patch->wim_data.wim_header); + wim_tail *wim_data = &patch->wim_data; + + debug("windows locate wim start %s\n", patch->path); + + g_ventoy_case_insensitive = 1; + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", disk, patch->path); + g_ventoy_case_insensitive = 0; + + if (!file) + { + debug("File %s%s NOT exist\n", disk, patch->path); + return 1; + } + + ventoy_get_override_info(file, &patch->wim_data); + + grub_file_seek(file, 0); + grub_file_read(file, head, sizeof(wim_header)); + + if (grub_memcmp(head->signature, WIM_HEAD_SIGNATURE, sizeof(head->signature))) + { + debug("Not a valid wim file %s\n", (char *)head->signature); + grub_file_close(file); + return 1; + } + + if (head->flags & FLAG_HEADER_COMPRESS_LZMS) + { + debug("LZMS compress is not supported 0x%x\n", head->flags); + grub_file_close(file); + return 1; + } + + rc = ventoy_read_resource(file, head, &head->metadata, (void **)&decompress_data); + if (rc) + { + grub_printf("failed to read meta data %d\n", rc); + grub_file_close(file); + return 1; + } + + security = (wim_security_header *)decompress_data; + if (security->len > 0) + { + rootdir = (wim_directory_entry *)(decompress_data + ((security->len + 7) & 0xFFFFFFF8U)); + } + else + { + rootdir = (wim_directory_entry *)(decompress_data + 8); + } + + + debug("read lookup offset:%llu size:%llu\n", (ulonglong)head->lookup.offset, (ulonglong)head->lookup.raw_size); + lookup = grub_malloc(head->lookup.raw_size); + grub_file_seek(file, head->lookup.offset); + grub_file_read(file, lookup, head->lookup.raw_size); + + + + /* search winpeshl.exe dirent entry */ + search = search_replace_wim_dirent(file, head, lookup, decompress_data, rootdir); + if (!search) + { + debug("Failed to find replace file %p\n", search); + grub_file_close(file); + return 1; + } + + debug("find replace file at %p\n", search); + + grub_memset(&patch->old_hash, 0, sizeof(wim_hash)); + if (grub_memcmp(&patch->old_hash, search->hash.sha1, sizeof(wim_hash)) == 0) + { + debug("search hash all 0, now do deep search\n"); + stream = (wim_stream_entry *)((char *)search + search->len); + for (i = 0; i < search->streams; i++) + { + if (stream->name_len == 0) + { + grub_memcpy(&patch->old_hash, stream->hash.sha1, sizeof(wim_hash)); + debug("new search hash: %02x %02x %02x %02x %02x %02x %02x %02x\n", + ventoy_varg_8(patch->old_hash.sha1)); + break; + } + stream = (wim_stream_entry *)((char *)stream + stream->len); + } + } + else + { + grub_memcpy(&patch->old_hash, search->hash.sha1, sizeof(wim_hash)); + } + + + /* find and extact winpeshl.exe */ + patch->replace_look = ventoy_find_look_entry(head, lookup, &patch->old_hash); + if (patch->replace_look) + { + exe_len = (grub_uint32_t)patch->replace_look->resource.raw_size; + debug("find replace lookup entry_id:%ld raw_size:%u\n", + ((long)patch->replace_look - (long)lookup) / sizeof(wim_lookup_entry), exe_len); + + if (0 == ventoy_read_resource(file, head, &(patch->replace_look->resource), (void **)&(exe_data))) + { + ventoy_cat_exe_file_data(wim_data, exe_len, exe_data, windatalen); + grub_free(exe_data); + } + else + { + debug("failed to read replace file meta data %u\n", exe_len); + } + } + else + { + debug("failed to find lookup entry for replace file %02x %02x %02x %02x\n", + ventoy_varg_4(patch->old_hash.sha1)); + } + + wim_data->wim_raw_size = (grub_uint32_t)file->size; + wim_data->wim_align_size = ventoy_align(wim_data->wim_raw_size, 2048); + + grub_check_free(wim_data->new_meta_data); + wim_data->new_meta_data = decompress_data; + wim_data->new_meta_len = head->metadata.raw_size; + wim_data->new_meta_align_len = ventoy_align(wim_data->new_meta_len, 2048); + + grub_check_free(wim_data->new_lookup_data); + wim_data->new_lookup_data = (grub_uint8_t *)lookup; + wim_data->new_lookup_len = (grub_uint32_t)head->lookup.raw_size; + wim_data->new_lookup_align_len = ventoy_align(wim_data->new_lookup_len, 2048); + + head->metadata.flags = RESHDR_FLAG_METADATA; + head->metadata.offset = wim_data->wim_align_size + wim_data->bin_align_len; + head->metadata.size_in_wim = wim_data->new_meta_len; + head->metadata.raw_size = wim_data->new_meta_len; + + head->lookup.flags = 0; + head->lookup.offset = head->metadata.offset + wim_data->new_meta_align_len; + head->lookup.size_in_wim = wim_data->new_lookup_len; + head->lookup.raw_size = wim_data->new_lookup_len; + + grub_file_close(file); + + debug("%s", "windows locate wim finish\n"); + return 0; +} + +grub_err_t ventoy_cmd_sel_winpe_wim(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i = 0; + int pos = 0; + int len = 0; + int find = 0; + char *cmd = NULL; + wim_patch *node = NULL; + wim_patch *tmp = NULL; + grub_file_t file = NULL; + wim_header *head = NULL; + char cfgfile[128]; + + (void)ctxt; + (void)argc; + + len = 8 * VTOY_SIZE_1KB; + cmd = (char *)grub_malloc(len + sizeof(wim_header)); + if (!cmd) + { + return 1; + } + + head = (wim_header *)(cmd + len); + grub_env_unset("vtoy_pe_wim_path"); + + for (node = g_wim_patch_head; node; node = node->next) + { + find = 0; + for (tmp = g_wim_patch_head; tmp != node; tmp = tmp->next) + { + if (tmp->valid && grub_strcasecmp(tmp->path, node->path) == 0) + { + find = 1; + break; + } + } + + if (find) + { + continue; + } + + g_ventoy_case_insensitive = 1; + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], node->path); + g_ventoy_case_insensitive = 0; + if (!file) + { + debug("File %s%s NOT exist\n", args[0], node->path); + continue; + } + + grub_file_read(file, head, sizeof(wim_header)); + if (grub_memcmp(head->signature, WIM_HEAD_SIGNATURE, sizeof(head->signature))) + { + debug("Not a valid wim file %s\n", (char *)head->signature); + grub_file_close(file); + continue; + } + + if (head->flags & FLAG_HEADER_COMPRESS_LZMS) + { + debug("LZMS compress is not supported 0x%x\n", head->flags); + grub_file_close(file); + continue; + } + + grub_file_close(file); + node->valid = 1; + + vtoy_len_ssprintf(cmd, pos, len, "menuentry \"%s\" --class=\"sel_wim\" {\n echo \"\"\n}\n", node->path); + } + + if (pos > 0) + { + g_ventoy_menu_esc = 1; + g_ventoy_suppress_esc = 1; + g_ventoy_suppress_esc_default = 0; + g_ventoy_secondary_menu_on = 1; + + grub_snprintf(cfgfile, sizeof(cfgfile), "configfile mem:0x%llx:size:%d", (ulonglong)(ulong)cmd, pos); + grub_script_execute_sourcecode(cfgfile); + + g_ventoy_menu_esc = 0; + g_ventoy_suppress_esc = 0; + g_ventoy_suppress_esc_default = 1; + g_ventoy_secondary_menu_on = 0; + + for (node = g_wim_patch_head; node; node = node->next) + { + if (node->valid) + { + if (i == g_ventoy_last_entry) + { + grub_env_set("vtoy_pe_wim_path", node->path); + break; + } + i++; + } + } + } + + grub_free(cmd); + return 0; +} + +grub_err_t ventoy_cmd_locate_wim_patch(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int datalen = 0; + int dataflag = 0; + wim_patch *node = g_wim_patch_head; + + (void)ctxt; + (void)argc; + (void)args; + + datalen = ventoy_get_windows_rtdata_len(args[1], &dataflag); + + while (node) + { + node->wim_data.windata_flag = dataflag; + if (0 == ventoy_wimdows_locate_wim(args[0], node, datalen)) + { + node->valid = 1; + g_wim_valid_patch_count++; + } + + node = node->next; + } + + return 0; +} + +static grub_uint32_t ventoy_get_override_chunk_num(void) +{ + grub_uint32_t chunk_num = 0; + + if (g_iso_fs_type == 0) + { + /* ISO9660: */ + /* per wim */ + /* 1: file_size and file_offset */ + /* 2: new wim file header */ + chunk_num = g_wim_valid_patch_count * 2; + } + else + { + /* UDF: */ + /* global: */ + /* 1: block count in Partition Descriptor */ + + /* per wim */ + /* 1: file_size in file_entry or extend_file_entry */ + /* 2: data_size and position in extend data short ad */ + /* 3: new wim file header */ + chunk_num = g_wim_valid_patch_count * 3 + 1; + } + + if (g_suppress_wincd_override_offset > 0) + { + chunk_num++; + } + + return chunk_num; +} + +static void ventoy_fill_suppress_wincd_override_data(void *override) +{ + ventoy_override_chunk *cur = (ventoy_override_chunk *)override; + + cur->override_size = 4; + cur->img_offset = g_suppress_wincd_override_offset; + grub_memcpy(cur->override_data, &g_suppress_wincd_override_data, cur->override_size); +} + +static void ventoy_windows_fill_override_data_iso9660( grub_uint64_t isosize, void *override) +{ + grub_uint64_t sector; + grub_uint32_t new_wim_size; + ventoy_override_chunk *cur; + wim_patch *node = NULL; + wim_tail *wim_data = NULL; + ventoy_iso9660_override *dirent = NULL; + + sector = (isosize + 2047) / 2048; + + cur = (ventoy_override_chunk *)override; + + if (g_suppress_wincd_override_offset > 0) + { + ventoy_fill_suppress_wincd_override_data(cur); + cur++; + } + + debug("ventoy_windows_fill_override_data_iso9660 %lu\n", (ulong)isosize); + + for (node = g_wim_patch_head; node; node = node->next) + { + wim_data = &node->wim_data; + if (0 == node->valid) + { + continue; + } + + new_wim_size = wim_data->wim_align_size + wim_data->bin_align_len + + wim_data->new_meta_align_len + wim_data->new_lookup_align_len; + + dirent = (ventoy_iso9660_override *)wim_data->override_data; + + dirent->first_sector = (grub_uint32_t)sector; + dirent->size = new_wim_size; + dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector); + dirent->size_be = grub_swap_bytes32(dirent->size); + + sector += (new_wim_size / 2048); + + /* override 1: position and length in dirent */ + cur->img_offset = wim_data->override_offset; + cur->override_size = wim_data->override_len; + grub_memcpy(cur->override_data, wim_data->override_data, cur->override_size); + cur++; + + /* override 2: new wim file header */ + cur->img_offset = wim_data->file_offset; + cur->override_size = sizeof(wim_header); + grub_memcpy(cur->override_data, &(wim_data->wim_header), cur->override_size); + cur++; + } + + return; +} + +static int ventoy_windows_fill_udf_short_ad(grub_file_t isofile, grub_uint32_t curpos, + wim_tail *wim_data, grub_uint32_t new_wim_size) +{ + int i; + grub_uint32_t total = 0; + grub_uint32_t left_size = 0; + ventoy_udf_override *udf = NULL; + ventoy_udf_override tmp[4]; + + grub_memset(tmp, 0, sizeof(tmp)); + grub_file_seek(isofile, wim_data->override_offset); + grub_file_read(isofile, tmp, sizeof(tmp)); + + left_size = new_wim_size; + udf = (ventoy_udf_override *)wim_data->override_data; + + for (i = 0; i < 4; i++) + { + total += tmp[i].length; + if (total >= wim_data->wim_raw_size) + { + udf->length = left_size; + udf->position = curpos; + return 0; + } + else + { + udf->length = tmp[i].length; + udf->position = curpos; + } + + left_size -= tmp[i].length; + curpos += udf->length / 2048; + udf++; + wim_data->override_len += sizeof(ventoy_udf_override); + } + + debug("######## Too many udf ad ######\n"); + return 1; +} + +static void ventoy_windows_fill_override_data_udf(grub_file_t isofile, void *override) +{ + grub_uint32_t data32; + grub_uint64_t data64; + grub_uint64_t sector; + grub_uint32_t new_wim_size; + grub_uint64_t total_wim_size = 0; + grub_uint32_t udf_start_block = 0; + ventoy_override_chunk *cur; + wim_patch *node = NULL; + wim_tail *wim_data = NULL; + + sector = (isofile->size + 2047) / 2048; + + cur = (ventoy_override_chunk *)override; + + if (g_suppress_wincd_override_offset > 0) + { + ventoy_fill_suppress_wincd_override_data(cur); + cur++; + } + + debug("ventoy_windows_fill_override_data_udf %lu\n", (ulong)isofile->size); + + for (node = g_wim_patch_head; node; node = node->next) + { + wim_data = &node->wim_data; + if (node->valid) + { + if (udf_start_block == 0) + { + udf_start_block = wim_data->udf_start_block; + } + new_wim_size = wim_data->wim_align_size + wim_data->bin_align_len + + wim_data->new_meta_align_len + wim_data->new_lookup_align_len; + total_wim_size += new_wim_size; + } + } + + //override 1: sector number in pd data + cur->img_offset = grub_udf_get_last_pd_size_offset(); + cur->override_size = 4; + data32 = sector - udf_start_block + (total_wim_size / 2048); + grub_memcpy(cur->override_data, &(data32), 4); + + for (node = g_wim_patch_head; node; node = node->next) + { + wim_data = &node->wim_data; + if (0 == node->valid) + { + continue; + } + + new_wim_size = wim_data->wim_align_size + wim_data->bin_align_len + + wim_data->new_meta_align_len + wim_data->new_lookup_align_len; + + //override 2: filesize in file_entry + cur++; + cur->img_offset = wim_data->fe_entry_size_offset; + cur->override_size = 8; + data64 = new_wim_size; + grub_memcpy(cur->override_data, &(data64), 8); + + /* override 3: position and length in extend data */ + ventoy_windows_fill_udf_short_ad(isofile, (grub_uint32_t)sector - udf_start_block, wim_data, new_wim_size); + + sector += (new_wim_size / 2048); + + cur++; + cur->img_offset = wim_data->override_offset; + cur->override_size = wim_data->override_len; + grub_memcpy(cur->override_data, wim_data->override_data, cur->override_size); + + /* override 4: new wim file header */ + cur++; + cur->img_offset = wim_data->file_offset; + cur->override_size = sizeof(wim_header); + grub_memcpy(cur->override_data, &(wim_data->wim_header), cur->override_size); + } + + return; +} + +static grub_uint32_t ventoy_windows_get_virt_data_size(void) +{ + grub_uint32_t size = 0; + wim_tail *wim_data = NULL; + wim_patch *node = g_wim_patch_head; + + while (node) + { + if (node->valid) + { + wim_data = &node->wim_data; + size += sizeof(ventoy_virt_chunk) + wim_data->bin_align_len + + wim_data->new_meta_align_len + wim_data->new_lookup_align_len; + } + node = node->next; + } + + return size; +} + +static void ventoy_windows_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain) +{ + grub_uint64_t sector; + grub_uint32_t offset; + grub_uint32_t wim_secs; + grub_uint32_t mem_secs; + char *override = NULL; + ventoy_virt_chunk *cur = NULL; + wim_tail *wim_data = NULL; + wim_patch *node = NULL; + + sector = (isosize + 2047) / 2048; + offset = sizeof(ventoy_virt_chunk) * g_wim_valid_patch_count; + + override = (char *)chain + chain->virt_chunk_offset; + cur = (ventoy_virt_chunk *)override; + + for (node = g_wim_patch_head; node; node = node->next) + { + if (0 == node->valid) + { + continue; + } + + wim_data = &node->wim_data; + + wim_secs = wim_data->wim_align_size / 2048; + mem_secs = (wim_data->bin_align_len + wim_data->new_meta_align_len + wim_data->new_lookup_align_len) / 2048; + + cur->remap_sector_start = sector; + cur->remap_sector_end = cur->remap_sector_start + wim_secs; + cur->org_sector_start = (grub_uint32_t)(wim_data->file_offset / 2048); + + cur->mem_sector_start = cur->remap_sector_end; + cur->mem_sector_end = cur->mem_sector_start + mem_secs; + cur->mem_sector_offset = offset; + + sector += wim_secs + mem_secs; + cur++; + + grub_memcpy(override + offset, wim_data->jump_bin_data, wim_data->bin_raw_len); + offset += wim_data->bin_align_len; + + grub_memcpy(override + offset, wim_data->new_meta_data, wim_data->new_meta_len); + offset += wim_data->new_meta_align_len; + + grub_memcpy(override + offset, wim_data->new_lookup_data, wim_data->new_lookup_len); + offset += wim_data->new_lookup_align_len; + + chain->virt_img_size_in_bytes += wim_data->wim_align_size + + wim_data->bin_align_len + + wim_data->new_meta_align_len + + wim_data->new_lookup_align_len; + } + + return; +} + +static int ventoy_windows_drive_map(ventoy_chain_head *chain, int vlnk) +{ + int hd1 = 0; + grub_disk_t disk; + + debug("drive map begin <%p> <%d> ...\n", chain, vlnk); + + disk = grub_disk_open("hd1"); + if (disk) + { + grub_disk_close(disk); + hd1 = 1; + debug("BIOS hd1 exist\n"); + } + else + { + debug("failed to open disk %s\n", "hd1"); + } + + if (vlnk) + { + if (g_ventoy_disk_bios_id == 0x80 && hd1) + { + debug("drive map needed vlnk %p\n", disk); + chain->drive_map = 0x81; + } + } + else if (chain->disk_drive == 0x80) + { + if (hd1) + { + debug("drive map needed normal %p\n", disk); + chain->drive_map = 0x81; + } + } + else + { + debug("no need to map 0x%x\n", chain->disk_drive); + } + + return 0; +} + +static int ventoy_suppress_windows_cd_prompt(void) +{ + int rc = 1; + const char *cdprompt = NULL; + grub_uint64_t readpos = 0; + grub_file_t file = NULL; + grub_uint8_t data[32]; + + cdprompt = ventoy_get_env("VTOY_WINDOWS_CD_PROMPT"); + if (cdprompt && cdprompt[0] == '1' && cdprompt[1] == 0) + { + debug("VTOY_WINDOWS_CD_PROMPT:<%s>\n", cdprompt); + return 0; + } + + g_ventoy_case_insensitive = 1; + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s/boot/bootfix.bin", "(loop)"); + g_ventoy_case_insensitive = 0; + + if (!file) + { + debug("Failed to open %s\n", "bootfix.bin"); + goto end; + } + + grub_file_read(file, data, 32); + + if (file->fs && file->fs->name && grub_strcmp(file->fs->name, "udf") == 0) + { + readpos = grub_udf_get_file_offset(file); + } + else + { + readpos = grub_iso9660_get_last_read_pos(file); + } + + debug("bootfix.bin readpos:%lu (sector:%lu) data: %02x %02x %02x %02x\n", + (ulong)readpos, (ulong)readpos / 2048, data[24], data[25], data[26], data[27]); + + if (*(grub_uint32_t *)(data + 24) == 0x13cd0080) + { + g_suppress_wincd_override_offset = readpos + 24; + g_suppress_wincd_override_data = 0x13cd00fd; + + rc = 0; + } + + debug("g_suppress_wincd_override_offset:%lu\n", (ulong)g_suppress_wincd_override_offset); + +end: + check_free(file, grub_file_close); + + return rc; +} + +static int ventoy_extract_init_exe(char *wimfile, grub_uint8_t **pexe_data, grub_uint32_t *pexe_len, char *exe_name) +{ + int rc; + int ret = 1; + grub_uint16_t i; + grub_file_t file = NULL; + grub_uint32_t exe_len = 0; + wim_header *head = NULL; + grub_uint16_t *uname = NULL; + grub_uint8_t *exe_data = NULL; + grub_uint8_t *decompress_data = NULL; + wim_lookup_entry *lookup = NULL; + wim_security_header *security = NULL; + wim_directory_entry *rootdir = NULL; + wim_directory_entry *search = NULL; + wim_stream_entry *stream = NULL; + wim_lookup_entry *replace_look = NULL; + wim_header wimhdr; + wim_hash hashdata; + + head = &wimhdr; + + file = grub_file_open(wimfile, VENTOY_FILE_TYPE); + if (!file) + { + goto out; + } + + grub_file_read(file, head, sizeof(wim_header)); + rc = ventoy_read_resource(file, head, &head->metadata, (void **)&decompress_data); + if (rc) + { + grub_printf("failed to read meta data %d\n", rc); + goto out; + } + + security = (wim_security_header *)decompress_data; + if (security->len > 0) + { + rootdir = (wim_directory_entry *)(decompress_data + ((security->len + 7) & 0xFFFFFFF8U)); + } + else + { + rootdir = (wim_directory_entry *)(decompress_data + 8); + } + + debug("read lookup offset:%llu size:%llu\n", (ulonglong)head->lookup.offset, (ulonglong)head->lookup.raw_size); + lookup = grub_malloc(head->lookup.raw_size); + grub_file_seek(file, head->lookup.offset); + grub_file_read(file, lookup, head->lookup.raw_size); + + /* search winpeshl.exe dirent entry */ + search = search_replace_wim_dirent(file, head, lookup, decompress_data, rootdir); + if (!search) + { + debug("Failed to find replace file %p\n", search); + goto out; + } + + uname = (grub_uint16_t *)(search + 1); + for (i = 0; i < search->name_len / 2 && i < 200; i++) + { + exe_name[i] = (char)uname[i]; + } + exe_name[i] = 0; + debug("find replace file at %p <%s>\n", search, exe_name); + + grub_memset(&hashdata, 0, sizeof(wim_hash)); + if (grub_memcmp(&hashdata, search->hash.sha1, sizeof(wim_hash)) == 0) + { + debug("search hash all 0, now do deep search\n"); + stream = (wim_stream_entry *)((char *)search + search->len); + for (i = 0; i < search->streams; i++) + { + if (stream->name_len == 0) + { + grub_memcpy(&hashdata, stream->hash.sha1, sizeof(wim_hash)); + debug("new search hash: %02x %02x %02x %02x %02x %02x %02x %02x\n", + ventoy_varg_8(hashdata.sha1)); + break; + } + stream = (wim_stream_entry *)((char *)stream + stream->len); + } + } + else + { + grub_memcpy(&hashdata, search->hash.sha1, sizeof(wim_hash)); + } + + /* find and extact winpeshl.exe */ + replace_look = ventoy_find_look_entry(head, lookup, &hashdata); + if (replace_look) + { + exe_len = (grub_uint32_t)replace_look->resource.raw_size; + debug("find replace lookup entry_id:%ld raw_size:%u\n", + ((long)replace_look - (long)lookup) / sizeof(wim_lookup_entry), exe_len); + + if (0 != ventoy_read_resource(file, head, &(replace_look->resource), (void **)&(exe_data))) + { + exe_len = 0; + exe_data = NULL; + debug("failed to read replace file meta data %u\n", exe_len); + } + } + else + { + debug("failed to find lookup entry for replace file %02x %02x %02x %02x\n", + ventoy_varg_4(hashdata.sha1)); + } + + if (exe_data) + { + ret = 0; + *pexe_data = exe_data; + *pexe_len = exe_len; + } + +out: + + grub_check_free(lookup); + grub_check_free(decompress_data); + check_free(file, grub_file_close); + + return ret; +} + +grub_err_t ventoy_cmd_windows_wimboot_data(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int rc = 0; + int wim64 = 0; + int datalen = 0; + int dataflag = 0; + grub_uint32_t exe_len = 0; + grub_uint32_t jump_align = 0; + const char *addr = NULL; + ventoy_chain_head *chain = NULL; + grub_uint8_t *param = NULL; + grub_uint8_t *exe_data = NULL; + ventoy_windows_data *rtdata = NULL; + char exename[128] = {0}; + wim_tail wim_data; + + (void)ctxt; + (void)argc; + + addr = grub_env_get("vtoy_chain_mem_addr"); + if (!addr) + { + debug("Failed to find vtoy_chain_mem_addr\n"); + return 1; + } + + chain = (ventoy_chain_head *)(void *)grub_strtoul(addr, NULL, 16); + + if (grub_memcmp(&g_ventoy_guid, &chain->os_param.guid, 16) != 0) + { + debug("os_param.guid not match\n"); + return 1; + } + + datalen = ventoy_get_windows_rtdata_len(chain->os_param.vtoy_img_path, &dataflag); + + rc = ventoy_extract_init_exe(args[0], &exe_data, &exe_len, exename); + if (rc) + { + return 1; + } + wim64 = ventoy_is_pe64(exe_data); + + grub_memset(&wim_data, 0, sizeof(wim_data)); + ventoy_cat_exe_file_data(&wim_data, exe_len, exe_data, datalen); + grub_check_free(exe_data); + + jump_align = ventoy_align(wim_data.jump_exe_len, 16); + param = wim_data.jump_bin_data; + + grub_memcpy(param + jump_align, &chain->os_param, sizeof(ventoy_os_param)); + + rtdata = (ventoy_windows_data *)(param + jump_align + sizeof(ventoy_os_param)); + ventoy_fill_windows_rtdata(rtdata, chain->os_param.vtoy_img_path, dataflag); + + ventoy_memfile_env_set("vtoy_wimboot_mem", param, (ulonglong)(wim_data.bin_align_len)); + + grub_env_set(args[1], exename); + grub_env_set(args[2], wim64 ? "64" : "32"); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_windows_chain_data(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int unknown_image = 0; + int ventoy_compatible = 0; + grub_uint32_t size = 0; + grub_uint64_t isosize = 0; + grub_uint32_t boot_catlog = 0; + grub_uint32_t img_chunk_size = 0; + grub_uint32_t override_size = 0; + grub_uint32_t virt_chunk_size = 0; + grub_file_t file; + grub_disk_t disk; + const char *pLastChain = NULL; + const char *compatible; + ventoy_chain_head *chain; + + (void)ctxt; + (void)argc; + + debug("chain data begin <%s> ...\n", args[0]); + + compatible = grub_env_get("ventoy_compatible"); + if (compatible && compatible[0] == 'Y') + { + ventoy_compatible = 1; + } + + if (NULL == g_img_chunk_list.chunk) + { + grub_printf("ventoy not ready\n"); + return 1; + } + + if (0 == ventoy_compatible && g_wim_valid_patch_count == 0) + { + unknown_image = 1; + if (!g_ventoy_wimboot_mode) + { + debug("Warning: %s was not recognized by Ventoy\n", args[0]); + } + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + return 1; + } + + isosize = file->size; + + boot_catlog = ventoy_get_iso_boot_catlog(file); + if (boot_catlog) + { + if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog))) + { + grub_env_set("LoadIsoEfiDriver", "on"); + } + } + else + { + if (ventoy_is_efi_os()) + { + grub_env_set("LoadIsoEfiDriver", "on"); + } + else + { + return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]); + } + } + + g_suppress_wincd_override_offset = 0; + if (!ventoy_is_efi_os()) /* legacy mode */ + { + ventoy_suppress_windows_cd_prompt(); + } + + img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk); + + if (ventoy_compatible || unknown_image) + { + override_size = g_suppress_wincd_override_offset > 0 ? sizeof(ventoy_override_chunk) : 0; + size = sizeof(ventoy_chain_head) + img_chunk_size + override_size; + } + else + { + override_size = ventoy_get_override_chunk_num() * sizeof(ventoy_override_chunk); + virt_chunk_size = ventoy_windows_get_virt_data_size(); + size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size; + } + + pLastChain = grub_env_get("vtoy_chain_mem_addr"); + if (pLastChain) + { + chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16); + if (chain) + { + debug("free last chain memory %p\n", chain); + grub_free(chain); + } + } + + chain = ventoy_alloc_chain(size); + if (!chain) + { + grub_printf("Failed to alloc chain win1 memory size %u\n", size); + grub_file_close(file); + return 1; + } + + ventoy_memfile_env_set("vtoy_chain_mem", chain, (ulonglong)size); + + grub_memset(chain, 0, sizeof(ventoy_chain_head)); + + /* part 1: os parameter */ + g_ventoy_chain_type = ventoy_chain_windows; + ventoy_fill_os_param(file, &(chain->os_param)); + + if (0 == unknown_image) + { + ventoy_update_before_chain(&(chain->os_param), args[0]); + } + + /* part 2: chain head */ + disk = file->device->disk; + chain->disk_drive = disk->id; + chain->disk_sector_size = (1 << disk->log_sector_size); + chain->real_img_size_in_bytes = file->size; + chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048; + chain->boot_catalog = boot_catlog; + + if (!ventoy_is_efi_os()) + { + grub_file_seek(file, boot_catlog * 2048); + grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector)); + } + + /* part 3: image chunk */ + chain->img_chunk_offset = sizeof(ventoy_chain_head); + chain->img_chunk_num = g_img_chunk_list.cur_chunk; + grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size); + + if (ventoy_compatible || unknown_image) + { + if (g_suppress_wincd_override_offset > 0) + { + chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size; + chain->override_chunk_num = 1; + ventoy_fill_suppress_wincd_override_data((char *)chain + chain->override_chunk_offset); + } + + return 0; + } + + if (0 == g_wim_valid_patch_count) + { + return 0; + } + + /* part 4: override chunk */ + chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size; + chain->override_chunk_num = ventoy_get_override_chunk_num(); + + if (g_iso_fs_type == 0) + { + ventoy_windows_fill_override_data_iso9660(isosize, (char *)chain + chain->override_chunk_offset); + } + else + { + ventoy_windows_fill_override_data_udf(file, (char *)chain + chain->override_chunk_offset); + } + + /* part 5: virt chunk */ + chain->virt_chunk_offset = chain->override_chunk_offset + override_size; + chain->virt_chunk_num = g_wim_valid_patch_count; + ventoy_windows_fill_virt_data(isosize, chain); + + if (ventoy_is_efi_os() == 0) + { + ventoy_windows_drive_map(chain, file->vlnk); + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_uint32_t ventoy_get_wim_iso_offset(const char *filepath) +{ + grub_uint32_t imgoffset; + grub_file_t file; + char cmdbuf[128]; + + grub_snprintf(cmdbuf, sizeof(cmdbuf), "loopback wimiso \"%s\"", filepath); + grub_script_execute_sourcecode(cmdbuf); + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", "(wimiso)/boot/boot.wim"); + if (!file) + { + grub_printf("Failed to open boot.wim file in the image file\n"); + return 0; + } + + imgoffset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file) + 2; + + debug("wimiso wim direct offset: %u\n", imgoffset); + + grub_file_close(file); + + grub_script_execute_sourcecode("loopback -d wimiso"); + + return imgoffset; +} + +static int ventoy_get_wim_chunklist(grub_file_t wimfile, ventoy_img_chunk_list *wimchunk) +{ + grub_memset(wimchunk, 0, sizeof(ventoy_img_chunk_list)); + wimchunk->chunk = grub_malloc(sizeof(ventoy_img_chunk) * DEFAULT_CHUNK_NUM); + if (NULL == wimchunk->chunk) + { + return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Can't allocate image chunk memoty\n"); + } + + wimchunk->max_chunk = DEFAULT_CHUNK_NUM; + wimchunk->cur_chunk = 0; + + ventoy_get_block_list(wimfile, wimchunk, wimfile->device->disk->partition->start); + + return 0; +} + +grub_err_t ventoy_cmd_is_standard_winiso(grub_extcmd_context_t ctxt, int argc, char **args) +{ + int i; + int ret = 1; + char prefix[32] = {0}; + const char *chkfile[] = + { + "boot/bcd", "boot/boot.sdi", NULL + }; + + (void)ctxt; + (void)argc; + + if (ventoy_check_file_exist("%s/sources/boot.wim", args[0])) + { + prefix[0] = 0; + } + else if (ventoy_check_file_exist("%s/x86/sources/boot.wim", args[0])) + { + grub_snprintf(prefix, sizeof(prefix), "/x86"); + } + else if (ventoy_check_file_exist("%s/x64/sources/boot.wim", args[0])) + { + grub_snprintf(prefix, sizeof(prefix), "/x64"); + } + else + { + debug("No boot.wim found.\n"); + goto out; + } + + for (i = 0; chkfile[i]; i++) + { + if (!ventoy_check_file_exist("%s%s/%s", args[0], prefix, chkfile[i])) + { + debug("%s not found.\n", chkfile[i]); + goto out; + } + } + + if ((!ventoy_check_file_exist("%s%s/sources/install.wim", args[0], prefix)) && + (!ventoy_check_file_exist("%s%s/sources/install.esd", args[0], prefix))) + { + debug("No install.wim(esd) found.\n"); + goto out; + } + + if (!ventoy_check_file_exist("%s/setup.exe", args[0])) + { + debug("No setup.exe found.\n"); + goto out; + } + + ret = 0; + debug("This is standard Windows ISO.\n"); + +out: + + return ret; +} + +grub_err_t ventoy_cmd_wim_check_bootable(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint32_t boot_index; + grub_file_t file = NULL; + wim_header *wimhdr = NULL; + + (void)ctxt; + (void)argc; + + wimhdr = grub_zalloc(sizeof(wim_header)); + if (!wimhdr) + { + return 1; + } + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]); + if (!file) + { + grub_free(wimhdr); + return 1; + } + + grub_file_read(file, wimhdr, sizeof(wim_header)); + grub_file_close(file); + boot_index = wimhdr->boot_index; + grub_free(wimhdr); + + if (boot_index == 0) + { + return 1; + } + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_vlnk_wim_chain_data(grub_file_t wimfile) +{ + grub_uint32_t i = 0; + grub_uint32_t imgoffset = 0; + grub_uint32_t size = 0; + grub_uint32_t isosector = 0; + grub_uint64_t wimsize = 0; + grub_uint32_t boot_catlog = 0; + grub_uint32_t img_chunk1_size = 0; + grub_uint32_t img_chunk2_size = 0; + grub_uint32_t override_size = 0; + grub_file_t file; + grub_disk_t disk; + const char *pLastChain = NULL; + ventoy_chain_head *chain; + ventoy_iso9660_override *dirent; + ventoy_img_chunk *chunknode; + ventoy_override_chunk *override; + ventoy_img_chunk_list wimchunk; + + debug("vlnk wim chain data begin <%s> ...\n", wimfile->name); + + if (NULL == g_wimiso_chunk_list.chunk || NULL == g_wimiso_path) + { + grub_printf("ventoy not ready\n"); + return 1; + } + + imgoffset = ventoy_get_wim_iso_offset(g_wimiso_path); + if (imgoffset == 0) + { + grub_printf("image offset not found\n"); + return 1; + } + + if (0 != ventoy_get_wim_chunklist(wimfile, &wimchunk)) + { + grub_printf("Failed to get wim chunklist\n"); + return 1; + } + wimsize = wimfile->size; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", g_wimiso_path); + if (!file) + { + return 1; + } + + boot_catlog = ventoy_get_iso_boot_catlog(file); + + img_chunk1_size = g_wimiso_chunk_list.cur_chunk * sizeof(ventoy_img_chunk); + img_chunk2_size = wimchunk.cur_chunk * sizeof(ventoy_img_chunk); + override_size = sizeof(ventoy_override_chunk) + g_wimiso_size; + + size = sizeof(ventoy_chain_head) + img_chunk1_size + img_chunk2_size + override_size; + + pLastChain = grub_env_get("vtoy_chain_mem_addr"); + if (pLastChain) + { + chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16); + if (chain) + { + debug("free last chain memory %p\n", chain); + grub_free(chain); + } + } + + chain = ventoy_alloc_chain(size); + if (!chain) + { + grub_printf("Failed to alloc chain win2 memory size %u\n", size); + grub_file_close(file); + return 1; + } + + ventoy_memfile_env_set("vtoy_chain_mem", chain, (ulonglong)size); + + grub_memset(chain, 0, sizeof(ventoy_chain_head)); + + /* part 1: os parameter */ + g_ventoy_chain_type = ventoy_chain_wim; + ventoy_fill_os_param(wimfile, &(chain->os_param)); + + /* part 2: chain head */ + disk = wimfile->device->disk; + chain->disk_drive = disk->id; + chain->disk_sector_size = (1 << disk->log_sector_size); + chain->real_img_size_in_bytes = ventoy_align_2k(file->size) + ventoy_align_2k(wimsize); + chain->virt_img_size_in_bytes = chain->real_img_size_in_bytes; + chain->boot_catalog = boot_catlog; + + if (!ventoy_is_efi_os()) + { + grub_file_seek(file, boot_catlog * 2048); + grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector)); + } + + /* part 3: image chunk */ + chain->img_chunk_offset = sizeof(ventoy_chain_head); + chain->img_chunk_num = g_wimiso_chunk_list.cur_chunk + wimchunk.cur_chunk; + grub_memcpy((char *)chain + chain->img_chunk_offset, g_wimiso_chunk_list.chunk, img_chunk1_size); + + chunknode = (ventoy_img_chunk *)((char *)chain + chain->img_chunk_offset); + for (i = 0; i < g_wimiso_chunk_list.cur_chunk; i++) + { + chunknode->disk_end_sector = chunknode->disk_end_sector - chunknode->disk_start_sector; + chunknode->disk_start_sector = 0; + chunknode++; + } + + /* fs cluster size >= 2048, so don't need to proc align */ + + /* align by 2048 */ + chunknode = wimchunk.chunk + wimchunk.cur_chunk - 1; + i = (chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) % 4; + if (i) + { + chunknode->disk_end_sector += 4 - i; + } + + isosector = (grub_uint32_t)((file->size + 2047) / 2048); + for (i = 0; i < wimchunk.cur_chunk; i++) + { + chunknode = wimchunk.chunk + i; + chunknode->img_start_sector = isosector; + chunknode->img_end_sector = chunknode->img_start_sector + + ((chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) / 4) - 1; + isosector = chunknode->img_end_sector + 1; + } + + grub_memcpy((char *)chain + chain->img_chunk_offset + img_chunk1_size, wimchunk.chunk, img_chunk2_size); + + /* part 4: override chunk */ + chain->override_chunk_offset = chain->img_chunk_offset + img_chunk1_size + img_chunk2_size; + chain->override_chunk_num = 1; + + override = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset); + override->img_offset = 0; + override->override_size = g_wimiso_size; + + grub_file_seek(file, 0); + grub_file_read(file, override->override_data, file->size); + + dirent = (ventoy_iso9660_override *)(override->override_data + imgoffset); + dirent->first_sector = (grub_uint32_t)((file->size + 2047) / 2048); + dirent->size = (grub_uint32_t)(wimsize); + dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector); + dirent->size_be = grub_swap_bytes32(dirent->size); + + debug("imgoffset=%u first_sector=0x%x size=0x%x\n", imgoffset, dirent->first_sector, dirent->size); + + if (ventoy_is_efi_os() == 0) + { + ventoy_windows_drive_map(chain, 0); + } + + grub_file_close(file); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +static grub_err_t ventoy_normal_wim_chain_data(grub_file_t wimfile) +{ + grub_uint32_t i = 0; + grub_uint32_t imgoffset = 0; + grub_uint32_t size = 0; + grub_uint32_t isosector = 0; + grub_uint64_t wimsize = 0; + grub_uint32_t boot_catlog = 0; + grub_uint32_t img_chunk1_size = 0; + grub_uint32_t img_chunk2_size = 0; + grub_uint32_t override_size = 0; + grub_file_t file; + grub_disk_t disk; + const char *pLastChain = NULL; + ventoy_chain_head *chain; + ventoy_iso9660_override *dirent; + ventoy_img_chunk *chunknode; + ventoy_override_chunk *override; + ventoy_img_chunk_list wimchunk; + + debug("normal wim chain data begin <%s> ...\n", wimfile->name); + + if (NULL == g_wimiso_chunk_list.chunk || NULL == g_wimiso_path) + { + grub_printf("ventoy not ready\n"); + return 1; + } + + imgoffset = ventoy_get_wim_iso_offset(g_wimiso_path); + if (imgoffset == 0) + { + grub_printf("image offset not found\n"); + return 1; + } + + if (0 != ventoy_get_wim_chunklist(wimfile, &wimchunk)) + { + grub_printf("Failed to get wim chunklist\n"); + return 1; + } + wimsize = wimfile->size; + + file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", g_wimiso_path); + if (!file) + { + return 1; + } + + boot_catlog = ventoy_get_iso_boot_catlog(file); + + img_chunk1_size = g_wimiso_chunk_list.cur_chunk * sizeof(ventoy_img_chunk); + img_chunk2_size = wimchunk.cur_chunk * sizeof(ventoy_img_chunk); + override_size = sizeof(ventoy_override_chunk); + + size = sizeof(ventoy_chain_head) + img_chunk1_size + img_chunk2_size + override_size; + + pLastChain = grub_env_get("vtoy_chain_mem_addr"); + if (pLastChain) + { + chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16); + if (chain) + { + debug("free last chain memory %p\n", chain); + grub_free(chain); + } + } + + chain = ventoy_alloc_chain(size); + if (!chain) + { + grub_printf("Failed to alloc chain win3 memory size %u\n", size); + grub_file_close(file); + return 1; + } + + ventoy_memfile_env_set("vtoy_chain_mem", chain, (ulonglong)size); + + grub_memset(chain, 0, sizeof(ventoy_chain_head)); + + /* part 1: os parameter */ + g_ventoy_chain_type = ventoy_chain_wim; + ventoy_fill_os_param(file, &(chain->os_param)); + + /* part 2: chain head */ + disk = file->device->disk; + chain->disk_drive = disk->id; + chain->disk_sector_size = (1 << disk->log_sector_size); + chain->real_img_size_in_bytes = ventoy_align_2k(file->size) + ventoy_align_2k(wimsize); + chain->virt_img_size_in_bytes = chain->real_img_size_in_bytes; + chain->boot_catalog = boot_catlog; + + if (!ventoy_is_efi_os()) + { + grub_file_seek(file, boot_catlog * 2048); + grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector)); + } + + /* part 3: image chunk */ + chain->img_chunk_offset = sizeof(ventoy_chain_head); + chain->img_chunk_num = g_wimiso_chunk_list.cur_chunk + wimchunk.cur_chunk; + grub_memcpy((char *)chain + chain->img_chunk_offset, g_wimiso_chunk_list.chunk, img_chunk1_size); + + /* fs cluster size >= 2048, so don't need to proc align */ + + /* align by 2048 */ + chunknode = wimchunk.chunk + wimchunk.cur_chunk - 1; + i = (chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) % 4; + if (i) + { + chunknode->disk_end_sector += 4 - i; + } + + isosector = (grub_uint32_t)((file->size + 2047) / 2048); + for (i = 0; i < wimchunk.cur_chunk; i++) + { + chunknode = wimchunk.chunk + i; + chunknode->img_start_sector = isosector; + chunknode->img_end_sector = chunknode->img_start_sector + + ((chunknode->disk_end_sector + 1 - chunknode->disk_start_sector) / 4) - 1; + isosector = chunknode->img_end_sector + 1; + } + + grub_memcpy((char *)chain + chain->img_chunk_offset + img_chunk1_size, wimchunk.chunk, img_chunk2_size); + + /* part 4: override chunk */ + chain->override_chunk_offset = chain->img_chunk_offset + img_chunk1_size + img_chunk2_size; + chain->override_chunk_num = 1; + + override = (ventoy_override_chunk *)((char *)chain + chain->override_chunk_offset); + override->img_offset = imgoffset; + override->override_size = sizeof(ventoy_iso9660_override); + + dirent = (ventoy_iso9660_override *)(override->override_data); + dirent->first_sector = (grub_uint32_t)((file->size + 2047) / 2048); + dirent->size = (grub_uint32_t)(wimsize); + dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector); + dirent->size_be = grub_swap_bytes32(dirent->size); + + debug("imgoffset=%u first_sector=0x%x size=0x%x\n", imgoffset, dirent->first_sector, dirent->size); + + if (ventoy_is_efi_os() == 0) + { + ventoy_windows_drive_map(chain, 0); + } + + grub_file_close(file); + + VENTOY_CMD_RETURN(GRUB_ERR_NONE); +} + +grub_err_t ventoy_cmd_wim_chain_data(grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_err_t ret; + grub_file_t wimfile; + + (void)ctxt; + (void)argc; + + wimfile = grub_file_open(args[0], VENTOY_FILE_TYPE); + if (!wimfile) + { + return 1; + } + + if (wimfile->vlnk) + { + ret = ventoy_vlnk_wim_chain_data(wimfile); + } + else + { + ret = ventoy_normal_wim_chain_data(wimfile); + } + + grub_file_close(wimfile); + return ret; +} + +int ventoy_chain_file_size(const char *path) +{ + int size; + grub_file_t file; + + file = grub_file_open(path, VENTOY_FILE_TYPE); + size = (int)(file->size); + + grub_file_close(file); + + return size; +} + +int ventoy_chain_file_read(const char *path, int offset, int len, void *buf) +{ + int size; + grub_file_t file; + + file = grub_file_open(path, VENTOY_FILE_TYPE); + grub_file_seek(file, offset); + size = grub_file_read(file, buf, len); + grub_file_close(file); + + return size; +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/wimboot.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/wimboot.h new file mode 100644 index 0000000..0cff658 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/wimboot.h @@ -0,0 +1,65 @@ +/****************************************************************************** + * wimboot.h + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ +#ifndef __WIMBOOT_H__ +#define __WIMBOOT_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ventoy_def.h" + + +#define size_t grub_size_t +#define ssize_t grub_ssize_t +#define memset grub_memset +#define memcpy grub_memcpy + +#define uint8_t grub_uint8_t +#define uint16_t grub_uint16_t +#define uint32_t grub_uint32_t +#define uint64_t grub_uint64_t +#define int32_t grub_int32_t + + + +#define assert(exp) + +//#define DBG grub_printf +#define DBG(fmt, ...) + +const char * huffman_bin ( unsigned long value, unsigned int bits ); + +#endif + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/xpress.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/xpress.c new file mode 100644 index 0000000..7570c90 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/xpress.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * @file + * + * Xpress Compression Algorithm (MS-XCA) decompression + * + */ + +#include "wimboot.h" +#include "huffman.h" +#include "xpress.h" + +#pragma GCC diagnostic ignored "-Wcast-align" + +/** + * Decompress XCA-compressed data + * + * @v data Compressed data + * @v len Length of compressed data + * @v buf Decompression buffer, or NULL + * @ret out_len Length of decompressed data, or negative error + */ +ssize_t xca_decompress ( const void *data, size_t len, void *buf ) { + const void *src = data; + const void *end = ( uint8_t * ) src + len; + uint8_t *out = buf; + size_t out_len = 0; + size_t out_len_threshold = 0; + const struct xca_huf_len *lengths; + struct xca xca; + uint32_t accum = 0; + int extra_bits = 0; + unsigned int huf; + struct huffman_symbols *sym; + unsigned int raw; + unsigned int match_len; + unsigned int match_offset_bits; + unsigned int match_offset; + const uint8_t *copy; + int rc; + + /* Process data stream */ + while ( src < end ) { + + /* (Re)initialise decompressor if applicable */ + if ( out_len >= out_len_threshold ) { + + /* Construct symbol lengths */ + lengths = src; + src = ( uint8_t * ) src + sizeof ( *lengths ); + if ( src > end ) { + DBG ( "XCA too short to hold Huffman lengths table.\n"); + return -1; + } + for ( raw = 0 ; raw < XCA_CODES ; raw++ ) + xca.lengths[raw] = xca_huf_len ( lengths, raw ); + + /* Construct Huffman alphabet */ + if ( ( rc = huffman_alphabet ( &xca.alphabet, + xca.lengths, + XCA_CODES ) ) != 0 ) + return rc; + + /* Initialise state */ + accum = XCA_GET16 ( src ); + accum <<= 16; + accum |= XCA_GET16 ( src ); + extra_bits = 16; + + /* Determine next threshold */ + out_len_threshold = ( out_len + XCA_BLOCK_SIZE ); + } + + /* Determine symbol */ + huf = ( accum >> ( 32 - HUFFMAN_BITS ) ); + sym = huffman_sym ( &xca.alphabet, huf ); + raw = huffman_raw ( sym, huf ); + accum <<= huffman_len ( sym ); + extra_bits -= huffman_len ( sym ); + if ( extra_bits < 0 ) { + accum |= ( XCA_GET16 ( src ) << ( -extra_bits ) ); + extra_bits += 16; + } + + /* Process symbol */ + if ( raw < XCA_END_MARKER ) { + + /* Literal symbol - add to output stream */ + if ( buf ) + *(out++) = raw; + out_len++; + + } else if ( ( raw == XCA_END_MARKER ) && + ( (uint8_t *) src >= ( ( uint8_t * ) end - 1 ) ) ) { + + /* End marker symbol */ + return out_len; + + } else { + + /* LZ77 match symbol */ + raw -= XCA_END_MARKER; + match_offset_bits = ( raw >> 4 ); + match_len = ( raw & 0x0f ); + if ( match_len == 0x0f ) { + match_len = XCA_GET8 ( src ); + if ( match_len == 0xff ) { + match_len = XCA_GET16 ( src ); + } else { + match_len += 0x0f; + } + } + match_len += 3; + if ( match_offset_bits ) { + match_offset = + ( ( accum >> ( 32 - match_offset_bits )) + + ( 1 << match_offset_bits ) ); + } else { + match_offset = 1; + } + accum <<= match_offset_bits; + extra_bits -= match_offset_bits; + if ( extra_bits < 0 ) { + accum |= ( XCA_GET16 ( src ) << (-extra_bits) ); + extra_bits += 16; + } + + /* Copy data */ + out_len += match_len; + if ( buf ) { + copy = ( out - match_offset ); + while ( match_len-- ) + *(out++) = *(copy++); + } + } + } + + return out_len; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/xpress.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/xpress.h new file mode 100644 index 0000000..de6ed89 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/grub-core/ventoy/xpress.h @@ -0,0 +1,87 @@ +#ifndef _XCA_H +#define _XCA_H + +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * @file + * + * Xpress Compression Algorithm (MS-XCA) decompression + * + */ + +#include "huffman.h" + +/** Number of XCA codes */ +#define XCA_CODES 512 + +/** XCA decompressor */ +struct xca { + /** Huffman alphabet */ + struct huffman_alphabet alphabet; + /** Raw symbols + * + * Must immediately follow the Huffman alphabet. + */ + huffman_raw_symbol_t raw[XCA_CODES]; + /** Code lengths */ + uint8_t lengths[XCA_CODES]; +}; + +/** XCA symbol Huffman lengths table */ +struct xca_huf_len { + /** Lengths of each symbol */ + uint8_t nibbles[ XCA_CODES / 2 ]; +} __attribute__ (( packed )); + +/** + * Extract Huffman-coded length of a raw symbol + * + * @v lengths Huffman lengths table + * @v symbol Raw symbol + * @ret len Huffman-coded length + */ +static inline unsigned int xca_huf_len ( const struct xca_huf_len *lengths, + unsigned int symbol ) { + return ( ( ( lengths->nibbles[ symbol / 2 ] ) >> + ( 4 * ( symbol % 2 ) ) ) & 0x0f ); +} + +/** Get word from source data stream */ +#define XCA_GET16( src ) ( { \ + const uint16_t *src16 = src; \ + src = ( uint8_t * ) src + sizeof ( *src16 ); \ + *src16; } ) + +/** Get byte from source data stream */ +#define XCA_GET8( src ) ( { \ + const uint8_t *src8 = src; \ + src = ( uint8_t * ) src + sizeof ( *src8 ); \ + *src8; } ) + +/** XCA source data stream end marker */ +#define XCA_END_MARKER 256 + +/** XCA block size */ +#define XCA_BLOCK_SIZE ( 64 * 1024 ) + +extern ssize_t xca_decompress ( const void *data, size_t len, void *buf ); + +#endif /* _XCA_H */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/cache.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/cache.h new file mode 100644 index 0000000..b7a0cfc --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/cache.h @@ -0,0 +1,56 @@ +/* cache.h - Flush the processor's cache. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2007 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_CACHE_H +#define GRUB_CACHE_H 1 + +#include +#include + +#if defined (__i386__) || defined (__x86_64__) +static inline void +grub_arch_sync_caches (void *address __attribute__ ((unused)), + grub_size_t len __attribute__ ((unused))) +{ +} +#else +void EXPORT_FUNC(grub_arch_sync_caches) (void *address, grub_size_t len); +#endif + +#ifndef GRUB_MACHINE_EMU +#if defined (__aarch64__) || defined (__ia64__) || defined (__powerpc__) || \ + defined (__sparc__) + +#elif defined (__i386__) || defined (__x86_64__) +static inline void +grub_arch_sync_dma_caches (volatile void *address __attribute__ ((unused)), + grub_size_t len __attribute__ ((unused))) +{ +} +#elif defined(__mips__) && (_MIPS_SIM != _ABI64) +void EXPORT_FUNC(grub_arch_sync_dma_caches) (volatile void *address, grub_size_t len); +#endif +#endif + +#ifdef __arm__ +void +grub_arm_cache_enable (void); +#endif + +#endif /* ! GRUB_CACHE_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/charset.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/charset.h new file mode 100644 index 0000000..ffbf9d6 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/charset.h @@ -0,0 +1,329 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_CHARSET_HEADER +#define GRUB_CHARSET_HEADER 1 + +#include + +#define GRUB_UINT8_1_LEADINGBIT 0x80 +#define GRUB_UINT8_2_LEADINGBITS 0xc0 +#define GRUB_UINT8_3_LEADINGBITS 0xe0 +#define GRUB_UINT8_4_LEADINGBITS 0xf0 +#define GRUB_UINT8_5_LEADINGBITS 0xf8 +#define GRUB_UINT8_6_LEADINGBITS 0xfc +#define GRUB_UINT8_7_LEADINGBITS 0xfe + +#define GRUB_UINT8_1_TRAILINGBIT 0x01 +#define GRUB_UINT8_2_TRAILINGBITS 0x03 +#define GRUB_UINT8_3_TRAILINGBITS 0x07 +#define GRUB_UINT8_4_TRAILINGBITS 0x0f +#define GRUB_UINT8_5_TRAILINGBITS 0x1f +#define GRUB_UINT8_6_TRAILINGBITS 0x3f + +#define GRUB_MAX_UTF8_PER_UTF16 4 +/* You need at least one UTF-8 byte to have one UTF-16 word. + You need at least three UTF-8 bytes to have 2 UTF-16 words (surrogate pairs). + */ +#define GRUB_MAX_UTF16_PER_UTF8 1 +#define GRUB_MAX_UTF8_PER_CODEPOINT 4 + +#define GRUB_UCS2_LIMIT 0x10000 +#define GRUB_UTF16_UPPER_SURROGATE(code) \ + (0xD800 | ((((code) - GRUB_UCS2_LIMIT) >> 10) & 0x3ff)) +#define GRUB_UTF16_LOWER_SURROGATE(code) \ + (0xDC00 | (((code) - GRUB_UCS2_LIMIT) & 0x3ff)) + +/* Process one character from UTF8 sequence. + At beginning set *code = 0, *count = 0. Returns 0 on failure and + 1 on success. *count holds the number of trailing bytes. */ +static inline int +grub_utf8_process (grub_uint8_t c, grub_uint32_t *code, int *count) +{ + if (*count) + { + if ((c & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT) + { + *count = 0; + /* invalid */ + return 0; + } + else + { + *code <<= 6; + *code |= (c & GRUB_UINT8_6_TRAILINGBITS); + (*count)--; + /* Overlong. */ + if ((*count == 1 && *code <= 0x1f) + || (*count == 2 && *code <= 0xf)) + { + *code = 0; + *count = 0; + return 0; + } + return 1; + } + } + + if ((c & GRUB_UINT8_1_LEADINGBIT) == 0) + { + *code = c; + return 1; + } + if ((c & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS) + { + *count = 1; + *code = c & GRUB_UINT8_5_TRAILINGBITS; + /* Overlong */ + if (*code <= 1) + { + *count = 0; + *code = 0; + return 0; + } + return 1; + } + if ((c & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS) + { + *count = 2; + *code = c & GRUB_UINT8_4_TRAILINGBITS; + return 1; + } + if ((c & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS) + { + *count = 3; + *code = c & GRUB_UINT8_3_TRAILINGBITS; + return 1; + } + return 0; +} + + +/* Convert a (possibly null-terminated) UTF-8 string of at most SRCSIZE + bytes (if SRCSIZE is -1, it is ignored) in length to a UTF-16 string. + Return the number of characters converted. DEST must be able to hold + at least DESTSIZE characters. If an invalid sequence is found, return -1. + If SRCEND is not NULL, then *SRCEND is set to the next byte after the + last byte used in SRC. */ +static inline grub_size_t +grub_utf8_to_utf16 (grub_uint16_t *dest, grub_size_t destsize, + const grub_uint8_t *src, grub_size_t srcsize, + const grub_uint8_t **srcend) +{ + grub_uint16_t *p = dest; + int count = 0; + grub_uint32_t code = 0; + + if (srcend) + *srcend = src; + + while (srcsize && destsize) + { + int was_count = count; + if (srcsize != (grub_size_t)-1) + srcsize--; + if (!grub_utf8_process (*src++, &code, &count)) + { + code = '?'; + count = 0; + /* Character c may be valid, don't eat it. */ + if (was_count) + src--; + } + if (count != 0) + continue; + if (code == 0) + break; + if (destsize < 2 && code >= GRUB_UCS2_LIMIT) + break; + if (code >= GRUB_UCS2_LIMIT) + { + *p++ = GRUB_UTF16_UPPER_SURROGATE (code); + *p++ = GRUB_UTF16_LOWER_SURROGATE (code); + destsize -= 2; + } + else + { + *p++ = code; + destsize--; + } + } + + if (srcend) + *srcend = src; + return p - dest; +} + +/* Determine the last position where the UTF-8 string [beg, end) can + be safely cut. */ +static inline grub_size_t +grub_getend (const char *beg, const char *end) +{ + const char *ptr; + for (ptr = end - 1; ptr >= beg; ptr--) + if ((*ptr & GRUB_UINT8_2_LEADINGBITS) != GRUB_UINT8_1_LEADINGBIT) + break; + if (ptr < beg) + return 0; + if ((*ptr & GRUB_UINT8_1_LEADINGBIT) == 0) + return ptr + 1 - beg; + if ((*ptr & GRUB_UINT8_3_LEADINGBITS) == GRUB_UINT8_2_LEADINGBITS + && ptr + 2 <= end) + return ptr + 2 - beg; + if ((*ptr & GRUB_UINT8_4_LEADINGBITS) == GRUB_UINT8_3_LEADINGBITS + && ptr + 3 <= end) + return ptr + 3 - beg; + if ((*ptr & GRUB_UINT8_5_LEADINGBITS) == GRUB_UINT8_4_LEADINGBITS + && ptr + 4 <= end) + return ptr + 4 - beg; + /* Invalid character or incomplete. Cut before it. */ + return ptr - beg; +} + +/* Convert UTF-16 to UTF-8. */ +static inline grub_uint8_t * +grub_utf16_to_utf8 (grub_uint8_t *dest, const grub_uint16_t *src, + grub_size_t size) +{ + grub_uint32_t code_high = 0; + + while (size--) + { + grub_uint32_t code = *src++; + + if (code_high) + { + if (code >= 0xDC00 && code <= 0xDFFF) + { + /* Surrogate pair. */ + code = ((code_high - 0xD800) << 10) + (code - 0xDC00) + 0x10000; + + *dest++ = (code >> 18) | 0xF0; + *dest++ = ((code >> 12) & 0x3F) | 0x80; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + else + { + /* Error... */ + *dest++ = '?'; + /* *src may be valid. Don't eat it. */ + src--; + } + + code_high = 0; + } + else + { + if (code <= 0x007F) + *dest++ = code; + else if (code <= 0x07FF) + { + *dest++ = (code >> 6) | 0xC0; + *dest++ = (code & 0x3F) | 0x80; + } + else if (code >= 0xD800 && code <= 0xDBFF) + { + code_high = code; + continue; + } + else if (code >= 0xDC00 && code <= 0xDFFF) + { + /* Error... */ + *dest++ = '?'; + } + else if (code < 0x10000) + { + *dest++ = (code >> 12) | 0xE0; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + else + { + *dest++ = (code >> 18) | 0xF0; + *dest++ = ((code >> 12) & 0x3F) | 0x80; + *dest++ = ((code >> 6) & 0x3F) | 0x80; + *dest++ = (code & 0x3F) | 0x80; + } + } + } + + return dest; +} + +#define GRUB_MAX_UTF8_PER_LATIN1 2 + +/* Convert Latin1 to UTF-8. */ +static inline grub_uint8_t * +grub_latin1_to_utf8 (grub_uint8_t *dest, const grub_uint8_t *src, + grub_size_t size) +{ + while (size--) + { + if (!(*src & 0x80)) + *dest++ = *src; + else + { + *dest++ = (*src >> 6) | 0xC0; + *dest++ = (*src & 0x3F) | 0x80; + } + src++; + } + + return dest; +} + +/* Convert UCS-4 to UTF-8. */ +char *grub_ucs4_to_utf8_alloc (const grub_uint32_t *src, grub_size_t size); + +int +grub_is_valid_utf8 (const grub_uint8_t *src, grub_size_t srcsize); + +grub_ssize_t grub_utf8_to_ucs4_alloc (const char *msg, + grub_uint32_t **unicode_msg, + grub_uint32_t **last_position); + +/* Returns the number of bytes the string src would occupy is converted + to UTF-8, excluding \0. */ +grub_size_t +grub_get_num_of_utf8_bytes (const grub_uint32_t *src, grub_size_t size); + +/* Converts UCS-4 to UTF-8. Returns the number of bytes effectively written + excluding the trailing \0. */ +grub_size_t +grub_ucs4_to_utf8 (const grub_uint32_t *src, grub_size_t size, + grub_uint8_t *dest, grub_size_t destsize); +grub_size_t grub_utf8_to_ucs4 (grub_uint32_t *dest, grub_size_t destsize, + const grub_uint8_t *src, grub_size_t srcsize, + const grub_uint8_t **srcend); +/* Returns -2 if not enough space, -1 on invalid character. */ +grub_ssize_t +grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend, + grub_uint32_t code); + +const grub_uint32_t * +grub_unicode_get_comb_start (const grub_uint32_t *str, + const grub_uint32_t *cur); + +int +grub_utf8_get_num_code (const char *src, grub_size_t srcsize); + +const char * +grub_utf8_offset_code (const char *src, grub_size_t srcsize, int num); + +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/compiler.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/compiler.h new file mode 100644 index 0000000..046be99 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/compiler.h @@ -0,0 +1,53 @@ +/* compiler.h - macros for various compiler features */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010,2014 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_COMPILER_HEADER +#define GRUB_COMPILER_HEADER 1 + +/* GCC version checking borrowed from glibc. */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define GNUC_PREREQ(maj,min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define GNUC_PREREQ(maj,min) 0 +#endif + +/* Does this compiler support compile-time error attributes? */ +#if GNUC_PREREQ(4,3) +# define ATTRIBUTE_ERROR(msg) \ + __attribute__ ((__error__ (msg))) +#else +# define ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn)) +#endif + +#if GNUC_PREREQ(4,4) +# define GNU_PRINTF gnu_printf +#else +# define GNU_PRINTF printf +#endif + +#if GNUC_PREREQ(3,4) +# define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) +#else +# define WARN_UNUSED_RESULT +#endif + +#define UNUSED __attribute__((__unused__)) + +#endif /* ! GRUB_COMPILER_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/disk.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/disk.h new file mode 100644 index 0000000..e55c5ab --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/disk.h @@ -0,0 +1,267 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_DISK_HEADER +#define GRUB_DISK_HEADER 1 + +#include + +#include +#include +#include +#include +/* For NULL. */ +#include + +/* These are used to set a device id. When you add a new disk device, + you must define a new id for it here. */ +enum grub_disk_dev_id + { + GRUB_DISK_DEVICE_BIOSDISK_ID, + GRUB_DISK_DEVICE_OFDISK_ID, + GRUB_DISK_DEVICE_LOOPBACK_ID, + GRUB_DISK_DEVICE_EFIDISK_ID, + GRUB_DISK_DEVICE_DISKFILTER_ID, + GRUB_DISK_DEVICE_HOST_ID, + GRUB_DISK_DEVICE_ATA_ID, + GRUB_DISK_DEVICE_MEMDISK_ID, + GRUB_DISK_DEVICE_NAND_ID, + GRUB_DISK_DEVICE_SCSI_ID, + GRUB_DISK_DEVICE_CRYPTODISK_ID, + GRUB_DISK_DEVICE_ARCDISK_ID, + GRUB_DISK_DEVICE_HOSTDISK_ID, + GRUB_DISK_DEVICE_PROCFS_ID, + GRUB_DISK_DEVICE_CBFSDISK_ID, + GRUB_DISK_DEVICE_UBOOTDISK_ID, + GRUB_DISK_DEVICE_XEN, + GRUB_DISK_DEVICE_OBDISK_ID, + }; + +struct grub_disk; +#ifdef GRUB_UTIL +struct grub_disk_memberlist; +#endif + +typedef enum + { + GRUB_DISK_PULL_NONE, + GRUB_DISK_PULL_REMOVABLE, + GRUB_DISK_PULL_RESCAN, + GRUB_DISK_PULL_MAX + } grub_disk_pull_t; + +typedef int (*grub_disk_dev_iterate_hook_t) (const char *name, void *data); + +/* Disk device. */ +struct grub_disk_dev +{ + /* The device name. */ + const char *name; + + /* The device id used by the cache manager. */ + enum grub_disk_dev_id id; + + /* Call HOOK with each device name, until HOOK returns non-zero. */ + int (*disk_iterate) (grub_disk_dev_iterate_hook_t hook, void *hook_data, + grub_disk_pull_t pull); + + /* Open the device named NAME, and set up DISK. */ + grub_err_t (*disk_open) (const char *name, struct grub_disk *disk); + + /* Close the disk DISK. */ + void (*disk_close) (struct grub_disk *disk); + + /* Read SIZE sectors from the sector SECTOR of the disk DISK into BUF. */ + grub_err_t (*disk_read) (struct grub_disk *disk, grub_disk_addr_t sector, + grub_size_t size, char *buf); + + /* Write SIZE sectors from BUF into the sector SECTOR of the disk DISK. */ + grub_err_t (*disk_write) (struct grub_disk *disk, grub_disk_addr_t sector, + grub_size_t size, const char *buf); + +#ifdef GRUB_UTIL + struct grub_disk_memberlist *(*disk_memberlist) (struct grub_disk *disk); + const char * (*disk_raidname) (struct grub_disk *disk); +#endif + + /* The next disk device. */ + struct grub_disk_dev *next; +}; +typedef struct grub_disk_dev *grub_disk_dev_t; + +extern grub_disk_dev_t EXPORT_VAR (grub_disk_dev_list); + +struct grub_partition; + +typedef void (*grub_disk_read_hook_t) (grub_disk_addr_t sector, + unsigned offset, unsigned length, + void *data); + +/* Disk. */ +struct grub_disk +{ + /* The disk name. */ + const char *name; + + /* The underlying disk device. */ + grub_disk_dev_t dev; + + /* The total number of sectors. */ + grub_uint64_t total_sectors; + + /* Logarithm of sector size. */ + unsigned int log_sector_size; + + /* Maximum number of sectors read divided by GRUB_DISK_CACHE_SIZE. */ + unsigned int max_agglomerate; + + /* The id used by the disk cache manager. */ + unsigned long id; + + /* The partition information. This is machine-specific. */ + struct grub_partition *partition; + + /* Called when a sector was read. OFFSET is between 0 and + the sector size minus 1, and LENGTH is between 0 and the sector size. */ + grub_disk_read_hook_t read_hook; + + /* Caller-specific data passed to the read hook. */ + void *read_hook_data; + + /* Device-specific data. */ + void *data; +}; +typedef struct grub_disk *grub_disk_t; + +#ifdef GRUB_UTIL +struct grub_disk_memberlist +{ + grub_disk_t disk; + struct grub_disk_memberlist *next; +}; +typedef struct grub_disk_memberlist *grub_disk_memberlist_t; +#endif + +/* The sector size. */ +#define GRUB_DISK_SECTOR_SIZE 0x200 +#define GRUB_DISK_SECTOR_BITS 9 + +/* The maximum number of disk caches. */ +#define GRUB_DISK_CACHE_NUM 1021 + +/* The size of a disk cache in 512B units. Must be at least as big as the + largest supported sector size, currently 16K. */ +#define GRUB_DISK_CACHE_BITS 6 +#define GRUB_DISK_CACHE_SIZE (1 << GRUB_DISK_CACHE_BITS) + +#define GRUB_DISK_MAX_MAX_AGGLOMERATE ((1 << (30 - GRUB_DISK_CACHE_BITS - GRUB_DISK_SECTOR_BITS)) - 1) + +/* Return value of grub_disk_get_size() in case disk size is unknown. */ +#define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL + +/* This is called from the memory manager. */ +void grub_disk_cache_invalidate_all (void); + +void EXPORT_FUNC(grub_disk_dev_register) (grub_disk_dev_t dev); +void EXPORT_FUNC(grub_disk_dev_unregister) (grub_disk_dev_t dev); +static inline int +grub_disk_dev_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data) +{ + grub_disk_dev_t p; + grub_disk_pull_t pull; + + for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++) + for (p = grub_disk_dev_list; p; p = p->next) + if (p->disk_iterate && (p->disk_iterate) (hook, hook_data, pull)) + return 1; + + return 0; +} + +grub_disk_t EXPORT_FUNC(grub_disk_open) (const char *name); +void EXPORT_FUNC(grub_disk_close) (grub_disk_t disk); +grub_err_t EXPORT_FUNC(grub_disk_blocklist_read)(void *chunklist, grub_uint64_t sector, + grub_uint64_t size, grub_uint32_t log_sector_size); +grub_err_t EXPORT_FUNC(grub_disk_blocklist_read2)(grub_disk_t disk, grub_uint64_t sector, + grub_uint64_t size, char *buf); + +grub_err_t EXPORT_FUNC(grub_disk_read) (grub_disk_t disk, + grub_disk_addr_t sector, + grub_off_t offset, + grub_size_t size, + void *buf); +grub_err_t grub_disk_write (grub_disk_t disk, + grub_disk_addr_t sector, + grub_off_t offset, + grub_size_t size, + const void *buf); +extern grub_err_t (*EXPORT_VAR(grub_disk_write_weak)) (grub_disk_t disk, + grub_disk_addr_t sector, + grub_off_t offset, + grub_size_t size, + const void *buf); + + +grub_uint64_t EXPORT_FUNC(grub_disk_get_size) (grub_disk_t disk); + +#if DISK_CACHE_STATS +void +EXPORT_FUNC(grub_disk_cache_get_performance) (unsigned long *hits, unsigned long *misses); +#endif + +extern void (* EXPORT_VAR(grub_disk_firmware_fini)) (void); +extern int EXPORT_VAR(grub_disk_firmware_is_tainted); + +static inline void +grub_stop_disk_firmware (void) +{ + /* To prevent two drivers operating on the same disks. */ + grub_disk_firmware_is_tainted = 1; + if (grub_disk_firmware_fini) + { + grub_disk_firmware_fini (); + grub_disk_firmware_fini = NULL; + } +} + +/* Disk cache. */ +struct grub_disk_cache +{ + enum grub_disk_dev_id dev_id; + unsigned long disk_id; + grub_disk_addr_t sector; + char *data; + int lock; +}; + +extern struct grub_disk_cache EXPORT_VAR(grub_disk_cache_table)[GRUB_DISK_CACHE_NUM]; + +#if defined (GRUB_UTIL) +void grub_lvm_init (void); +void grub_ldm_init (void); +void grub_mdraid09_init (void); +void grub_mdraid1x_init (void); +void grub_diskfilter_init (void); +void grub_lvm_fini (void); +void grub_ldm_fini (void); +void grub_mdraid09_fini (void); +void grub_mdraid1x_fini (void); +void grub_diskfilter_fini (void); +#endif + +#endif /* ! GRUB_DISK_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/dl.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/dl.h new file mode 100644 index 0000000..a5ccf7b --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/dl.h @@ -0,0 +1,309 @@ +/* dl.h - types and prototypes for loadable module support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_DL_H +#define GRUB_DL_H 1 + +#include +#ifndef ASM_FILE +#include +#include +#include +#include +#include +#endif + +/* + * Macros GRUB_MOD_INIT and GRUB_MOD_FINI are also used by build rules + * to collect module names, so we define them only when they are not + * defined already. + */ +#ifndef ASM_FILE + +#ifndef GRUB_MOD_INIT + +#if !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_KERNEL) + +#define GRUB_MOD_INIT(name) \ +static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ +static void \ +grub_mod_init (grub_dl_t mod __attribute__ ((unused))) + +#define GRUB_MOD_FINI(name) \ +static void grub_mod_fini (void) __attribute__ ((used)); \ +static void \ +grub_mod_fini (void) + +#elif defined (GRUB_KERNEL) + +#define GRUB_MOD_INIT(name) \ +static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ +void \ +grub_##name##_init (void) { grub_mod_init (0); } \ +static void \ +grub_mod_init (grub_dl_t mod __attribute__ ((unused))) + +#define GRUB_MOD_FINI(name) \ +static void grub_mod_fini (void) __attribute__ ((used)); \ +void \ +grub_##name##_fini (void) { grub_mod_fini (); } \ +static void \ +grub_mod_fini (void) + +#else + +#define GRUB_MOD_INIT(name) \ +static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ +void grub_##name##_init (void); \ +void \ +grub_##name##_init (void) { grub_mod_init (0); } \ +static void \ +grub_mod_init (grub_dl_t mod __attribute__ ((unused))) + +#define GRUB_MOD_FINI(name) \ +static void grub_mod_fini (void) __attribute__ ((used)); \ +void grub_##name##_fini (void); \ +void \ +grub_##name##_fini (void) { grub_mod_fini (); } \ +static void \ +grub_mod_fini (void) + +#endif + +#endif + +#endif + +#ifndef ASM_FILE +#ifdef __APPLE__ +#define GRUB_MOD_SECTION(x) "_" #x ", _" #x "" +#else +#define GRUB_MOD_SECTION(x) "." #x +#endif +#else +#ifdef __APPLE__ +#define GRUB_MOD_SECTION(x) _ ## x , _ ##x +#else +#define GRUB_MOD_SECTION(x) . ## x +#endif +#endif + +/* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. + Modules have to be licensed under GPLv3 or GPLv3+ (optionally + multi-licensed under other licences as well) independently of the + presence of this check and solely by linking (module loading in GRUB + constitutes linking) and GRUB core being licensed under GPLv3+. + Be sure to understand your license obligations. +*/ +#ifndef ASM_FILE +#if GNUC_PREREQ (3,2) +#define ATTRIBUTE_USED __used__ +#else +#define ATTRIBUTE_USED __unused__ +#endif +#define GRUB_MOD_LICENSE(license) \ + static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; +#define GRUB_MOD_DEP(name) \ +static const char grub_module_depend_##name[] \ + __attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name +#define GRUB_MOD_NAME(name) \ +static const char grub_module_name_##name[] \ + __attribute__((section(GRUB_MOD_SECTION(modname)), __used__)) = #name +#else +#ifdef __APPLE__ +.macro GRUB_MOD_LICENSE + .section GRUB_MOD_SECTION(module_license) + .ascii "LICENSE=" + .ascii $0 + .byte 0 +.endm +#else +.macro GRUB_MOD_LICENSE license + .section GRUB_MOD_SECTION(module_license), "a" + .ascii "LICENSE=" + .ascii "\license" + .byte 0 +.endm +#endif +#endif + +/* Under GPL license obligations you have to distribute your module + under GPLv3(+). However, you can also distribute the same code under + another license as long as GPLv3(+) version is provided. +*/ +#define GRUB_MOD_DUAL_LICENSE(x) + +#ifndef ASM_FILE + +struct grub_dl_segment +{ + struct grub_dl_segment *next; + void *addr; + grub_size_t size; + unsigned section; +}; +typedef struct grub_dl_segment *grub_dl_segment_t; + +struct grub_dl; + +struct grub_dl_dep +{ + struct grub_dl_dep *next; + struct grub_dl *mod; +}; +typedef struct grub_dl_dep *grub_dl_dep_t; + +#ifndef GRUB_UTIL +struct grub_dl +{ + char *name; + int ref_count; + int persistent; + grub_dl_dep_t dep; + grub_dl_segment_t segment; + Elf_Sym *symtab; + grub_size_t symsize; + void (*init) (struct grub_dl *mod); + void (*fini) (void); +#if !defined (__i386__) && !defined (__x86_64__) + void *got; + void *gotptr; + void *tramp; + void *trampptr; +#endif +#if defined(__mips__) && (_MIPS_SIM != _ABI64) + grub_uint32_t *reginfo; +#endif + void *base; + grub_size_t sz; + struct grub_dl *next; +}; +#endif +typedef struct grub_dl *grub_dl_t; + +grub_dl_t grub_dl_load_file (const char *filename); +grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); +grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); +grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); +int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); +void grub_dl_unload_unneeded (void); +int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); +int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); +extern grub_dl_t EXPORT_VAR(grub_dl_head); + +#ifndef GRUB_UTIL + +#define FOR_DL_MODULES(var) FOR_LIST_ELEMENTS ((var), (grub_dl_head)) + +#ifdef GRUB_MACHINE_EMU +void * +grub_osdep_dl_memalign (grub_size_t align, grub_size_t size); +void +grub_dl_osdep_dl_free (void *ptr); +#endif + +static inline void +grub_dl_init (grub_dl_t mod) +{ + if (mod->init) + (mod->init) (mod); + + mod->next = grub_dl_head; + grub_dl_head = mod; +} + +static inline grub_dl_t +grub_dl_get (const char *name) +{ + grub_dl_t l; + + FOR_DL_MODULES(l) + if (grub_strcmp (name, l->name) == 0) + return l; + + return 0; +} + +static inline void +grub_dl_set_persistent (grub_dl_t mod) +{ + mod->persistent = 1; +} + +static inline int +grub_dl_is_persistent (grub_dl_t mod) +{ + return mod->persistent; +} + +#endif + +grub_err_t grub_dl_register_symbol (const char *name, void *addr, + int isfunc, grub_dl_t mod); + +grub_err_t grub_arch_dl_check_header (void *ehdr); +#ifndef GRUB_UTIL +grub_err_t +grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Shdr *s, grub_dl_segment_t seg); +#endif + +#if defined (__mips__) && (_MIPS_SIM != _ABI64) +#define GRUB_LINKER_HAVE_INIT 1 +void grub_arch_dl_init_linker (void); +#endif + +#define GRUB_IA64_DL_TRAMP_ALIGN 16 +#define GRUB_IA64_DL_GOT_ALIGN 16 + +grub_err_t +grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + grub_size_t *got); +grub_err_t +grub_arm64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + grub_size_t *got); + +#if defined (__ia64__) +#define GRUB_ARCH_DL_TRAMP_ALIGN GRUB_IA64_DL_TRAMP_ALIGN +#define GRUB_ARCH_DL_GOT_ALIGN GRUB_IA64_DL_GOT_ALIGN +#define grub_arch_dl_get_tramp_got_size grub_ia64_dl_get_tramp_got_size +#elif defined (__aarch64__) +#define grub_arch_dl_get_tramp_got_size grub_arm64_dl_get_tramp_got_size +#else +grub_err_t +grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + grub_size_t *got); +#endif + +#if defined (__powerpc__) || (defined (__mips__) && (_MIPS_SIM != _ABI64)) || defined (__arm__) || \ + (defined(__riscv) && (__riscv_xlen == 32)) +#define GRUB_ARCH_DL_TRAMP_ALIGN 4 +#define GRUB_ARCH_DL_GOT_ALIGN 4 +#endif + +#if defined (__aarch64__) || defined (__sparc__) || (defined (__mips__) && (_MIPS_SIM == _ABI64)) || \ + (defined(__riscv) && (__riscv_xlen == 64)) +#define GRUB_ARCH_DL_TRAMP_ALIGN 8 +#define GRUB_ARCH_DL_GOT_ALIGN 8 +#endif + +#endif + +#endif /* ! GRUB_DL_H */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/api.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/api.h new file mode 100644 index 0000000..4ebe1db --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/api.h @@ -0,0 +1,1766 @@ +/* efi.h - declare EFI types and functions */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_EFI_API_HEADER +#define GRUB_EFI_API_HEADER 1 + +#include +#include + +/* For consistency and safety, we name the EFI-defined types differently. + All names are transformed into lower case, _t appended, and + grub_efi_ prepended. */ + +/* Constants. */ +#define GRUB_EFI_EVT_TIMER 0x80000000 +#define GRUB_EFI_EVT_RUNTIME 0x40000000 +#define GRUB_EFI_EVT_RUNTIME_CONTEXT 0x20000000 +#define GRUB_EFI_EVT_NOTIFY_WAIT 0x00000100 +#define GRUB_EFI_EVT_NOTIFY_SIGNAL 0x00000200 +#define GRUB_EFI_EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define GRUB_EFI_EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 + +#define GRUB_EFI_TPL_APPLICATION 4 +#define GRUB_EFI_TPL_CALLBACK 8 +#define GRUB_EFI_TPL_NOTIFY 16 +#define GRUB_EFI_TPL_HIGH_LEVEL 31 + +#define GRUB_EFI_MEMORY_UC 0x0000000000000001LL +#define GRUB_EFI_MEMORY_WC 0x0000000000000002LL +#define GRUB_EFI_MEMORY_WT 0x0000000000000004LL +#define GRUB_EFI_MEMORY_WB 0x0000000000000008LL +#define GRUB_EFI_MEMORY_UCE 0x0000000000000010LL +#define GRUB_EFI_MEMORY_WP 0x0000000000001000LL +#define GRUB_EFI_MEMORY_RP 0x0000000000002000LL +#define GRUB_EFI_MEMORY_XP 0x0000000000004000LL +#define GRUB_EFI_MEMORY_NV 0x0000000000008000LL +#define GRUB_EFI_MEMORY_MORE_RELIABLE 0x0000000000010000LL +#define GRUB_EFI_MEMORY_RO 0x0000000000020000LL +#define GRUB_EFI_MEMORY_RUNTIME 0x8000000000000000LL + +#define GRUB_EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001 +#define GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002 +#define GRUB_EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004 +#define GRUB_EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008 +#define GRUB_EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010 +#define GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE 0x00000020 + +#define GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL + +#define GRUB_EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 +#define GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 +#define GRUB_EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 + +#define GRUB_EFI_TIME_ADJUST_DAYLIGHT 0x01 +#define GRUB_EFI_TIME_IN_DAYLIGHT 0x02 + +#define GRUB_EFI_UNSPECIFIED_TIMEZONE 0x07FF + +#define GRUB_EFI_OPTIONAL_PTR 0x00000001 + +#define GRUB_EFI_LOADED_IMAGE_GUID \ + { 0x5b1b31a1, 0x9562, 0x11d2, \ + { 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +#define GRUB_EFI_DISK_IO_GUID \ + { 0xce345171, 0xba0b, 0x11d2, \ + { 0x8e, 0x4f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +#define GRUB_EFI_BLOCK_IO_GUID \ + { 0x964e5b21, 0x6459, 0x11d2, \ + { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +#define GRUB_EFI_SERIAL_IO_GUID \ + { 0xbb25cf6f, 0xf1d4, 0x11d2, \ + { 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0xfd } \ + } + +#define GRUB_EFI_SIMPLE_NETWORK_GUID \ + { 0xa19832b9, 0xac25, 0x11d3, \ + { 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_PXE_GUID \ + { 0x03c4e603, 0xac28, 0x11d3, \ + { 0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_DEVICE_PATH_GUID \ + { 0x09576e91, 0x6d3f, 0x11d2, \ + { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +#define GRUB_EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \ + { 0x387477c1, 0x69c7, 0x11d2, \ + { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +#define GRUB_EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ + { 0xdd9e7534, 0x7762, 0x4698, \ + { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } \ + } + +#define GRUB_EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \ + { 0x387477c2, 0x69c7, 0x11d2, \ + { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +#define GRUB_EFI_SIMPLE_POINTER_PROTOCOL_GUID \ + { 0x31878c87, 0xb75, 0x11d5, \ + { 0x9a, 0x4f, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_ABSOLUTE_POINTER_PROTOCOL_GUID \ + { 0x8D59D32B, 0xC655, 0x4AE9, \ + { 0x9B, 0x15, 0xF2, 0x59, 0x04, 0x99, 0x2A, 0x43 } \ + } + +#define GRUB_EFI_DRIVER_BINDING_PROTOCOL_GUID \ + { 0x18A031AB, 0xB443, 0x4D1A, \ + { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 } \ + } + +#define GRUB_EFI_LOADED_IMAGE_PROTOCOL_GUID \ + { 0x5B1B31A1, 0x9562, 0x11d2, \ + { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } \ + } + +#define GRUB_EFI_LOAD_FILE_PROTOCOL_GUID \ + { 0x56EC3091, 0x954C, 0x11d2, \ + { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } \ + } + +#define GRUB_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \ + { 0x0964e5b22, 0x6459, 0x11d2, \ + { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \ + } + +#define GRUB_EFI_TAPE_IO_PROTOCOL_GUID \ + { 0x1e93e633, 0xd65a, 0x459e, \ + { 0xab, 0x84, 0x93, 0xd9, 0xec, 0x26, 0x6d, 0x18 } \ + } + +#define GRUB_EFI_UNICODE_COLLATION_PROTOCOL_GUID \ + { 0x1d85cd7f, 0xf43d, 0x11d2, \ + { 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_SCSI_IO_PROTOCOL_GUID \ + { 0x932f47e6, 0x2362, 0x4002, \ + { 0x80, 0x3e, 0x3c, 0xd5, 0x4b, 0x13, 0x8f, 0x85 } \ + } + +#define GRUB_EFI_USB2_HC_PROTOCOL_GUID \ + { 0x3e745226, 0x9818, 0x45b6, \ + { 0xa2, 0xac, 0xd7, 0xcd, 0x0e, 0x8b, 0xa2, 0xbc } \ + } + +#define GRUB_EFI_DEBUG_SUPPORT_PROTOCOL_GUID \ + { 0x2755590C, 0x6F3C, 0x42FA, \ + { 0x9E, 0xA4, 0xA3, 0xBA, 0x54, 0x3C, 0xDA, 0x25 } \ + } + +#define GRUB_EFI_DEBUGPORT_PROTOCOL_GUID \ + { 0xEBA4E8D2, 0x3858, 0x41EC, \ + { 0xA2, 0x81, 0x26, 0x47, 0xBA, 0x96, 0x60, 0xD0 } \ + } + +#define GRUB_EFI_DECOMPRESS_PROTOCOL_GUID \ + { 0xd8117cfe, 0x94a6, 0x11d4, \ + { 0x9a, 0x3a, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID \ + { 0x8b843e20, 0x8132, 0x4852, \ + { 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c } \ + } + +#define GRUB_EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID \ + { 0x379be4e, 0xd706, 0x437d, \ + { 0xb0, 0x37, 0xed, 0xb8, 0x2f, 0xb7, 0x72, 0xa4 } \ + } + +#define GRUB_EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID \ + { 0x5c99a21, 0xc70f, 0x4ad2, \ + { 0x8a, 0x5f, 0x35, 0xdf, 0x33, 0x43, 0xf5, 0x1e } \ + } + +#define GRUB_EFI_ACPI_TABLE_PROTOCOL_GUID \ + { 0xffe06bdd, 0x6107, 0x46a6, \ + { 0x7b, 0xb2, 0x5a, 0x9c, 0x7e, 0xc5, 0x27, 0x5c} \ + } + +#define GRUB_EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID \ + { 0x587e72d7, 0xcc50, 0x4f79, \ + { 0x82, 0x09, 0xca, 0x29, 0x1f, 0xc1, 0xa1, 0x0f } \ + } + +#define GRUB_EFI_HII_DATABASE_PROTOCOL_GUID \ + { 0xef9fc172, 0xa1b2, 0x4693, \ + { 0xb3, 0x27, 0x6d, 0x32, 0xfc, 0x41, 0x60, 0x42 } \ + } + +#define GRUB_EFI_HII_STRING_PROTOCOL_GUID \ + { 0xfd96974, 0x23aa, 0x4cdc, \ + { 0xb9, 0xcb, 0x98, 0xd1, 0x77, 0x50, 0x32, 0x2a } \ + } + +#define GRUB_EFI_HII_IMAGE_PROTOCOL_GUID \ + { 0x31a6406a, 0x6bdf, 0x4e46, \ + { 0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x9, 0x20 } \ + } + +#define GRUB_EFI_HII_FONT_PROTOCOL_GUID \ + { 0xe9ca4775, 0x8657, 0x47fc, \ + { 0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x8, 0x43, 0x24 } \ + } + +#define GRUB_EFI_HII_CONFIGURATION_ACCESS_PROTOCOL_GUID \ + { 0x330d4706, 0xf2a0, 0x4e4f, \ + { 0xa3, 0x69, 0xb6, 0x6f, 0xa8, 0xd5, 0x43, 0x85 } \ + } + +#define GRUB_EFI_COMPONENT_NAME2_PROTOCOL_GUID \ + { 0x6a7a5cff, 0xe8d9, 0x4f70, \ + { 0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14} \ + } + +#define GRUB_EFI_USB_IO_PROTOCOL_GUID \ + { 0x2B2F68D6, 0x0CD2, 0x44cf, \ + { 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75 } \ + } + +#define GRUB_EFI_TIANO_CUSTOM_DECOMPRESS_GUID \ + { 0xa31280ad, 0x481e, 0x41b6, \ + { 0x95, 0xe8, 0x12, 0x7f, 0x4c, 0x98, 0x47, 0x79 } \ + } + +#define GRUB_EFI_CRC32_GUIDED_SECTION_EXTRACTION_GUID \ + { 0xfc1bcdb0, 0x7d31, 0x49aa, \ + { 0x93, 0x6a, 0xa4, 0x60, 0x0d, 0x9d, 0xd0, 0x83 } \ + } + +#define GRUB_EFI_LZMA_CUSTOM_DECOMPRESS_GUID \ + { 0xee4e5898, 0x3914, 0x4259, \ + { 0x9d, 0x6e, 0xdc, 0x7b, 0xd7, 0x94, 0x03, 0xcf } \ + } + +#define GRUB_EFI_TSC_FREQUENCY_GUID \ + { 0xdba6a7e3, 0xbb57, 0x4be7, \ + { 0x8a, 0xf8, 0xd5, 0x78, 0xdb, 0x7e, 0x56, 0x87 } \ + } + +#define GRUB_EFI_SYSTEM_RESOURCE_TABLE_GUID \ + { 0xb122a263, 0x3661, 0x4f68, \ + { 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80 } \ + } + +#define GRUB_EFI_DXE_SERVICES_TABLE_GUID \ + { 0x05ad34ba, 0x6f02, 0x4214, \ + { 0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9 } \ + } + +#define GRUB_EFI_HOB_LIST_GUID \ + { 0x7739f24c, 0x93d7, 0x11d4, \ + { 0x9a, 0x3a, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_MEMORY_TYPE_INFORMATION_GUID \ + { 0x4c19049f, 0x4137, 0x4dd3, \ + { 0x9c, 0x10, 0x8b, 0x97, 0xa8, 0x3f, 0xfd, 0xfa } \ + } + +#define GRUB_EFI_DEBUG_IMAGE_INFO_TABLE_GUID \ + { 0x49152e77, 0x1ada, 0x4764, \ + { 0xb7, 0xa2, 0x7a, 0xfe, 0xfe, 0xd9, 0x5e, 0x8b } \ + } + +#define GRUB_EFI_MPS_TABLE_GUID \ + { 0xeb9d2d2f, 0x2d88, 0x11d3, \ + { 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_ACPI_TABLE_GUID \ + { 0xeb9d2d30, 0x2d88, 0x11d3, \ + { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_ACPI_20_TABLE_GUID \ + { 0x8868e871, 0xe4f1, 0x11d3, \ + { 0xbc, 0x22, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \ + } + +#define GRUB_EFI_SMBIOS_TABLE_GUID \ + { 0xeb9d2d31, 0x2d88, 0x11d3, \ + { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_SMBIOS3_TABLE_GUID \ + { 0xf2fd1544, 0x9794, 0x4a2c, \ + { 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 } \ + } + +#define GRUB_EFI_SAL_TABLE_GUID \ + { 0xeb9d2d32, 0x2d88, 0x11d3, \ + { 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +#define GRUB_EFI_HCDP_TABLE_GUID \ + { 0xf951938d, 0x620b, 0x42ef, \ + { 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 } \ + } + +#define GRUB_EFI_DEVICE_TREE_GUID \ + { 0xb1b621d5, 0xf19c, 0x41a5, \ + { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } \ + } + +#define GRUB_EFI_VENDOR_APPLE_GUID \ + { 0x2B0585EB, 0xD8B8, 0x49A9, \ + { 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7 } \ + } + +struct grub_efi_sal_system_table +{ + grub_uint32_t signature; + grub_uint32_t total_table_len; + grub_uint16_t sal_rev; + grub_uint16_t entry_count; + grub_uint8_t checksum; + grub_uint8_t reserved1[7]; + grub_uint16_t sal_a_version; + grub_uint16_t sal_b_version; + grub_uint8_t oem_id[32]; + grub_uint8_t product_id[32]; + grub_uint8_t reserved2[8]; + grub_uint8_t entries[0]; +}; + +enum + { + GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_ENTRYPOINT_DESCRIPTOR = 0, + GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_MEMORY_DESCRIPTOR = 1, + GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_PLATFORM_FEATURES = 2, + GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_TRANSLATION_REGISTER_DESCRIPTOR = 3, + GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_PURGE_TRANSLATION_COHERENCE = 4, + GRUB_EFI_SAL_SYSTEM_TABLE_TYPE_AP_WAKEUP = 5 + }; + +struct grub_efi_sal_system_table_entrypoint_descriptor +{ + grub_uint8_t type; + grub_uint8_t pad[7]; + grub_uint64_t pal_proc_addr; + grub_uint64_t sal_proc_addr; + grub_uint64_t global_data_ptr; + grub_uint64_t reserved[2]; +}; + +struct grub_efi_sal_system_table_memory_descriptor +{ + grub_uint8_t type; + grub_uint8_t sal_used; + grub_uint8_t attr; + grub_uint8_t ar; + grub_uint8_t attr_mask; + grub_uint8_t mem_type; + grub_uint8_t usage; + grub_uint8_t unknown; + grub_uint64_t addr; + grub_uint64_t len; + grub_uint64_t unknown2; +}; + +struct grub_efi_sal_system_table_platform_features +{ + grub_uint8_t type; + grub_uint8_t flags; + grub_uint8_t reserved[14]; +}; + +struct grub_efi_sal_system_table_translation_register_descriptor +{ + grub_uint8_t type; + grub_uint8_t register_type; + grub_uint8_t register_number; + grub_uint8_t reserved[5]; + grub_uint64_t addr; + grub_uint64_t page_size; + grub_uint64_t reserver; +}; + +struct grub_efi_sal_system_table_purge_translation_coherence +{ + grub_uint8_t type; + grub_uint8_t reserved[3]; + grub_uint32_t ndomains; + grub_uint64_t coherence; +}; + +struct grub_efi_sal_system_table_ap_wakeup +{ + grub_uint8_t type; + grub_uint8_t mechanism; + grub_uint8_t reserved[6]; + grub_uint64_t vector; +}; + +enum + { + GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_BUSLOCK = 1, + GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_IRQREDIRECT = 2, + GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_IPIREDIRECT = 4, + GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_ITCDRIFT = 8, + }; + +typedef enum grub_efi_parity_type + { + GRUB_EFI_SERIAL_DEFAULT_PARITY, + GRUB_EFI_SERIAL_NO_PARITY, + GRUB_EFI_SERIAL_EVEN_PARITY, + GRUB_EFI_SERIAL_ODD_PARITY + } +grub_efi_parity_type_t; + +typedef enum grub_efi_stop_bits + { + GRUB_EFI_SERIAL_DEFAULT_STOP_BITS, + GRUB_EFI_SERIAL_1_STOP_BIT, + GRUB_EFI_SERIAL_1_5_STOP_BITS, + GRUB_EFI_SERIAL_2_STOP_BITS + } + grub_efi_stop_bits_t; + +/* Enumerations. */ +enum grub_efi_timer_delay + { + GRUB_EFI_TIMER_CANCEL, + GRUB_EFI_TIMER_PERIODIC, + GRUB_EFI_TIMER_RELATIVE + }; +typedef enum grub_efi_timer_delay grub_efi_timer_delay_t; + +enum grub_efi_allocate_type + { + GRUB_EFI_ALLOCATE_ANY_PAGES, + GRUB_EFI_ALLOCATE_MAX_ADDRESS, + GRUB_EFI_ALLOCATE_ADDRESS, + GRUB_EFI_MAX_ALLOCATION_TYPE + }; +typedef enum grub_efi_allocate_type grub_efi_allocate_type_t; + +enum grub_efi_memory_type + { + GRUB_EFI_RESERVED_MEMORY_TYPE, + GRUB_EFI_LOADER_CODE, + GRUB_EFI_LOADER_DATA, + GRUB_EFI_BOOT_SERVICES_CODE, + GRUB_EFI_BOOT_SERVICES_DATA, + GRUB_EFI_RUNTIME_SERVICES_CODE, + GRUB_EFI_RUNTIME_SERVICES_DATA, + GRUB_EFI_CONVENTIONAL_MEMORY, + GRUB_EFI_UNUSABLE_MEMORY, + GRUB_EFI_ACPI_RECLAIM_MEMORY, + GRUB_EFI_ACPI_MEMORY_NVS, + GRUB_EFI_MEMORY_MAPPED_IO, + GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE, + GRUB_EFI_PAL_CODE, + GRUB_EFI_PERSISTENT_MEMORY, + GRUB_EFI_MAX_MEMORY_TYPE + }; +typedef enum grub_efi_memory_type grub_efi_memory_type_t; + +enum grub_efi_interface_type + { + GRUB_EFI_NATIVE_INTERFACE + }; +typedef enum grub_efi_interface_type grub_efi_interface_type_t; + +enum grub_efi_locate_search_type + { + GRUB_EFI_ALL_HANDLES, + GRUB_EFI_BY_REGISTER_NOTIFY, + GRUB_EFI_BY_PROTOCOL + }; +typedef enum grub_efi_locate_search_type grub_efi_locate_search_type_t; + +enum grub_efi_reset_type + { + GRUB_EFI_RESET_COLD, + GRUB_EFI_RESET_WARM, + GRUB_EFI_RESET_SHUTDOWN + }; +typedef enum grub_efi_reset_type grub_efi_reset_type_t; + +/* Types. */ +typedef char grub_efi_boolean_t; +#if GRUB_CPU_SIZEOF_VOID_P == 8 +typedef grub_int64_t grub_efi_intn_t; +typedef grub_uint64_t grub_efi_uintn_t; +#else +typedef grub_int32_t grub_efi_intn_t; +typedef grub_uint32_t grub_efi_uintn_t; +#endif +typedef grub_int8_t grub_efi_int8_t; +typedef grub_uint8_t grub_efi_uint8_t; +typedef grub_int16_t grub_efi_int16_t; +typedef grub_uint16_t grub_efi_uint16_t; +typedef grub_int32_t grub_efi_int32_t; +typedef grub_uint32_t grub_efi_uint32_t; +typedef grub_int64_t grub_efi_int64_t; +typedef grub_uint64_t grub_efi_uint64_t; +typedef grub_uint8_t grub_efi_char8_t; +typedef grub_uint16_t grub_efi_char16_t; + +typedef grub_efi_intn_t grub_efi_status_t; + +#define GRUB_EFI_ERROR_CODE(value) \ + ((((grub_efi_status_t) 1) << (sizeof (grub_efi_status_t) * 8 - 1)) | (value)) + +#define GRUB_EFI_WARNING_CODE(value) (value) + +#define GRUB_EFI_SUCCESS 0 + +#define GRUB_EFI_LOAD_ERROR GRUB_EFI_ERROR_CODE (1) +#define GRUB_EFI_INVALID_PARAMETER GRUB_EFI_ERROR_CODE (2) +#define GRUB_EFI_UNSUPPORTED GRUB_EFI_ERROR_CODE (3) +#define GRUB_EFI_BAD_BUFFER_SIZE GRUB_EFI_ERROR_CODE (4) +#define GRUB_EFI_BUFFER_TOO_SMALL GRUB_EFI_ERROR_CODE (5) +#define GRUB_EFI_NOT_READY GRUB_EFI_ERROR_CODE (6) +#define GRUB_EFI_DEVICE_ERROR GRUB_EFI_ERROR_CODE (7) +#define GRUB_EFI_WRITE_PROTECTED GRUB_EFI_ERROR_CODE (8) +#define GRUB_EFI_OUT_OF_RESOURCES GRUB_EFI_ERROR_CODE (9) +#define GRUB_EFI_VOLUME_CORRUPTED GRUB_EFI_ERROR_CODE (10) +#define GRUB_EFI_VOLUME_FULL GRUB_EFI_ERROR_CODE (11) +#define GRUB_EFI_NO_MEDIA GRUB_EFI_ERROR_CODE (12) +#define GRUB_EFI_MEDIA_CHANGED GRUB_EFI_ERROR_CODE (13) +#define GRUB_EFI_NOT_FOUND GRUB_EFI_ERROR_CODE (14) +#define GRUB_EFI_ACCESS_DENIED GRUB_EFI_ERROR_CODE (15) +#define GRUB_EFI_NO_RESPONSE GRUB_EFI_ERROR_CODE (16) +#define GRUB_EFI_NO_MAPPING GRUB_EFI_ERROR_CODE (17) +#define GRUB_EFI_TIMEOUT GRUB_EFI_ERROR_CODE (18) +#define GRUB_EFI_NOT_STARTED GRUB_EFI_ERROR_CODE (19) +#define GRUB_EFI_ALREADY_STARTED GRUB_EFI_ERROR_CODE (20) +#define GRUB_EFI_ABORTED GRUB_EFI_ERROR_CODE (21) +#define GRUB_EFI_ICMP_ERROR GRUB_EFI_ERROR_CODE (22) +#define GRUB_EFI_TFTP_ERROR GRUB_EFI_ERROR_CODE (23) +#define GRUB_EFI_PROTOCOL_ERROR GRUB_EFI_ERROR_CODE (24) +#define GRUB_EFI_INCOMPATIBLE_VERSION GRUB_EFI_ERROR_CODE (25) +#define GRUB_EFI_SECURITY_VIOLATION GRUB_EFI_ERROR_CODE (26) +#define GRUB_EFI_CRC_ERROR GRUB_EFI_ERROR_CODE (27) + +#define GRUB_EFI_WARN_UNKNOWN_GLYPH GRUB_EFI_WARNING_CODE (1) +#define GRUB_EFI_WARN_DELETE_FAILURE GRUB_EFI_WARNING_CODE (2) +#define GRUB_EFI_WARN_WRITE_FAILURE GRUB_EFI_WARNING_CODE (3) +#define GRUB_EFI_WARN_BUFFER_TOO_SMALL GRUB_EFI_WARNING_CODE (4) + +typedef void *grub_efi_handle_t; +typedef void *grub_efi_event_t; +typedef grub_efi_uint64_t grub_efi_lba_t; +typedef grub_efi_uintn_t grub_efi_tpl_t; +typedef grub_uint8_t grub_efi_mac_address_t[32]; +typedef grub_uint8_t grub_efi_ipv4_address_t[4]; +typedef grub_uint16_t grub_efi_ipv6_address_t[8]; +typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4))); +typedef grub_efi_uint64_t grub_efi_physical_address_t; +typedef grub_efi_uint64_t grub_efi_virtual_address_t; + +struct grub_efi_guid +{ + grub_uint32_t data1; + grub_uint16_t data2; + grub_uint16_t data3; + grub_uint8_t data4[8]; +} __attribute__ ((aligned(8))); +typedef struct grub_efi_guid grub_efi_guid_t; + +struct grub_efi_packed_guid +{ + grub_uint32_t data1; + grub_uint16_t data2; + grub_uint16_t data3; + grub_uint8_t data4[8]; +} GRUB_PACKED; +typedef struct grub_efi_packed_guid grub_efi_packed_guid_t; + +/* XXX although the spec does not specify the padding, this actually + must have the padding! */ +struct grub_efi_memory_descriptor +{ + grub_efi_uint32_t type; + grub_efi_uint32_t padding; + grub_efi_physical_address_t physical_start; + grub_efi_virtual_address_t virtual_start; + grub_efi_uint64_t num_pages; + grub_efi_uint64_t attribute; +} GRUB_PACKED; +typedef struct grub_efi_memory_descriptor grub_efi_memory_descriptor_t; + +/* Device Path definitions. */ +struct grub_efi_device_path +{ + grub_efi_uint8_t type; + grub_efi_uint8_t subtype; + grub_efi_uint16_t length; +} GRUB_PACKED; +typedef struct grub_efi_device_path grub_efi_device_path_t; +/* XXX EFI does not define EFI_DEVICE_PATH_PROTOCOL but uses it. + It seems to be identical to EFI_DEVICE_PATH. */ +typedef struct grub_efi_device_path grub_efi_device_path_protocol_t; + +#define GRUB_EFI_DEVICE_PATH_TYPE(dp) ((dp)->type & 0x7f) +#define GRUB_EFI_DEVICE_PATH_SUBTYPE(dp) ((dp)->subtype) +#define GRUB_EFI_DEVICE_PATH_LENGTH(dp) ((dp)->length) + +/* The End of Device Path nodes. */ +#define GRUB_EFI_END_DEVICE_PATH_TYPE (0xff & 0x7f) + +#define GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff +#define GRUB_EFI_END_THIS_DEVICE_PATH_SUBTYPE 0x01 + +#define GRUB_EFI_END_ENTIRE_DEVICE_PATH(dp) \ + (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_END_DEVICE_PATH_TYPE \ + && (GRUB_EFI_DEVICE_PATH_SUBTYPE (dp) \ + == GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE)) + +#define GRUB_EFI_NEXT_DEVICE_PATH(dp) \ + ((grub_efi_device_path_t *) ((char *) (dp) \ + + GRUB_EFI_DEVICE_PATH_LENGTH (dp))) + +/* Hardware Device Path. */ +#define GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE 1 + +#define GRUB_EFI_PCI_DEVICE_PATH_SUBTYPE 1 + +struct grub_efi_pci_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint8_t function; + grub_efi_uint8_t device; +} GRUB_PACKED; +typedef struct grub_efi_pci_device_path grub_efi_pci_device_path_t; + +#define GRUB_EFI_PCCARD_DEVICE_PATH_SUBTYPE 2 + +struct grub_efi_pccard_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint8_t function; +} GRUB_PACKED; +typedef struct grub_efi_pccard_device_path grub_efi_pccard_device_path_t; + +#define GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE 3 + +struct grub_efi_memory_mapped_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t memory_type; + grub_efi_physical_address_t start_address; + grub_efi_physical_address_t end_address; +} GRUB_PACKED; +typedef struct grub_efi_memory_mapped_device_path grub_efi_memory_mapped_device_path_t; + +#define GRUB_EFI_VENDOR_DEVICE_PATH_SUBTYPE 4 + +struct grub_efi_vendor_device_path +{ + grub_efi_device_path_t header; + grub_efi_packed_guid_t vendor_guid; + grub_efi_uint8_t vendor_defined_data[0]; +} GRUB_PACKED; +typedef struct grub_efi_vendor_device_path grub_efi_vendor_device_path_t; + +#define GRUB_EFI_CONTROLLER_DEVICE_PATH_SUBTYPE 5 + +struct grub_efi_controller_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t controller_number; +} GRUB_PACKED; +typedef struct grub_efi_controller_device_path grub_efi_controller_device_path_t; + +/* ACPI Device Path. */ +#define GRUB_EFI_ACPI_DEVICE_PATH_TYPE 2 + +#define GRUB_EFI_ACPI_DEVICE_PATH_SUBTYPE 1 + +struct grub_efi_acpi_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t hid; + grub_efi_uint32_t uid; +} GRUB_PACKED; +typedef struct grub_efi_acpi_device_path grub_efi_acpi_device_path_t; + +#define GRUB_EFI_EXPANDED_ACPI_DEVICE_PATH_SUBTYPE 2 + +struct grub_efi_expanded_acpi_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t hid; + grub_efi_uint32_t uid; + grub_efi_uint32_t cid; + char hidstr[0]; +} GRUB_PACKED; +typedef struct grub_efi_expanded_acpi_device_path grub_efi_expanded_acpi_device_path_t; + +#define GRUB_EFI_EXPANDED_ACPI_HIDSTR(dp) \ + (((grub_efi_expanded_acpi_device_path_t *) dp)->hidstr) +#define GRUB_EFI_EXPANDED_ACPI_UIDSTR(dp) \ + (GRUB_EFI_EXPANDED_ACPI_HIDSTR(dp) \ + + grub_strlen (GRUB_EFI_EXPANDED_ACPI_HIDSTR(dp)) + 1) +#define GRUB_EFI_EXPANDED_ACPI_CIDSTR(dp) \ + (GRUB_EFI_EXPANDED_ACPI_UIDSTR(dp) \ + + grub_strlen (GRUB_EFI_EXPANDED_ACPI_UIDSTR(dp)) + 1) + +/* Messaging Device Path. */ +#define GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE 3 + +#define GRUB_EFI_ATAPI_DEVICE_PATH_SUBTYPE 1 + +struct grub_efi_atapi_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint8_t primary_secondary; + grub_efi_uint8_t slave_master; + grub_efi_uint16_t lun; +} GRUB_PACKED; +typedef struct grub_efi_atapi_device_path grub_efi_atapi_device_path_t; + +#define GRUB_EFI_SCSI_DEVICE_PATH_SUBTYPE 2 + +struct grub_efi_scsi_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint16_t pun; + grub_efi_uint16_t lun; +} GRUB_PACKED; +typedef struct grub_efi_scsi_device_path grub_efi_scsi_device_path_t; + +#define GRUB_EFI_FIBRE_CHANNEL_DEVICE_PATH_SUBTYPE 3 + +struct grub_efi_fibre_channel_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t reserved; + grub_efi_uint64_t wwn; + grub_efi_uint64_t lun; +} GRUB_PACKED; +typedef struct grub_efi_fibre_channel_device_path grub_efi_fibre_channel_device_path_t; + +#define GRUB_EFI_1394_DEVICE_PATH_SUBTYPE 4 + +struct grub_efi_1394_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t reserved; + grub_efi_uint64_t guid; +} GRUB_PACKED; +typedef struct grub_efi_1394_device_path grub_efi_1394_device_path_t; + +#define GRUB_EFI_USB_DEVICE_PATH_SUBTYPE 5 + +struct grub_efi_usb_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint8_t parent_port_number; + grub_efi_uint8_t usb_interface; +} GRUB_PACKED; +typedef struct grub_efi_usb_device_path grub_efi_usb_device_path_t; + +#define GRUB_EFI_USB_CLASS_DEVICE_PATH_SUBTYPE 15 + +struct grub_efi_usb_class_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint16_t vendor_id; + grub_efi_uint16_t product_id; + grub_efi_uint8_t device_class; + grub_efi_uint8_t device_subclass; + grub_efi_uint8_t device_protocol; +} GRUB_PACKED; +typedef struct grub_efi_usb_class_device_path grub_efi_usb_class_device_path_t; + +#define GRUB_EFI_I2O_DEVICE_PATH_SUBTYPE 6 + +struct grub_efi_i2o_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t tid; +} GRUB_PACKED; +typedef struct grub_efi_i2o_device_path grub_efi_i2o_device_path_t; + +#define GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE 11 + +struct grub_efi_mac_address_device_path +{ + grub_efi_device_path_t header; + grub_efi_mac_address_t mac_address; + grub_efi_uint8_t if_type; +} GRUB_PACKED; +typedef struct grub_efi_mac_address_device_path grub_efi_mac_address_device_path_t; + +#define GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE 12 + +struct grub_efi_ipv4_device_path +{ + grub_efi_device_path_t header; + grub_efi_ipv4_address_t local_ip_address; + grub_efi_ipv4_address_t remote_ip_address; + grub_efi_uint16_t local_port; + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; +} GRUB_PACKED; +typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; + +#define GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE 13 + +struct grub_efi_ipv6_device_path +{ + grub_efi_device_path_t header; + grub_efi_ipv6_address_t local_ip_address; + grub_efi_ipv6_address_t remote_ip_address; + grub_efi_uint16_t local_port; + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; +} GRUB_PACKED; +typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t; + +#define GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE 9 + +struct grub_efi_infiniband_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t resource_flags; + grub_efi_uint8_t port_gid[16]; + grub_efi_uint64_t remote_id; + grub_efi_uint64_t target_port_id; + grub_efi_uint64_t device_id; +} GRUB_PACKED; +typedef struct grub_efi_infiniband_device_path grub_efi_infiniband_device_path_t; + +#define GRUB_EFI_UART_DEVICE_PATH_SUBTYPE 14 + +struct grub_efi_uart_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t reserved; + grub_efi_uint64_t baud_rate; + grub_efi_uint8_t data_bits; + grub_efi_uint8_t parity; + grub_efi_uint8_t stop_bits; +} GRUB_PACKED; +typedef struct grub_efi_uart_device_path grub_efi_uart_device_path_t; + +#define GRUB_EFI_SATA_DEVICE_PATH_SUBTYPE 18 + +struct grub_efi_sata_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint16_t hba_port; + grub_efi_uint16_t multiplier_port; + grub_efi_uint16_t lun; +} GRUB_PACKED; +typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t; + +#define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 + +/* Media Device Path. */ +#define GRUB_EFI_MEDIA_DEVICE_PATH_TYPE 4 + +#define GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE 1 + +struct grub_efi_hard_drive_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t partition_number; + grub_efi_lba_t partition_start; + grub_efi_lba_t partition_size; + grub_efi_uint8_t partition_signature[16]; + grub_efi_uint8_t partmap_type; + grub_efi_uint8_t signature_type; +} GRUB_PACKED; +typedef struct grub_efi_hard_drive_device_path grub_efi_hard_drive_device_path_t; + +#define GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE 2 + +struct grub_efi_cdrom_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint32_t boot_entry; + grub_efi_lba_t partition_start; + grub_efi_lba_t partition_size; +} GRUB_PACKED; +typedef struct grub_efi_cdrom_device_path grub_efi_cdrom_device_path_t; + +#define GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE 3 + +struct grub_efi_vendor_media_device_path +{ + grub_efi_device_path_t header; + grub_efi_packed_guid_t vendor_guid; + grub_efi_uint8_t vendor_defined_data[0]; +} GRUB_PACKED; +typedef struct grub_efi_vendor_media_device_path grub_efi_vendor_media_device_path_t; + +#define GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE 4 + +struct grub_efi_file_path_device_path +{ + grub_efi_device_path_t header; + grub_efi_char16_t path_name[0]; +} GRUB_PACKED; +typedef struct grub_efi_file_path_device_path grub_efi_file_path_device_path_t; + +#define GRUB_EFI_PROTOCOL_DEVICE_PATH_SUBTYPE 5 + +struct grub_efi_protocol_device_path +{ + grub_efi_device_path_t header; + grub_efi_packed_guid_t guid; +} GRUB_PACKED; +typedef struct grub_efi_protocol_device_path grub_efi_protocol_device_path_t; + +#define GRUB_EFI_PIWG_DEVICE_PATH_SUBTYPE 6 + +struct grub_efi_piwg_device_path +{ + grub_efi_device_path_t header; + grub_efi_packed_guid_t guid; +} GRUB_PACKED; +typedef struct grub_efi_piwg_device_path grub_efi_piwg_device_path_t; + + +/* BIOS Boot Specification Device Path. */ +#define GRUB_EFI_BIOS_DEVICE_PATH_TYPE 5 + +#define GRUB_EFI_BIOS_DEVICE_PATH_SUBTYPE 1 + +struct grub_efi_bios_device_path +{ + grub_efi_device_path_t header; + grub_efi_uint16_t device_type; + grub_efi_uint16_t status_flags; + char description[0]; +} GRUB_PACKED; +typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t; + +struct grub_efi_open_protocol_information_entry +{ + grub_efi_handle_t agent_handle; + grub_efi_handle_t controller_handle; + grub_efi_uint32_t attributes; + grub_efi_uint32_t open_count; +}; +typedef struct grub_efi_open_protocol_information_entry grub_efi_open_protocol_information_entry_t; + +struct grub_efi_time +{ + grub_efi_uint16_t year; + grub_efi_uint8_t month; + grub_efi_uint8_t day; + grub_efi_uint8_t hour; + grub_efi_uint8_t minute; + grub_efi_uint8_t second; + grub_efi_uint8_t pad1; + grub_efi_uint32_t nanosecond; + grub_efi_int16_t time_zone; + grub_efi_uint8_t daylight; + grub_efi_uint8_t pad2; +} GRUB_PACKED; +typedef struct grub_efi_time grub_efi_time_t; + +struct grub_efi_time_capabilities +{ + grub_efi_uint32_t resolution; + grub_efi_uint32_t accuracy; + grub_efi_boolean_t sets_to_zero; +}; +typedef struct grub_efi_time_capabilities grub_efi_time_capabilities_t; + +struct grub_efi_input_key +{ + grub_efi_uint16_t scan_code; + grub_efi_char16_t unicode_char; +}; +typedef struct grub_efi_input_key grub_efi_input_key_t; + +typedef grub_efi_uint8_t grub_efi_key_toggle_state_t; +struct grub_efi_key_state +{ + grub_efi_uint32_t key_shift_state; + grub_efi_key_toggle_state_t key_toggle_state; +}; +typedef struct grub_efi_key_state grub_efi_key_state_t; + +#define GRUB_EFI_SHIFT_STATE_VALID 0x80000000 +#define GRUB_EFI_RIGHT_SHIFT_PRESSED 0x00000001 +#define GRUB_EFI_LEFT_SHIFT_PRESSED 0x00000002 +#define GRUB_EFI_RIGHT_CONTROL_PRESSED 0x00000004 +#define GRUB_EFI_LEFT_CONTROL_PRESSED 0x00000008 +#define GRUB_EFI_RIGHT_ALT_PRESSED 0x00000010 +#define GRUB_EFI_LEFT_ALT_PRESSED 0x00000020 +#define GRUB_EFI_RIGHT_LOGO_PRESSED 0x00000040 +#define GRUB_EFI_LEFT_LOGO_PRESSED 0x00000080 +#define GRUB_EFI_MENU_KEY_PRESSED 0x00000100 +#define GRUB_EFI_SYS_REQ_PRESSED 0x00000200 + +#define GRUB_EFI_TOGGLE_STATE_VALID 0x80 +#define GRUB_EFI_KEY_STATE_EXPOSED 0x40 +#define GRUB_EFI_SCROLL_LOCK_ACTIVE 0x01 +#define GRUB_EFI_NUM_LOCK_ACTIVE 0x02 +#define GRUB_EFI_CAPS_LOCK_ACTIVE 0x04 + +struct grub_efi_simple_text_output_mode +{ + grub_efi_int32_t max_mode; + grub_efi_int32_t mode; + grub_efi_int32_t attribute; + grub_efi_int32_t cursor_column; + grub_efi_int32_t cursor_row; + grub_efi_boolean_t cursor_visible; +}; +typedef struct grub_efi_simple_text_output_mode grub_efi_simple_text_output_mode_t; + +/* Tables. */ +struct grub_efi_table_header +{ + grub_efi_uint64_t signature; + grub_efi_uint32_t revision; + grub_efi_uint32_t header_size; + grub_efi_uint32_t crc32; + grub_efi_uint32_t reserved; +}; +typedef struct grub_efi_table_header grub_efi_table_header_t; + +struct grub_efi_boot_services +{ + grub_efi_table_header_t hdr; + + grub_efi_tpl_t + (*raise_tpl) (grub_efi_tpl_t new_tpl); + + void + (*restore_tpl) (grub_efi_tpl_t old_tpl); + + grub_efi_status_t + (*allocate_pages) (grub_efi_allocate_type_t type, + grub_efi_memory_type_t memory_type, + grub_efi_uintn_t pages, + grub_efi_physical_address_t *memory); + + grub_efi_status_t + (*free_pages) (grub_efi_physical_address_t memory, + grub_efi_uintn_t pages); + + grub_efi_status_t + (*get_memory_map) (grub_efi_uintn_t *memory_map_size, + grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version); + + grub_efi_status_t + (*allocate_pool) (grub_efi_memory_type_t pool_type, + grub_efi_uintn_t size, + void **buffer); + + grub_efi_status_t + (*free_pool) (void *buffer); + + grub_efi_status_t + (*create_event) (grub_efi_uint32_t type, + grub_efi_tpl_t notify_tpl, + void (*notify_function) (grub_efi_event_t event, + void *context), + void *notify_context, + grub_efi_event_t *event); + + grub_efi_status_t + (*set_timer) (grub_efi_event_t event, + grub_efi_timer_delay_t type, + grub_efi_uint64_t trigger_time); + + grub_efi_status_t + (*wait_for_event) (grub_efi_uintn_t num_events, + grub_efi_event_t *event, + grub_efi_uintn_t *index); + + grub_efi_status_t + (*signal_event) (grub_efi_event_t event); + + grub_efi_status_t + (*close_event) (grub_efi_event_t event); + + grub_efi_status_t + (*check_event) (grub_efi_event_t event); + + grub_efi_status_t + (*install_protocol_interface) (grub_efi_handle_t *handle, + grub_efi_guid_t *protocol, + grub_efi_interface_type_t protocol_interface_type, + void *protocol_interface); + + grub_efi_status_t + (*reinstall_protocol_interface) (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + void *old_interface, + void *new_interface); + + grub_efi_status_t + (*uninstall_protocol_interface) (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + void *protocol_interface); + + grub_efi_status_t + (*handle_protocol) (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + void **protocol_interface); + + void *reserved; + + grub_efi_status_t + (*register_protocol_notify) (grub_efi_guid_t *protocol, + grub_efi_event_t event, + void **registration); + + grub_efi_status_t + (*locate_handle) (grub_efi_locate_search_type_t search_type, + grub_efi_guid_t *protocol, + void *search_key, + grub_efi_uintn_t *buffer_size, + grub_efi_handle_t *buffer); + + grub_efi_status_t + (*locate_device_path) (grub_efi_guid_t *protocol, + grub_efi_device_path_t **device_path, + grub_efi_handle_t *device); + + grub_efi_status_t + (*install_configuration_table) (grub_efi_guid_t *guid, void *table); + + grub_efi_status_t + (*load_image) (grub_efi_boolean_t boot_policy, + grub_efi_handle_t parent_image_handle, + grub_efi_device_path_t *file_path, + void *source_buffer, + grub_efi_uintn_t source_size, + grub_efi_handle_t *image_handle); + + grub_efi_status_t + (*start_image) (grub_efi_handle_t image_handle, + grub_efi_uintn_t *exit_data_size, + grub_efi_char16_t **exit_data); + + grub_efi_status_t + (*exit) (grub_efi_handle_t image_handle, + grub_efi_status_t exit_status, + grub_efi_uintn_t exit_data_size, + grub_efi_char16_t *exit_data) __attribute__((noreturn)); + + grub_efi_status_t + (*unload_image) (grub_efi_handle_t image_handle); + + grub_efi_status_t + (*exit_boot_services) (grub_efi_handle_t image_handle, + grub_efi_uintn_t map_key); + + grub_efi_status_t + (*get_next_monotonic_count) (grub_efi_uint64_t *count); + + grub_efi_status_t + (*stall) (grub_efi_uintn_t microseconds); + + grub_efi_status_t + (*set_watchdog_timer) (grub_efi_uintn_t timeout, + grub_efi_uint64_t watchdog_code, + grub_efi_uintn_t data_size, + grub_efi_char16_t *watchdog_data); + + grub_efi_status_t + (*connect_controller) (grub_efi_handle_t controller_handle, + grub_efi_handle_t *driver_image_handle, + grub_efi_device_path_protocol_t *remaining_device_path, + grub_efi_boolean_t recursive); + + grub_efi_status_t + (*disconnect_controller) (grub_efi_handle_t controller_handle, + grub_efi_handle_t driver_image_handle, + grub_efi_handle_t child_handle); + + grub_efi_status_t + (*open_protocol) (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + void **protocol_interface, + grub_efi_handle_t agent_handle, + grub_efi_handle_t controller_handle, + grub_efi_uint32_t attributes); + + grub_efi_status_t + (*close_protocol) (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + grub_efi_handle_t agent_handle, + grub_efi_handle_t controller_handle); + + grub_efi_status_t + (*open_protocol_information) (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + grub_efi_open_protocol_information_entry_t **entry_buffer, + grub_efi_uintn_t *entry_count); + + grub_efi_status_t + (*protocols_per_handle) (grub_efi_handle_t handle, + grub_efi_packed_guid_t ***protocol_buffer, + grub_efi_uintn_t *protocol_buffer_count); + + grub_efi_status_t + (*locate_handle_buffer) (grub_efi_locate_search_type_t search_type, + grub_efi_guid_t *protocol, + void *search_key, + grub_efi_uintn_t *no_handles, + grub_efi_handle_t **buffer); + + grub_efi_status_t + (*locate_protocol) (grub_efi_guid_t *protocol, + void *registration, + void **protocol_interface); + + grub_efi_status_t + (*install_multiple_protocol_interfaces) (grub_efi_handle_t *handle, ...); + + grub_efi_status_t + (*uninstall_multiple_protocol_interfaces) (grub_efi_handle_t handle, ...); + + grub_efi_status_t + (*calculate_crc32) (void *data, + grub_efi_uintn_t data_size, + grub_efi_uint32_t *crc32); + + void + (*copy_mem) (void *destination, void *source, grub_efi_uintn_t length); + + void + (*set_mem) (void *buffer, grub_efi_uintn_t size, grub_efi_uint8_t value); +}; +typedef struct grub_efi_boot_services grub_efi_boot_services_t; + +struct grub_efi_runtime_services +{ + grub_efi_table_header_t hdr; + + grub_efi_status_t + (*get_time) (grub_efi_time_t *time, + grub_efi_time_capabilities_t *capabilities); + + grub_efi_status_t + (*set_time) (grub_efi_time_t *time); + + grub_efi_status_t + (*get_wakeup_time) (grub_efi_boolean_t *enabled, + grub_efi_boolean_t *pending, + grub_efi_time_t *time); + + grub_efi_status_t + (*set_wakeup_time) (grub_efi_boolean_t enabled, + grub_efi_time_t *time); + + grub_efi_status_t + (*set_virtual_address_map) (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map); + + grub_efi_status_t + (*convert_pointer) (grub_efi_uintn_t debug_disposition, void **address); + +#define GRUB_EFI_GLOBAL_VARIABLE_GUID \ + { 0x8BE4DF61, 0x93CA, 0x11d2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B,0x8C }} + + + grub_efi_status_t + (*get_variable) (grub_efi_char16_t *variable_name, + const grub_efi_guid_t *vendor_guid, + grub_efi_uint32_t *attributes, + grub_efi_uintn_t *data_size, + void *data); + + grub_efi_status_t + (*get_next_variable_name) (grub_efi_uintn_t *variable_name_size, + grub_efi_char16_t *variable_name, + grub_efi_guid_t *vendor_guid); + + grub_efi_status_t + (*set_variable) (grub_efi_char16_t *variable_name, + const grub_efi_guid_t *vendor_guid, + grub_efi_uint32_t attributes, + grub_efi_uintn_t data_size, + void *data); + + grub_efi_status_t + (*get_next_high_monotonic_count) (grub_efi_uint32_t *high_count); + + void + (*reset_system) (grub_efi_reset_type_t reset_type, + grub_efi_status_t reset_status, + grub_efi_uintn_t data_size, + grub_efi_char16_t *reset_data); +}; +typedef struct grub_efi_runtime_services grub_efi_runtime_services_t; + +struct grub_efi_configuration_table +{ + grub_efi_packed_guid_t vendor_guid; + void *vendor_table; +} GRUB_PACKED; +typedef struct grub_efi_configuration_table grub_efi_configuration_table_t; + +#define GRUB_EFIEMU_SYSTEM_TABLE_SIGNATURE 0x5453595320494249LL +#define GRUB_EFIEMU_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552LL + +struct grub_efi_serial_io_interface +{ + grub_efi_uint32_t revision; + void (*reset) (void); + grub_efi_status_t (*set_attributes) (struct grub_efi_serial_io_interface *this, + grub_efi_uint64_t speed, + grub_efi_uint32_t fifo_depth, + grub_efi_uint32_t timeout, + grub_efi_parity_type_t parity, + grub_uint8_t word_len, + grub_efi_stop_bits_t stop_bits); + grub_efi_status_t (*set_control_bits) (struct grub_efi_serial_io_interface *this, + grub_efi_uint32_t flags); + void (*get_control_bits) (void); + grub_efi_status_t (*write) (struct grub_efi_serial_io_interface *this, + grub_efi_uintn_t *buf_size, + void *buffer); + grub_efi_status_t (*read) (struct grub_efi_serial_io_interface *this, + grub_efi_uintn_t *buf_size, + void *buffer); +}; + +struct grub_efi_simple_input_interface +{ + grub_efi_status_t + (*reset) (struct grub_efi_simple_input_interface *this, + grub_efi_boolean_t extended_verification); + + grub_efi_status_t + (*read_key_stroke) (struct grub_efi_simple_input_interface *this, + grub_efi_input_key_t *key); + + grub_efi_event_t wait_for_key; +}; +typedef struct grub_efi_simple_input_interface grub_efi_simple_input_interface_t; + +struct grub_efi_key_data { + grub_efi_input_key_t key; + grub_efi_key_state_t key_state; +}; +typedef struct grub_efi_key_data grub_efi_key_data_t; + +typedef grub_efi_status_t (*grub_efi_key_notify_function_t) ( + grub_efi_key_data_t *key_data + ); + +struct grub_efi_simple_text_input_ex_interface +{ + grub_efi_status_t + (*reset) (struct grub_efi_simple_text_input_ex_interface *this, + grub_efi_boolean_t extended_verification); + + grub_efi_status_t + (*read_key_stroke) (struct grub_efi_simple_text_input_ex_interface *this, + grub_efi_key_data_t *key_data); + + grub_efi_event_t wait_for_key; + + grub_efi_status_t + (*set_state) (struct grub_efi_simple_text_input_ex_interface *this, + grub_efi_key_toggle_state_t *key_toggle_state); + + grub_efi_status_t + (*register_key_notify) (struct grub_efi_simple_text_input_ex_interface *this, + grub_efi_key_data_t *key_data, + grub_efi_key_notify_function_t key_notification_function); + + grub_efi_status_t + (*unregister_key_notify) (struct grub_efi_simple_text_input_ex_interface *this, + void *notification_handle); +}; +typedef struct grub_efi_simple_text_input_ex_interface grub_efi_simple_text_input_ex_interface_t; + +struct grub_efi_simple_text_output_interface +{ + grub_efi_status_t + (*reset) (struct grub_efi_simple_text_output_interface *this, + grub_efi_boolean_t extended_verification); + + grub_efi_status_t + (*output_string) (struct grub_efi_simple_text_output_interface *this, + grub_efi_char16_t *string); + + grub_efi_status_t + (*test_string) (struct grub_efi_simple_text_output_interface *this, + grub_efi_char16_t *string); + + grub_efi_status_t + (*query_mode) (struct grub_efi_simple_text_output_interface *this, + grub_efi_uintn_t mode_number, + grub_efi_uintn_t *columns, + grub_efi_uintn_t *rows); + + grub_efi_status_t + (*set_mode) (struct grub_efi_simple_text_output_interface *this, + grub_efi_uintn_t mode_number); + + grub_efi_status_t + (*set_attributes) (struct grub_efi_simple_text_output_interface *this, + grub_efi_uintn_t attribute); + + grub_efi_status_t + (*clear_screen) (struct grub_efi_simple_text_output_interface *this); + + grub_efi_status_t + (*set_cursor_position) (struct grub_efi_simple_text_output_interface *this, + grub_efi_uintn_t column, + grub_efi_uintn_t row); + + grub_efi_status_t + (*enable_cursor) (struct grub_efi_simple_text_output_interface *this, + grub_efi_boolean_t visible); + + grub_efi_simple_text_output_mode_t *mode; +}; +typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t; + +typedef grub_uint8_t grub_efi_pxe_packet_t[1472]; + +typedef struct grub_efi_pxe_mode +{ + grub_uint8_t unused[52]; + grub_efi_pxe_packet_t dhcp_discover; + grub_efi_pxe_packet_t dhcp_ack; + grub_efi_pxe_packet_t proxy_offer; + grub_efi_pxe_packet_t pxe_discover; + grub_efi_pxe_packet_t pxe_reply; +} grub_efi_pxe_mode_t; + +typedef struct grub_efi_pxe +{ + grub_uint64_t rev; + void (*start) (void); + void (*stop) (void); + void (*dhcp) (void); + void (*discover) (void); + void (*mftp) (void); + void (*udpwrite) (void); + void (*udpread) (void); + void (*setipfilter) (void); + void (*arp) (void); + void (*setparams) (void); + void (*setstationip) (void); + void (*setpackets) (void); + struct grub_efi_pxe_mode *mode; +} grub_efi_pxe_t; + +#define GRUB_EFI_BLACK 0x00 +#define GRUB_EFI_BLUE 0x01 +#define GRUB_EFI_GREEN 0x02 +#define GRUB_EFI_CYAN 0x03 +#define GRUB_EFI_RED 0x04 +#define GRUB_EFI_MAGENTA 0x05 +#define GRUB_EFI_BROWN 0x06 +#define GRUB_EFI_LIGHTGRAY 0x07 +#define GRUB_EFI_BRIGHT 0x08 +#define GRUB_EFI_DARKGRAY 0x08 +#define GRUB_EFI_LIGHTBLUE 0x09 +#define GRUB_EFI_LIGHTGREEN 0x0A +#define GRUB_EFI_LIGHTCYAN 0x0B +#define GRUB_EFI_LIGHTRED 0x0C +#define GRUB_EFI_LIGHTMAGENTA 0x0D +#define GRUB_EFI_YELLOW 0x0E +#define GRUB_EFI_WHITE 0x0F + +#define GRUB_EFI_BACKGROUND_BLACK 0x00 +#define GRUB_EFI_BACKGROUND_BLUE 0x10 +#define GRUB_EFI_BACKGROUND_GREEN 0x20 +#define GRUB_EFI_BACKGROUND_CYAN 0x30 +#define GRUB_EFI_BACKGROUND_RED 0x40 +#define GRUB_EFI_BACKGROUND_MAGENTA 0x50 +#define GRUB_EFI_BACKGROUND_BROWN 0x60 +#define GRUB_EFI_BACKGROUND_LIGHTGRAY 0x70 + +#define GRUB_EFI_TEXT_ATTR(fg, bg) ((fg) | ((bg))) + +struct grub_efi_system_table +{ + grub_efi_table_header_t hdr; + grub_efi_char16_t *firmware_vendor; + grub_efi_uint32_t firmware_revision; + grub_efi_handle_t console_in_handler; + grub_efi_simple_input_interface_t *con_in; + grub_efi_handle_t console_out_handler; + grub_efi_simple_text_output_interface_t *con_out; + grub_efi_handle_t standard_error_handle; + grub_efi_simple_text_output_interface_t *std_err; + grub_efi_runtime_services_t *runtime_services; + grub_efi_boot_services_t *boot_services; + grub_efi_uintn_t num_table_entries; + grub_efi_configuration_table_t *configuration_table; +}; +typedef struct grub_efi_system_table grub_efi_system_table_t; + +struct grub_efi_loaded_image +{ + grub_efi_uint32_t revision; + grub_efi_handle_t parent_handle; + grub_efi_system_table_t *system_table; + + grub_efi_handle_t device_handle; + grub_efi_device_path_t *file_path; + void *reserved; + + grub_efi_uint32_t load_options_size; + void *load_options; + + void *image_base; + grub_efi_uint64_t image_size; + grub_efi_memory_type_t image_code_type; + grub_efi_memory_type_t image_data_type; + + grub_efi_status_t (*unload) (grub_efi_handle_t image_handle); +}; +typedef struct grub_efi_loaded_image grub_efi_loaded_image_t; + +struct grub_efi_disk_io +{ + grub_efi_uint64_t revision; + grub_efi_status_t (*read) (struct grub_efi_disk_io *this, + grub_efi_uint32_t media_id, + grub_efi_uint64_t offset, + grub_efi_uintn_t buffer_size, + void *buffer); + grub_efi_status_t (*write) (struct grub_efi_disk_io *this, + grub_efi_uint32_t media_id, + grub_efi_uint64_t offset, + grub_efi_uintn_t buffer_size, + void *buffer); +}; +typedef struct grub_efi_disk_io grub_efi_disk_io_t; + +struct grub_efi_block_io_media +{ + grub_efi_uint32_t media_id; + grub_efi_boolean_t removable_media; + grub_efi_boolean_t media_present; + grub_efi_boolean_t logical_partition; + grub_efi_boolean_t read_only; + grub_efi_boolean_t write_caching; + grub_efi_uint8_t pad[3]; + grub_efi_uint32_t block_size; + grub_efi_uint32_t io_align; + grub_efi_uint8_t pad2[4]; + grub_efi_lba_t last_block; +}; +typedef struct grub_efi_block_io_media grub_efi_block_io_media_t; + +typedef grub_uint8_t grub_efi_mac_t[32]; + +struct grub_efi_simple_network_mode +{ + grub_uint32_t state; + grub_uint32_t hwaddr_size; + grub_uint32_t media_header_size; + grub_uint32_t max_packet_size; + grub_uint32_t nvram_size; + grub_uint32_t nvram_access_size; + grub_uint32_t receive_filter_mask; + grub_uint32_t receive_filter_setting; + grub_uint32_t max_mcast_filter_count; + grub_uint32_t mcast_filter_count; + grub_efi_mac_t mcast_filter[16]; + grub_efi_mac_t current_address; + grub_efi_mac_t broadcast_address; + grub_efi_mac_t permanent_address; + grub_uint8_t if_type; + grub_uint8_t mac_changeable; + grub_uint8_t multitx_supported; + grub_uint8_t media_present_supported; + grub_uint8_t media_present; +}; + +enum + { + GRUB_EFI_NETWORK_STOPPED, + GRUB_EFI_NETWORK_STARTED, + GRUB_EFI_NETWORK_INITIALIZED, + }; + +enum + { + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST = 0x01, + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST = 0x02, + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST = 0x04, + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS = 0x08, + GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST = 0x10, + }; + +struct grub_efi_simple_network +{ + grub_uint64_t revision; + grub_efi_status_t (*start) (struct grub_efi_simple_network *this); + grub_efi_status_t (*stop) (struct grub_efi_simple_network *this); + grub_efi_status_t (*initialize) (struct grub_efi_simple_network *this, + grub_efi_uintn_t extra_rx, + grub_efi_uintn_t extra_tx); + void (*reset) (void); + grub_efi_status_t (*shutdown) (struct grub_efi_simple_network *this); + grub_efi_status_t (*receive_filters) (struct grub_efi_simple_network *this, + grub_uint32_t enable, + grub_uint32_t disable, + grub_efi_boolean_t reset_mcast_filter, + grub_efi_uintn_t mcast_filter_count, + grub_efi_mac_address_t *mcast_filter); + void (*station_address) (void); + void (*statistics) (void); + void (*mcastiptomac) (void); + void (*nvdata) (void); + grub_efi_status_t (*get_status) (struct grub_efi_simple_network *this, + grub_uint32_t *int_status, + void **txbuf); + grub_efi_status_t (*transmit) (struct grub_efi_simple_network *this, + grub_efi_uintn_t header_size, + grub_efi_uintn_t buffer_size, + void *buffer, + grub_efi_mac_t *src_addr, + grub_efi_mac_t *dest_addr, + grub_efi_uint16_t *protocol); + grub_efi_status_t (*receive) (struct grub_efi_simple_network *this, + grub_efi_uintn_t *header_size, + grub_efi_uintn_t *buffer_size, + void *buffer, + grub_efi_mac_t *src_addr, + grub_efi_mac_t *dest_addr, + grub_uint16_t *protocol); + void (*waitforpacket) (void); + struct grub_efi_simple_network_mode *mode; +}; +typedef struct grub_efi_simple_network grub_efi_simple_network_t; + + +struct grub_efi_block_io +{ + grub_efi_uint64_t revision; + grub_efi_block_io_media_t *media; + grub_efi_status_t (*reset) (struct grub_efi_block_io *this, + grub_efi_boolean_t extended_verification); + grub_efi_status_t (*read_blocks) (struct grub_efi_block_io *this, + grub_efi_uint32_t media_id, + grub_efi_lba_t lba, + grub_efi_uintn_t buffer_size, + void *buffer); + grub_efi_status_t (*write_blocks) (struct grub_efi_block_io *this, + grub_efi_uint32_t media_id, + grub_efi_lba_t lba, + grub_efi_uintn_t buffer_size, + void *buffer); + grub_efi_status_t (*flush_blocks) (struct grub_efi_block_io *this); +}; +typedef struct grub_efi_block_io grub_efi_block_io_t; + +#if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined(__mips__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) + +#define efi_call_0(func) func() +#define efi_call_1(func, a) func(a) +#define efi_call_2(func, a, b) func(a, b) +#define efi_call_3(func, a, b, c) func(a, b, c) +#define efi_call_4(func, a, b, c, d) func(a, b, c, d) +#define efi_call_5(func, a, b, c, d, e) func(a, b, c, d, e) +#define efi_call_6(func, a, b, c, d, e, f) func(a, b, c, d, e, f) +#define efi_call_7(func, a, b, c, d, e, f, g) func(a, b, c, d, e, f, g) +#define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) func(a, b, c, d, e, f, g, h, i, j) + +#else + +#define efi_call_0(func) \ + efi_wrap_0(func) +#define efi_call_1(func, a) \ + efi_wrap_1(func, (grub_uint64_t) (a)) +#define efi_call_2(func, a, b) \ + efi_wrap_2(func, (grub_uint64_t) (a), (grub_uint64_t) (b)) +#define efi_call_3(func, a, b, c) \ + efi_wrap_3(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c)) +#define efi_call_4(func, a, b, c, d) \ + efi_wrap_4(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d)) +#define efi_call_5(func, a, b, c, d, e) \ + efi_wrap_5(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e)) +#define efi_call_6(func, a, b, c, d, e, f) \ + efi_wrap_6(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e), \ + (grub_uint64_t) (f)) +#define efi_call_7(func, a, b, c, d, e, f, g) \ + efi_wrap_7(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e), \ + (grub_uint64_t) (f), (grub_uint64_t) (g)) +#define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) \ + efi_wrap_10(func, (grub_uint64_t) (a), (grub_uint64_t) (b), \ + (grub_uint64_t) (c), (grub_uint64_t) (d), (grub_uint64_t) (e), \ + (grub_uint64_t) (f), (grub_uint64_t) (g), (grub_uint64_t) (h), \ + (grub_uint64_t) (i), (grub_uint64_t) (j)) + +grub_uint64_t EXPORT_FUNC(efi_wrap_0) (void *func); +grub_uint64_t EXPORT_FUNC(efi_wrap_1) (void *func, grub_uint64_t arg1); +grub_uint64_t EXPORT_FUNC(efi_wrap_2) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2); +grub_uint64_t EXPORT_FUNC(efi_wrap_3) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3); +grub_uint64_t EXPORT_FUNC(efi_wrap_4) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3, + grub_uint64_t arg4); +grub_uint64_t EXPORT_FUNC(efi_wrap_5) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3, + grub_uint64_t arg4, grub_uint64_t arg5); +grub_uint64_t EXPORT_FUNC(efi_wrap_6) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3, + grub_uint64_t arg4, grub_uint64_t arg5, + grub_uint64_t arg6); +grub_uint64_t EXPORT_FUNC(efi_wrap_7) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3, + grub_uint64_t arg4, grub_uint64_t arg5, + grub_uint64_t arg6, grub_uint64_t arg7); +grub_uint64_t EXPORT_FUNC(efi_wrap_10) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3, + grub_uint64_t arg4, grub_uint64_t arg5, + grub_uint64_t arg6, grub_uint64_t arg7, + grub_uint64_t arg8, grub_uint64_t arg9, + grub_uint64_t arg10); +#endif + +#endif /* ! GRUB_EFI_API_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/efi.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/efi.h new file mode 100644 index 0000000..14edcd9 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/efi.h @@ -0,0 +1,125 @@ +/* efi.h - declare variables and functions for EFI support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_EFI_EFI_HEADER +#define GRUB_EFI_EFI_HEADER 1 + +#include +#include +#include + +/* Functions. */ +void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_efi_guid_t *protocol, + void *registration); +grub_efi_handle_t * +EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type, + grub_efi_guid_t *protocol, + void *search_key, + grub_efi_uintn_t *num_handles); +void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + grub_efi_uint32_t attributes); +int EXPORT_FUNC(grub_efi_set_text_mode) (int on); +void EXPORT_FUNC(grub_efi_stall) (grub_efi_uintn_t microseconds); +void * +EXPORT_FUNC(grub_efi_allocate_pages_real) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages, + grub_efi_allocate_type_t alloctype, + grub_efi_memory_type_t memtype); +void * +EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages); +void * +EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages); +void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages); +grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void); +int +EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size, + grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version); +void grub_efi_memory_fini (void); +grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle); +void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp); +char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); +grub_efi_device_path_t * +EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle); +grub_efi_device_path_t * +EXPORT_FUNC(grub_efi_find_last_device_path) (const grub_efi_device_path_t *dp); +grub_efi_device_path_t * +EXPORT_FUNC(grub_efi_duplicate_device_path) (const grub_efi_device_path_t *dp); +grub_err_t EXPORT_FUNC (grub_efi_finish_boot_services) (grub_efi_uintn_t *outbuf_size, void *outbuf, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *efi_desc_size, + grub_efi_uint32_t *efi_desc_version); +grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memory_map_size, + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map); +void *EXPORT_FUNC (grub_efi_get_variable) (const char *variable, + const grub_efi_guid_t *guid, + grub_size_t *datasize_out); +grub_err_t +EXPORT_FUNC (grub_efi_set_variable) (const char *var, + const grub_efi_guid_t *guid, + void *data, + grub_size_t datasize); +int +EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1, + const grub_efi_device_path_t *dp2); + +void * EXPORT_FUNC (grub_efi_allocate_iso_buf) (grub_uint64_t size); +void * EXPORT_FUNC (grub_efi_allocate_chain_buf) (grub_uint64_t size); +void EXPORT_FUNC (grub_efi_get_reserved_page_num) (grub_uint64_t *total, grub_uint64_t *org_required, grub_uint64_t *new_required); + +extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, + char **device, + char **path); + +#if defined(__arm__) || defined(__aarch64__) || defined(__riscv) +void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); +grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); +#include +grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh); +grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, + char *args); +#endif + +grub_addr_t grub_efi_modules_addr (void); + +void grub_efi_mm_init (void); +void grub_efi_mm_fini (void); +void grub_efi_init (void); +void grub_efi_fini (void); +void grub_efi_set_prefix (void); + +/* Variables. */ +extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); +extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); + +extern int EXPORT_VAR(grub_efi_is_finished); + +struct grub_net_card; + +grub_efi_handle_t +grub_efinet_get_device_handle (struct grub_net_card *card); + +#endif /* ! GRUB_EFI_EFI_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/pe32.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/pe32.h new file mode 100644 index 0000000..230cf01 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/efi/pe32.h @@ -0,0 +1,339 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_EFI_PE32_HEADER +#define GRUB_EFI_PE32_HEADER 1 + +#include +#include + +/* The MSDOS compatibility stub. This was copied from the output of + objcopy, and it is not necessary to care about what this means. */ +#define GRUB_PE32_MSDOS_STUB \ + { \ + 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, \ + 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, \ + 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, \ + 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, \ + 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, \ + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, \ + 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, \ + 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, \ + 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, \ + 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, \ + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \ + } + +#define GRUB_PE32_MSDOS_STUB_SIZE 0x80 + +#define GRUB_PE32_MAGIC 0x5a4d + +/* According to the spec, the minimal alignment is 512 bytes... + But some examples (such as EFI drivers in the Intel + Sample Implementation) use 32 bytes (0x20) instead, and it seems + to be working. + + However, there is firmware showing up in the field now with + page alignment constraints to guarantee that page protection + bits take effect. Because currently existing GRUB code can not + properly distinguish between in-memory and in-file layout, let's + bump all alignment to GRUB_EFI_PAGE_SIZE. */ +#define GRUB_PE32_SECTION_ALIGNMENT GRUB_EFI_PAGE_SIZE +#define GRUB_PE32_FILE_ALIGNMENT GRUB_PE32_SECTION_ALIGNMENT + +struct grub_pe32_coff_header +{ + grub_uint16_t machine; + grub_uint16_t num_sections; + grub_uint32_t time; + grub_uint32_t symtab_offset; + grub_uint32_t num_symbols; + grub_uint16_t optional_header_size; + grub_uint16_t characteristics; +}; + +#define GRUB_PE32_MACHINE_I386 0x14c +#define GRUB_PE32_MACHINE_MIPS 0x166 +#define GRUB_PE32_MACHINE_IA64 0x200 +#define GRUB_PE32_MACHINE_X86_64 0x8664 +#define GRUB_PE32_MACHINE_ARMTHUMB_MIXED 0x01c2 +#define GRUB_PE32_MACHINE_ARM64 0xAA64 +#define GRUB_PE32_MACHINE_RISCV32 0x5032 +#define GRUB_PE32_MACHINE_RISCV64 0x5064 + +#define GRUB_PE32_RELOCS_STRIPPED 0x0001 +#define GRUB_PE32_EXECUTABLE_IMAGE 0x0002 +#define GRUB_PE32_LINE_NUMS_STRIPPED 0x0004 +#define GRUB_PE32_LOCAL_SYMS_STRIPPED 0x0008 +#define GRUB_PE32_AGGRESSIVE_WS_TRIM 0x0010 +#define GRUB_PE32_LARGE_ADDRESS_AWARE 0x0020 +#define GRUB_PE32_16BIT_MACHINE 0x0040 +#define GRUB_PE32_BYTES_REVERSED_LO 0x0080 +#define GRUB_PE32_32BIT_MACHINE 0x0100 +#define GRUB_PE32_DEBUG_STRIPPED 0x0200 +#define GRUB_PE32_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define GRUB_PE32_SYSTEM 0x1000 +#define GRUB_PE32_DLL 0x2000 +#define GRUB_PE32_UP_SYSTEM_ONLY 0x4000 +#define GRUB_PE32_BYTES_REVERSED_HI 0x8000 + +struct grub_pe32_data_directory +{ + grub_uint32_t rva; + grub_uint32_t size; +}; + +struct grub_pe32_optional_header +{ + grub_uint16_t magic; + grub_uint8_t major_linker_version; + grub_uint8_t minor_linker_version; + grub_uint32_t code_size; + grub_uint32_t data_size; + grub_uint32_t bss_size; + grub_uint32_t entry_addr; + grub_uint32_t code_base; + + grub_uint32_t data_base; + grub_uint32_t image_base; + + grub_uint32_t section_alignment; + grub_uint32_t file_alignment; + grub_uint16_t major_os_version; + grub_uint16_t minor_os_version; + grub_uint16_t major_image_version; + grub_uint16_t minor_image_version; + grub_uint16_t major_subsystem_version; + grub_uint16_t minor_subsystem_version; + grub_uint32_t reserved; + grub_uint32_t image_size; + grub_uint32_t header_size; + grub_uint32_t checksum; + grub_uint16_t subsystem; + grub_uint16_t dll_characteristics; + + grub_uint32_t stack_reserve_size; + grub_uint32_t stack_commit_size; + grub_uint32_t heap_reserve_size; + grub_uint32_t heap_commit_size; + + grub_uint32_t loader_flags; + grub_uint32_t num_data_directories; + + /* Data directories. */ + struct grub_pe32_data_directory export_table; + struct grub_pe32_data_directory import_table; + struct grub_pe32_data_directory resource_table; + struct grub_pe32_data_directory exception_table; + struct grub_pe32_data_directory certificate_table; + struct grub_pe32_data_directory base_relocation_table; + struct grub_pe32_data_directory debug; + struct grub_pe32_data_directory architecture; + struct grub_pe32_data_directory global_ptr; + struct grub_pe32_data_directory tls_table; + struct grub_pe32_data_directory load_config_table; + struct grub_pe32_data_directory bound_import; + struct grub_pe32_data_directory iat; + struct grub_pe32_data_directory delay_import_descriptor; + struct grub_pe32_data_directory com_runtime_header; + struct grub_pe32_data_directory reserved_entry; +}; + +struct grub_pe64_optional_header +{ + grub_uint16_t magic; + grub_uint8_t major_linker_version; + grub_uint8_t minor_linker_version; + grub_uint32_t code_size; + grub_uint32_t data_size; + grub_uint32_t bss_size; + grub_uint32_t entry_addr; + grub_uint32_t code_base; + + grub_uint64_t image_base; + + grub_uint32_t section_alignment; + grub_uint32_t file_alignment; + grub_uint16_t major_os_version; + grub_uint16_t minor_os_version; + grub_uint16_t major_image_version; + grub_uint16_t minor_image_version; + grub_uint16_t major_subsystem_version; + grub_uint16_t minor_subsystem_version; + grub_uint32_t reserved; + grub_uint32_t image_size; + grub_uint32_t header_size; + grub_uint32_t checksum; + grub_uint16_t subsystem; + grub_uint16_t dll_characteristics; + + grub_uint64_t stack_reserve_size; + grub_uint64_t stack_commit_size; + grub_uint64_t heap_reserve_size; + grub_uint64_t heap_commit_size; + + grub_uint32_t loader_flags; + grub_uint32_t num_data_directories; + + /* Data directories. */ + struct grub_pe32_data_directory export_table; + struct grub_pe32_data_directory import_table; + struct grub_pe32_data_directory resource_table; + struct grub_pe32_data_directory exception_table; + struct grub_pe32_data_directory certificate_table; + struct grub_pe32_data_directory base_relocation_table; + struct grub_pe32_data_directory debug; + struct grub_pe32_data_directory architecture; + struct grub_pe32_data_directory global_ptr; + struct grub_pe32_data_directory tls_table; + struct grub_pe32_data_directory load_config_table; + struct grub_pe32_data_directory bound_import; + struct grub_pe32_data_directory iat; + struct grub_pe32_data_directory delay_import_descriptor; + struct grub_pe32_data_directory com_runtime_header; + struct grub_pe32_data_directory reserved_entry; +}; + +#define GRUB_PE32_PE32_MAGIC 0x10b +#define GRUB_PE32_PE64_MAGIC 0x20b + +#define GRUB_PE32_SUBSYSTEM_EFI_APPLICATION 10 + +#define GRUB_PE32_NUM_DATA_DIRECTORIES 16 + +struct grub_pe32_section_table +{ + char name[8]; + grub_uint32_t virtual_size; + grub_uint32_t virtual_address; + grub_uint32_t raw_data_size; + grub_uint32_t raw_data_offset; + grub_uint32_t relocations_offset; + grub_uint32_t line_numbers_offset; + grub_uint16_t num_relocations; + grub_uint16_t num_line_numbers; + grub_uint32_t characteristics; +}; + +#define GRUB_PE32_SCN_CNT_CODE 0x00000020 +#define GRUB_PE32_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define GRUB_PE32_SCN_MEM_DISCARDABLE 0x02000000 +#define GRUB_PE32_SCN_MEM_EXECUTE 0x20000000 +#define GRUB_PE32_SCN_MEM_READ 0x40000000 +#define GRUB_PE32_SCN_MEM_WRITE 0x80000000 + +#define GRUB_PE32_SCN_ALIGN_1BYTES 0x00100000 +#define GRUB_PE32_SCN_ALIGN_2BYTES 0x00200000 +#define GRUB_PE32_SCN_ALIGN_4BYTES 0x00300000 +#define GRUB_PE32_SCN_ALIGN_8BYTES 0x00400000 +#define GRUB_PE32_SCN_ALIGN_16BYTES 0x00500000 +#define GRUB_PE32_SCN_ALIGN_32BYTES 0x00600000 +#define GRUB_PE32_SCN_ALIGN_64BYTES 0x00700000 + +#define GRUB_PE32_SCN_ALIGN_SHIFT 20 +#define GRUB_PE32_SCN_ALIGN_MASK 7 + +#define GRUB_PE32_SIGNATURE_SIZE 4 + +struct grub_pe32_header +{ + /* This should be filled in with GRUB_PE32_MSDOS_STUB. */ + grub_uint8_t msdos_stub[GRUB_PE32_MSDOS_STUB_SIZE]; + + /* This is always PE\0\0. */ + char signature[GRUB_PE32_SIGNATURE_SIZE]; + + /* The COFF file header. */ + struct grub_pe32_coff_header coff_header; + +#if GRUB_TARGET_SIZEOF_VOID_P == 8 + /* The Optional header. */ + struct grub_pe64_optional_header optional_header; +#else + /* The Optional header. */ + struct grub_pe32_optional_header optional_header; +#endif +}; + +struct grub_pe32_fixup_block +{ + grub_uint32_t page_rva; + grub_uint32_t block_size; + grub_uint16_t entries[0]; +}; + +#define GRUB_PE32_FIXUP_ENTRY(type, offset) (((type) << 12) | (offset)) + +#define GRUB_PE32_REL_BASED_ABSOLUTE 0 +#define GRUB_PE32_REL_BASED_HIGH 1 +#define GRUB_PE32_REL_BASED_LOW 2 +#define GRUB_PE32_REL_BASED_HIGHLOW 3 +#define GRUB_PE32_REL_BASED_HIGHADJ 4 +#define GRUB_PE32_REL_BASED_MIPS_JMPADDR 5 +#define GRUB_PE32_REL_BASED_MIPS_LOW 6 +#define GRUB_PE32_REL_BASED_MIPS_HIGH 4 +#define GRUB_PE32_REL_BASED_MIPS_HIGHER 7 +#define GRUB_PE32_REL_BASED_MIPS_HIGHEST 8 +#define GRUB_PE32_REL_BASED_ARM_MOV32A 5 +#define GRUB_PE32_REL_BASED_RISCV_HI20 5 +#define GRUB_PE32_REL_BASED_SECTION 6 +#define GRUB_PE32_REL_BASED_REL 7 +#define GRUB_PE32_REL_BASED_ARM_MOV32T 7 +#define GRUB_PE32_REL_BASED_RISCV_LOW12I 7 +#define GRUB_PE32_REL_BASED_RISCV_LOW12S 8 +#define GRUB_PE32_REL_BASED_IA64_IMM64 9 +#define GRUB_PE32_REL_BASED_DIR64 10 +#define GRUB_PE32_REL_BASED_HIGH3ADJ 11 + +struct grub_pe32_symbol +{ + union + { + char short_name[8]; + grub_uint32_t long_name[2]; + }; + + grub_uint32_t value; + grub_uint16_t section; + grub_uint16_t type; + grub_uint8_t storage_class; + grub_uint8_t num_aux; +} GRUB_PACKED; + +#define GRUB_PE32_SYM_CLASS_EXTERNAL 2 +#define GRUB_PE32_SYM_CLASS_STATIC 3 +#define GRUB_PE32_SYM_CLASS_FILE 0x67 + +#define GRUB_PE32_DT_FUNCTION 0x20 + +struct grub_pe32_reloc +{ + grub_uint32_t offset; + grub_uint32_t symtab_index; + grub_uint16_t type; +} GRUB_PACKED; + +#define GRUB_PE32_REL_I386_DIR32 0x6 +#define GRUB_PE32_REL_I386_REL32 0x14 + +#endif /* ! GRUB_EFI_PE32_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/env.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/env.h new file mode 100644 index 0000000..2a9f6fe --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/env.h @@ -0,0 +1,78 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,2006,2007,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_ENV_HEADER +#define GRUB_ENV_HEADER 1 + +#include +#include +#include +#include + +#define VTOY_SB_POLICY_BYPASS 0 +#define VTOY_SB_POLICY_CHECK 1 +extern grub_uint8_t EXPORT_VAR(g_sys_sb); +extern grub_uint8_t EXPORT_VAR(g_sb_policy); + +struct grub_env_var; + +typedef const char *(*grub_env_read_hook_t) (struct grub_env_var *var, + const char *val); +typedef char *(*grub_env_write_hook_t) (struct grub_env_var *var, + const char *val); + +struct grub_env_var +{ + char *name; + char *value; + grub_env_read_hook_t read_hook; + grub_env_write_hook_t write_hook; + struct grub_env_var *next; + struct grub_env_var **prevp; + struct grub_env_var *sorted_next; + int global; +}; + +grub_err_t EXPORT_FUNC(grub_env_set) (const char *name, const char *val); +const char *EXPORT_FUNC(grub_env_get) (const char *name); +void EXPORT_FUNC(grub_env_unset) (const char *name); +struct grub_env_var *EXPORT_FUNC(grub_env_update_get_sorted) (void); + +#define FOR_SORTED_ENV(var) for (var = grub_env_update_get_sorted (); var; var = var->sorted_next) + +grub_err_t EXPORT_FUNC(grub_register_variable_hook) (const char *name, + grub_env_read_hook_t read_hook, + grub_env_write_hook_t write_hook); +grub_err_t EXPORT_FUNC(grub_register_vtoy_menu_lang_hook) (grub_env_read_hook_t read_hook); + +grub_err_t grub_env_context_open (void); +grub_err_t grub_env_context_close (void); +grub_err_t EXPORT_FUNC(grub_env_export) (const char *name); + +void grub_env_unset_menu (void); +grub_menu_t grub_env_get_menu (void); +void grub_env_set_menu (grub_menu_t nmenu); + +grub_err_t +grub_env_extractor_open (int source); + +grub_err_t +grub_env_extractor_close (int source); + + +#endif /* ! GRUB_ENV_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/file.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/file.h new file mode 100644 index 0000000..9a14d6e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/file.h @@ -0,0 +1,251 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2007 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_FILE_HEADER +#define GRUB_FILE_HEADER 1 + +#include +#include +#include +#include +#include + +enum grub_file_type + { + GRUB_FILE_TYPE_NONE = 0, + /* GRUB module to be loaded. */ + GRUB_FILE_TYPE_GRUB_MODULE, + /* Loopback file to be represented as disk. */ + GRUB_FILE_TYPE_LOOPBACK, + /* Linux kernel to be loaded. */ + GRUB_FILE_TYPE_LINUX_KERNEL, + /* Linux initrd. */ + GRUB_FILE_TYPE_LINUX_INITRD, + + /* Multiboot kernel. */ + GRUB_FILE_TYPE_MULTIBOOT_KERNEL, + /* Multiboot module. */ + GRUB_FILE_TYPE_MULTIBOOT_MODULE, + + /* Xen hypervisor - used on ARM only. */ + GRUB_FILE_TYPE_XEN_HYPERVISOR, + /* Xen module - used on ARM only. */ + GRUB_FILE_TYPE_XEN_MODULE, + + GRUB_FILE_TYPE_BSD_KERNEL, + GRUB_FILE_TYPE_FREEBSD_ENV, + GRUB_FILE_TYPE_FREEBSD_MODULE, + GRUB_FILE_TYPE_FREEBSD_MODULE_ELF, + GRUB_FILE_TYPE_NETBSD_MODULE, + GRUB_FILE_TYPE_OPENBSD_RAMDISK, + + GRUB_FILE_TYPE_XNU_INFO_PLIST, + GRUB_FILE_TYPE_XNU_MKEXT, + GRUB_FILE_TYPE_XNU_KEXT, + GRUB_FILE_TYPE_XNU_KERNEL, + GRUB_FILE_TYPE_XNU_RAMDISK, + GRUB_FILE_TYPE_XNU_HIBERNATE_IMAGE, + GRUB_FILE_XNU_DEVPROP, + + GRUB_FILE_TYPE_PLAN9_KERNEL, + + GRUB_FILE_TYPE_NTLDR, + GRUB_FILE_TYPE_TRUECRYPT, + GRUB_FILE_TYPE_FREEDOS, + GRUB_FILE_TYPE_PXECHAINLOADER, + GRUB_FILE_TYPE_PCCHAINLOADER, + + GRUB_FILE_TYPE_COREBOOT_CHAINLOADER, + + GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE, + + /* File holding signature. */ + GRUB_FILE_TYPE_SIGNATURE, + /* File holding public key to verify signature once. */ + GRUB_FILE_TYPE_PUBLIC_KEY, + /* File holding public key to add to trused keys. */ + GRUB_FILE_TYPE_PUBLIC_KEY_TRUST, + /* File of which we intend to print a blocklist to the user. */ + GRUB_FILE_TYPE_PRINT_BLOCKLIST, + /* File we intend to use for test loading or testing speed. */ + GRUB_FILE_TYPE_TESTLOAD, + /* File we open only to get its size. E.g. in ls output. */ + GRUB_FILE_TYPE_GET_SIZE, + /* Font file. */ + GRUB_FILE_TYPE_FONT, + /* File holding encryption key for encrypted ZFS. */ + GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY, + /* File we open n grub-fstest. */ + GRUB_FILE_TYPE_FSTEST, + /* File we open n grub-mount. */ + GRUB_FILE_TYPE_MOUNT, + /* File which we attempt to identify the type of. */ + GRUB_FILE_TYPE_FILE_ID, + /* File holding ACPI table. */ + GRUB_FILE_TYPE_ACPI_TABLE, + /* File holding Device Tree. */ + GRUB_FILE_TYPE_DEVICE_TREE_IMAGE, + /* File we intend show to user. */ + GRUB_FILE_TYPE_CAT, + GRUB_FILE_TYPE_HEXCAT, + /* One of pair of files we intend to compare. */ + GRUB_FILE_TYPE_CMP, + /* List of hashes for hashsum. */ + GRUB_FILE_TYPE_HASHLIST, + /* File hashed by hashsum. */ + GRUB_FILE_TYPE_TO_HASH, + /* Keyboard layout. */ + GRUB_FILE_TYPE_KEYBOARD_LAYOUT, + /* Picture file. */ + GRUB_FILE_TYPE_PIXMAP, + /* *.lst shipped by GRUB. */ + GRUB_FILE_TYPE_GRUB_MODULE_LIST, + /* config file. */ + GRUB_FILE_TYPE_CONFIG, + GRUB_FILE_TYPE_THEME, + GRUB_FILE_TYPE_GETTEXT_CATALOG, + GRUB_FILE_TYPE_FS_SEARCH, + GRUB_FILE_TYPE_AUDIO, + GRUB_FILE_TYPE_VBE_DUMP, + + GRUB_FILE_TYPE_LOADENV, + GRUB_FILE_TYPE_SAVEENV, + + GRUB_FILE_TYPE_VERIFY_SIGNATURE, + + GRUB_FILE_TYPE_MASK = 0xffff, + + /* --skip-sig is specified. */ + GRUB_FILE_TYPE_SKIP_SIGNATURE = 0x10000, + GRUB_FILE_TYPE_NO_DECOMPRESS = 0x20000, + GRUB_FILE_TYPE_NO_VLNK = 0x40000, + }; + +/* File description. */ +struct grub_file +{ + /* File name. */ + char *name; + + int vlnk; + + /* The underlying device. */ + grub_device_t device; + + /* The underlying filesystem. */ + grub_fs_t fs; + + /* The current offset. */ + grub_off_t offset; + grub_off_t progress_offset; + + /* Progress info. */ + grub_uint64_t last_progress_time; + grub_off_t last_progress_offset; + grub_uint64_t estimated_speed; + + /* The file size. */ + grub_off_t size; + + /* If file is not easily seekable. Should be set by underlying layer. */ + int not_easily_seekable; + + /* Filesystem-specific data. */ + void *data; + + /* This is called when a sector is read. Used only for a disk device. */ + grub_disk_read_hook_t read_hook; + + /* Caller-specific data passed to the read hook. */ + void *read_hook_data; +}; +typedef struct grub_file *grub_file_t; + +extern grub_disk_read_hook_t EXPORT_VAR(grub_file_progress_hook); + +/* Filters with lower ID are executed first. */ +typedef enum grub_file_filter_id + { + GRUB_FILE_FILTER_VERIFY, + GRUB_FILE_FILTER_GZIO, + GRUB_FILE_FILTER_XZIO, + GRUB_FILE_FILTER_LZOPIO, + GRUB_FILE_FILTER_MAX, + GRUB_FILE_FILTER_COMPRESSION_FIRST = GRUB_FILE_FILTER_GZIO, + GRUB_FILE_FILTER_COMPRESSION_LAST = GRUB_FILE_FILTER_LZOPIO, + } grub_file_filter_id_t; + +typedef grub_file_t (*grub_file_filter_t) (grub_file_t in, enum grub_file_type type); + +extern grub_file_filter_t EXPORT_VAR(grub_file_filters)[GRUB_FILE_FILTER_MAX]; + +static inline void +grub_file_filter_register (grub_file_filter_id_t id, grub_file_filter_t filter) +{ + grub_file_filters[id] = filter; +} + +static inline void +grub_file_filter_unregister (grub_file_filter_id_t id) +{ + grub_file_filters[id] = 0; +} + +/* Get a device name from NAME. */ +char *EXPORT_FUNC(grub_file_get_device_name) (const char *name); + +int EXPORT_FUNC(ventoy_check_file_exist) (const char * fmt, ...); +grub_file_t EXPORT_FUNC(grub_file_open) (const char *name, enum grub_file_type type); +grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf, + grub_size_t len); +grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset); +grub_err_t EXPORT_FUNC(grub_file_close) (grub_file_t file); + +int EXPORT_FUNC(grub_file_is_vlnk_suffix)(const char *name, int len); +int EXPORT_FUNC(grub_file_add_vlnk)(const char *src, const char *dst); +int EXPORT_FUNC(grub_file_vtoy_vlnk)(const char *src, const char *dst); +const char * EXPORT_FUNC(grub_file_get_vlnk)(const char *name, int *vlnk); + +/* Return value of grub_file_size() in case file size is unknown. */ +#define GRUB_FILE_SIZE_UNKNOWN 0xffffffffffffffffULL + +static inline grub_off_t +grub_file_size (const grub_file_t file) +{ + return file->size; +} + +static inline grub_off_t +grub_file_tell (const grub_file_t file) +{ + return file->offset; +} + +static inline int +grub_file_seekable (const grub_file_t file) +{ + return !file->not_easily_seekable; +} + +grub_file_t +grub_file_offset_open (grub_file_t parent, enum grub_file_type type, + grub_off_t start, grub_off_t size); +void +grub_file_offset_close (grub_file_t file); + +#endif /* ! GRUB_FILE_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/fs.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/fs.h new file mode 100644 index 0000000..18ef824 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/fs.h @@ -0,0 +1,133 @@ +/* fs.h - filesystem manager */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_FS_HEADER +#define GRUB_FS_HEADER 1 + +#include +#include +#include + +#include +/* For embedding types. */ +#ifdef GRUB_UTIL +#include +#endif + +/* Forward declaration is required, because of mutual reference. */ +struct grub_file; + +struct grub_dirhook_info +{ + unsigned dir:1; + unsigned mtimeset:1; + unsigned case_insensitive:1; + unsigned inodeset:1; + grub_int32_t mtime; + grub_uint64_t inode; + grub_uint64_t size; +}; + +typedef int (*grub_fs_dir_hook_t) (const char *filename, + const struct grub_dirhook_info *info, + void *data); + +/* Filesystem descriptor. */ +struct grub_fs +{ + /* The next filesystem. */ + struct grub_fs *next; + struct grub_fs **prev; + + /* My name. */ + const char *name; + + /* Call HOOK with each file under DIR. */ + grub_err_t (*fs_dir) (grub_device_t device, const char *path, + grub_fs_dir_hook_t hook, void *hook_data); + + /* Open a file named NAME and initialize FILE. */ + grub_err_t (*fs_open) (struct grub_file *file, const char *name); + + /* Read LEN bytes data from FILE into BUF. */ + grub_ssize_t (*fs_read) (struct grub_file *file, char *buf, grub_size_t len); + + /* Close the file FILE. */ + grub_err_t (*fs_close) (struct grub_file *file); + + /* Return the label of the device DEVICE in LABEL. The label is + returned in a grub_malloc'ed buffer and should be freed by the + caller. */ + grub_err_t (*fs_label) (grub_device_t device, char **label); + + /* Return the uuid of the device DEVICE in UUID. The uuid is + returned in a grub_malloc'ed buffer and should be freed by the + caller. */ + grub_err_t (*fs_uuid) (grub_device_t device, char **uuid); + + /* Get writing time of filesystem. */ + grub_err_t (*fs_mtime) (grub_device_t device, grub_int32_t *timebuf); + +#ifdef GRUB_UTIL + /* Determine sectors available for embedding. */ + grub_err_t (*fs_embed) (grub_device_t device, unsigned int *nsectors, + unsigned int max_nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors); + + /* Whether this filesystem reserves first sector for DOS-style boot. */ + int reserved_first_sector; + + /* Whether blocklist installs have a chance to work. */ + int blocklist_install; +#endif +}; +typedef struct grub_fs *grub_fs_t; + +/* This is special, because block lists are not files in usual sense. */ +extern struct grub_fs grub_fs_blocklist; + +/* This hook is used to automatically load filesystem modules. + If this hook loads a module, return non-zero. Otherwise return zero. + The newly loaded filesystem is assumed to be inserted into the head of + the linked list GRUB_FS_LIST through the function grub_fs_register. */ +typedef int (*grub_fs_autoload_hook_t) (void); +extern grub_fs_autoload_hook_t EXPORT_VAR(grub_fs_autoload_hook); +extern grub_fs_t EXPORT_VAR (grub_fs_list); + +#ifndef GRUB_LST_GENERATOR +static inline void +grub_fs_register (grub_fs_t fs) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_fs_list), GRUB_AS_LIST (fs)); +} +#endif + +static inline void +grub_fs_unregister (grub_fs_t fs) +{ + grub_list_remove (GRUB_AS_LIST (fs)); +} + +#define FOR_FILESYSTEMS(var) FOR_LIST_ELEMENTS((var), (grub_fs_list)) + +grub_fs_t EXPORT_FUNC(grub_fs_probe) (grub_device_t device); +grub_fs_t EXPORT_FUNC(grub_fs_list_probe) (grub_device_t device, const char **list); + +#endif /* ! GRUB_FS_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/gfxmenu_view.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/gfxmenu_view.h new file mode 100644 index 0000000..aec33a3 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/gfxmenu_view.h @@ -0,0 +1,128 @@ +/* gfxmenu_view.h - gfxmenu view interface. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_GFXMENU_VIEW_HEADER +#define GRUB_GFXMENU_VIEW_HEADER 1 + +#include +#include +#include +#include +#include + +struct grub_gfxmenu_view; /* Forward declaration of opaque type. */ +typedef struct grub_gfxmenu_view *grub_gfxmenu_view_t; + + +grub_gfxmenu_view_t grub_gfxmenu_view_new (const char *theme_path, + int width, int height); + +void grub_gfxmenu_view_destroy (grub_gfxmenu_view_t view); + +/* Set properties on the view based on settings from the specified + theme file. */ +grub_err_t grub_gfxmenu_view_load_theme (grub_gfxmenu_view_t view, + const char *theme_path); + +grub_err_t grub_gui_recreate_box (grub_gfxmenu_box_t *boxptr, + const char *pattern, const char *theme_dir); + +void grub_gfxmenu_view_draw (grub_gfxmenu_view_t view); + +void +grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view); + +void +grub_gfxmenu_redraw_timeout (grub_gfxmenu_view_t view); + +void +grub_gfxmenu_view_redraw (grub_gfxmenu_view_t view, + const grub_video_rect_t *region); + +void +grub_gfxmenu_clear_timeout (void *data); +void +grub_gfxmenu_print_timeout (int timeout, void *data); +void +grub_gfxmenu_set_chosen_entry (int entry, void *data); +void +grub_gfxmenu_scroll_chosen_entry (void *data, int diren); + +grub_err_t grub_font_draw_string (const char *str, + grub_font_t font, + grub_video_color_t color, + int left_x, int baseline_y); +int grub_font_get_string_width (grub_font_t font, + const char *str); + + +/* Implementation details -- this should not be used outside of the + view itself. */ + +#include +#include +#include +#include +#include +#include + +/* Definition of the private representation of the view. */ +struct grub_gfxmenu_view +{ + grub_video_rect_t screen; + + int need_to_check_sanity; + grub_video_rect_t terminal_rect; + int terminal_border; + + grub_font_t title_font; + grub_font_t message_font; + char *terminal_font_name; + grub_video_rgba_color_t title_color; + grub_video_rgba_color_t message_color; + grub_video_rgba_color_t message_bg_color; + struct grub_video_bitmap *raw_desktop_image; + struct grub_video_bitmap *scaled_desktop_image; + grub_video_bitmap_selection_method_t desktop_image_scale_method; + grub_video_bitmap_h_align_t desktop_image_h_align; + grub_video_bitmap_v_align_t desktop_image_v_align; + grub_video_rgba_color_t desktop_color; + grub_gfxmenu_box_t terminal_box; + char *title_text; + char *progress_message_text; + char *theme_path; + + grub_gui_container_t canvas; + + int double_repaint; + + int selected; + + grub_video_rect_t progress_message_frame; + + grub_menu_t menu; + + int nested; + + int first_timeout; + + int *menu_title_offset; +}; + +#endif /* ! GRUB_GFXMENU_VIEW_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/kernel.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/kernel.h new file mode 100644 index 0000000..dd9d205 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/kernel.h @@ -0,0 +1,133 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_KERNEL_HEADER +#define GRUB_KERNEL_HEADER 1 + +#include +#include + +enum +{ + OBJ_TYPE_ELF, + OBJ_TYPE_MEMDISK, + OBJ_TYPE_CONFIG, + OBJ_TYPE_PREFIX, + OBJ_TYPE_PUBKEY, + OBJ_TYPE_DTB +}; + +/* The module header. */ +struct grub_module_header +{ + /* The type of object. */ + grub_uint32_t type; + /* The size of object (including this header). */ + grub_uint32_t size; +}; + +/* "gmim" (GRUB Module Info Magic). */ +#define GRUB_MODULE_MAGIC 0x676d696d + +struct grub_module_info32 +{ + /* Magic number so we know we have modules present. */ + grub_uint32_t magic; + /* The offset of the modules. */ + grub_uint32_t offset; + /* The size of all modules plus this header. */ + grub_uint32_t size; +}; + +struct grub_module_info64 +{ + /* Magic number so we know we have modules present. */ + grub_uint32_t magic; + grub_uint32_t padding; + /* The offset of the modules. */ + grub_uint64_t offset; + /* The size of all modules plus this header. */ + grub_uint64_t size; +}; + +#ifndef GRUB_UTIL +/* Space isn't reusable on some platforms. */ +/* On Qemu the preload space is readonly. */ +/* On emu there is no preload space. */ +/* On ieee1275 our code assumes that heap is p=v which isn't guaranteed for module space. */ +#if defined (GRUB_MACHINE_QEMU) || defined (GRUB_MACHINE_EMU) \ + || defined (GRUB_MACHINE_EFI) \ + || (defined (GRUB_MACHINE_IEEE1275) && !defined (__sparc__)) +#define GRUB_KERNEL_PRELOAD_SPACE_REUSABLE 0 +#endif + +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) \ + || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) \ + || defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_ARC) \ + || (defined (__sparc__) && defined (GRUB_MACHINE_IEEE1275)) \ + || defined (GRUB_MACHINE_UBOOT) || defined (GRUB_MACHINE_XEN) \ + || defined(GRUB_MACHINE_XEN_PVH) +/* FIXME: stack is between 2 heap regions. Move it. */ +#define GRUB_KERNEL_PRELOAD_SPACE_REUSABLE 1 +#endif + +#ifndef GRUB_KERNEL_PRELOAD_SPACE_REUSABLE +#error "Please check if preload space is reusable on this platform!" +#endif + +#if GRUB_TARGET_SIZEOF_VOID_P == 8 +#define grub_module_info grub_module_info64 +#else +#define grub_module_info grub_module_info32 +#endif + +extern grub_addr_t EXPORT_VAR (grub_modbase); + +void EXPORT_FUNC(ventoy_env_hook_root)(int hook); + +#define FOR_MODULES(var) for (\ + var = (grub_modbase && ((((struct grub_module_info *) grub_modbase)->magic) == GRUB_MODULE_MAGIC)) ? (struct grub_module_header *) \ + (grub_modbase + (((struct grub_module_info *) grub_modbase)->offset)) : 0;\ + var && (grub_addr_t) var \ + < (grub_modbase + (((struct grub_module_info *) grub_modbase)->size)); \ + var = (struct grub_module_header *) \ + (((grub_uint32_t *) var) + ((((struct grub_module_header *) var)->size + sizeof (grub_addr_t) - 1) / sizeof (grub_addr_t)) * (sizeof (grub_addr_t) / sizeof (grub_uint32_t)))) + +grub_addr_t grub_modules_get_end (void); + +#endif + +/* The start point of the C code. */ +void grub_main (void) __attribute__ ((noreturn)); + +/* The machine-specific initialization. This must initialize memory. */ +void grub_machine_init (void); + +/* The machine-specific finalization. */ +void EXPORT_FUNC(grub_machine_fini) (int flags); + +/* The machine-specific prefix initialization. */ +void +grub_machine_get_bootlocation (char **device, char **path); + +/* Register all the exported symbols. This is automatically generated. */ +void grub_register_exported_symbols (void); + +extern void (*EXPORT_VAR(grub_net_poll_cards_idle)) (void); + +#endif /* ! GRUB_KERNEL_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/menu.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/menu.h new file mode 100644 index 0000000..11484d9 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/menu.h @@ -0,0 +1,119 @@ +/* menu.h - Menu model function prototypes and data structures. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_MENU_HEADER +#define GRUB_MENU_HEADER 1 + +struct bls_entry +{ + struct bls_entry *next; + struct bls_entry *prev; + struct keyval **keyvals; + int nkeyvals; + char *filename; + int visible; +}; + +struct grub_menu_entry_class +{ + char *name; + struct grub_menu_entry_class *next; +}; + +/* The menu entry. */ +struct grub_menu_entry +{ + /* The title name. */ + const char *title; + + /* The identifier. */ + const char *id; + + /* If set means not everybody is allowed to boot this entry. */ + int restricted; + + /* Allowed users. */ + const char *users; + + /* The classes associated with the menu entry: + used to choose an icon or other style attributes. + This is a dummy head node for the linked list, so for an entry E, + E.classes->next is the first class if it is not NULL. */ + struct grub_menu_entry_class *classes; + + /* The sourcecode of the menu entry, used by the editor. */ + const char *sourcecode; + + /* Parameters to be passed to menu definition. */ + int argc; + char **args; + + int hotkey; + + int submenu; + + /* The next element. */ + struct grub_menu_entry *next; + + /* BLS used to populate the entry */ + struct bls_entry *bls; +}; +typedef struct grub_menu_entry *grub_menu_entry_t; + +/* The menu. */ +struct grub_menu +{ + /* The size of a menu. */ + int size; + + /* The list of menu entries. */ + grub_menu_entry_t entry_list; +}; +typedef struct grub_menu *grub_menu_t; + +/* Callback structure menu viewers can use to provide user feedback when + default entries are executed, possibly including fallback entries. */ +typedef struct grub_menu_execute_callback +{ + /* Called immediately before ENTRY is booted. */ + void (*notify_booting) (grub_menu_entry_t entry, void *userdata); + + /* Called when executing one entry has failed, and another entry, ENTRY, will + be executed as a fallback. The implementation of this function should + delay for a period of at least 2 seconds before returning in order to + allow the user time to read the information before it can be lost by + executing ENTRY. */ + void (*notify_fallback) (grub_menu_entry_t entry, void *userdata); + + /* Called when an entry has failed to execute and there is no remaining + fallback entry to attempt. */ + void (*notify_failure) (void *userdata); +} +*grub_menu_execute_callback_t; + +grub_menu_entry_t grub_menu_get_entry (grub_menu_t menu, int no); +int grub_menu_get_timeout (void); +void grub_menu_set_timeout (int timeout); +void grub_menu_entry_run (grub_menu_entry_t entry); +int grub_menu_get_default_entry_index (grub_menu_t menu); + +void grub_menu_init (void); +void grub_menu_fini (void); + +#endif /* GRUB_MENU_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/menu_viewer.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/menu_viewer.h new file mode 100644 index 0000000..4016194 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/menu_viewer.h @@ -0,0 +1,49 @@ +/* menu_viewer.h - Interface to menu viewer implementations. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_MENU_VIEWER_HEADER +#define GRUB_MENU_VIEWER_HEADER 1 + +#include +#include +#include +#include +#include + +struct grub_menu_viewer +{ + struct grub_menu_viewer *next; + void *data; + void (*set_chosen_entry) (int entry, void *data); + void (*scroll_chosen_entry) (void *data, int diren); + void (*print_timeout) (int timeout, void *data); + void (*clear_timeout) (void *data); + void (*fini) (void *fini); +}; + +void grub_menu_register_viewer (struct grub_menu_viewer *viewer); + +grub_err_t +grub_menu_try_text (struct grub_term_output *term, + int entry, grub_menu_t menu, int nested); + +extern grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, + int nested); + +#endif /* GRUB_MENU_VIEWER_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/asm.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/asm.h new file mode 100644 index 0000000..8c5aae0 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/asm.h @@ -0,0 +1,10 @@ +#ifndef GRUB_MIPS64_ASM_HEADER +#define GRUB_MIPS64_ASM_HEADER 1 + +#define GRUB_ASM_T4 $a4 +#define GRUB_ASM_T5 $a5 +#define GRUB_ASM_SZREG 8 +#define GRUB_ASM_REG_S sd +#define GRUB_ASM_REG_L ld + +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/boot.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/boot.h new file mode 100644 index 0000000..e69de29 diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/loader.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/loader.h new file mode 100644 index 0000000..b1927bb --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/loader.h @@ -0,0 +1,25 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2006,2007,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_LOADER_MACHINE_HEADER +#define GRUB_LOADER_MACHINE_HEADER 1 + +#include +#include + +#endif /* ! GRUB_LOADER_MACHINE_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/loongson.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/loongson.h new file mode 100644 index 0000000..80de37e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/loongson.h @@ -0,0 +1,303 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_EFI_LOONGSON_HEADER +#define GRUB_EFI_LOONGSON_HEADER 1 + +#include + +#include + +#define GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID \ + { 0x4660f721, 0x2ec5, 0x416a, \ + { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \ + } + +#define GRUB_EFI_LOONGSON_MMAP_MAX 128 +typedef enum + { + GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW = 1, + GRUB_EFI_LOONGSON_SYSTEM_RAM_HIGH, + GRUB_EFI_LOONGSON_MEMORY_RESERVED, + GRUB_EFI_LOONGSON_PCI_IO, + GRUB_EFI_LOONGSON_PCI_MEM, + GRUB_EFI_LOONGSON_CFG_REG, + GRUB_EFI_LOONGSON_VIDEO_ROM, + GRUB_EFI_LOONGSON_ADAPTER_ROM, + GRUB_EFI_LOONGSON_ACPI_TABLE, + GRUB_EFI_LOONGSON_SMBIOS_TABLE, + GRUB_EFI_LOONGSON_UMA_VIDEO_RAM, + GRUB_EFI_LOONGSON_VUMA_VIDEO_RAM, + GRUB_EFI_LOONGSON_SYSTEM_RAM_LOW_DMA, + GRUB_EFI_LOONGSON_SYSTEM_RAM_HIGH_DMA, + GRUB_EFI_LOONGSON_ACPI_NVS, + GRUB_EFI_LOONGSON_MAX_MEMORY_TYPE + } +grub_efi_loongson_memory_type; + +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint32_t nr_map; /* number of memory_maps */ + grub_uint32_t mem_freq; /* memory frequence */ + struct mem_map { + grub_uint32_t node_id; /* node_id which memory attached to */ + grub_uint32_t mem_type; /* system memory, pci memory, pci io, etc. */ + grub_uint64_t mem_start; /* memory map start address */ + grub_uint32_t mem_size; /* each memory_map size, not the total size */ + } map[GRUB_EFI_LOONGSON_MMAP_MAX]; +} GRUB_PACKED +grub_efi_loongson_memory_map; + +/* + * Capability and feature descriptor structure for MIPS CPU + */ +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint32_t processor_id; /* PRID, e.g. 6305, 6306 */ + grub_uint32_t cputype; /* Loongson_3A/3B, etc. */ + grub_uint32_t total_node; /* num of total numa nodes */ + grub_uint16_t cpu_startup_core_id; /* Boot core id */ + grub_uint16_t reserved_cores_mask; + grub_uint32_t cpu_clock_freq; /* cpu_clock */ + grub_uint32_t nr_cpus; +} GRUB_PACKED +grub_efi_loongson_cpu_info; + +#define GRUB_EFI_LOONGSON_MAX_UARTS 64 + +typedef struct +{ + grub_uint32_t iotype; /* see include/linux/serial_core.h */ + grub_uint32_t uartclk; + grub_uint32_t int_offset; + grub_uint64_t uart_base; +} GRUB_PACKED +grub_efi_loongson_uart_device; + +#define GRUB_EFI_LOONGSON_MAX_SENSORS 64 + +typedef struct +{ + char name[32]; /* a formal name */ + char label[64]; /* a flexible description */ + grub_uint32_t type; /* SENSOR_* */ + grub_uint32_t id; /* instance id of a sensor-class */ + grub_uint32_t fan_policy; + grub_uint32_t fan_percent; /* only for constant speed policy */ + grub_uint64_t base_addr; /* base address of device registers */ +} GRUB_PACKED +grub_efi_loongson_sensor_device; + +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint32_t ccnuma_smp; /* 0: no numa; 1: has numa */ + grub_uint32_t sing_double_channel; /* 1:single; 2:double */ + grub_uint32_t nr_uarts; + grub_efi_loongson_uart_device uarts[GRUB_EFI_LOONGSON_MAX_UARTS]; + grub_uint32_t nr_sensors; + grub_efi_loongson_sensor_device sensors[GRUB_EFI_LOONGSON_MAX_SENSORS]; + char has_ec; + char ec_name[32]; + grub_uint64_t ec_base_addr; + char has_tcm; + char tcm_name[32]; + grub_uint64_t tcm_base_addr; + grub_uint64_t workarounds; /* see workarounds.h */ +} GRUB_PACKED +grub_efi_loongson_system_info; + +typedef struct +{ + grub_uint16_t vers; + grub_uint16_t size; + grub_uint16_t rtr_bus; + grub_uint16_t rtr_devfn; + grub_uint32_t vendor; + grub_uint32_t device; + grub_uint32_t PIC_type; /* conform use HT or PCI to route to CPU-PIC */ + grub_uint64_t ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ + grub_uint64_t ht_enable; /* irqs used in this PIC */ + grub_uint32_t node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ + grub_uint64_t pci_mem_start_addr; + grub_uint64_t pci_mem_end_addr; + grub_uint64_t pci_io_start_addr; + grub_uint64_t pci_io_end_addr; + grub_uint64_t pci_config_addr; + grub_uint32_t dma_mask_bits; +} GRUB_PACKED +grub_efi_loongson_irq_src_routing_table; + +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint16_t size; + grub_uint8_t flag; + char description[64]; +} GRUB_PACKED +grub_efi_loongson_interface_info; + +#define GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER 128 + +typedef struct +{ + grub_uint64_t start; /* resource start address */ + grub_uint64_t end; /* resource end address */ + char name[64]; + grub_uint32_t flags; +} +grub_efi_loongson_resource; + +/* arch specific additions */ +typedef struct +{ +} +grub_efi_loongson_archdev_data; + +typedef struct +{ + char name[64]; /* hold the device name */ + grub_uint32_t num_resources; /* number of device_resource */ + /* for each device's resource */ + grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; + /* arch specific additions */ + grub_efi_loongson_archdev_data archdata; +} +grub_efi_loongson_board_devices; + +typedef struct +{ + grub_uint16_t vers; /* version */ + char special_name[64]; /* special_atribute_name */ + grub_uint32_t loongson_special_type; /* type of special device */ + /* for each device's resource */ + grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; +} +grub_efi_loongson_special_attribute; + +typedef struct +{ + grub_uint64_t memory_offset; /* efi_loongson_memory_map struct offset */ + grub_uint64_t cpu_offset; /* efi_loongson_cpuinfo struct offset */ + grub_uint64_t system_offset; /* efi_loongson_system_info struct offset */ + grub_uint64_t irq_offset; /* efi_loongson_irq_src_routing_table struct offset */ + grub_uint64_t interface_offset; /* interface_info struct offset */ + grub_uint64_t special_offset; /* efi_loongson_special_attribute struct offset */ + grub_uint64_t boarddev_table_offset; /* efi_loongson_board_devices offset */ +} +grub_efi_loongson_params; + +typedef struct +{ + grub_uint16_t vers; /* version */ + grub_uint64_t vga_bios; /* vga_bios address */ + grub_efi_loongson_params lp; +} +grub_efi_loongson_smbios_table; + +typedef struct +{ + grub_uint64_t reset_cold; + grub_uint64_t reset_warm; + grub_uint64_t reset_type; + grub_uint64_t shutdown; + grub_uint64_t do_suspend; /* NULL if not support */ +} +grub_efi_loongson_reset_system; + +typedef struct +{ + grub_uint64_t mps; /* MPS table */ + grub_uint64_t acpi; /* ACPI table (IA64 ext 0.71) */ + grub_uint64_t acpi20; /* ACPI table (ACPI 2.0) */ + grub_efi_loongson_smbios_table smbios; /* SM BIOS table */ + grub_uint64_t sal_systab; /* SAL system table */ + grub_uint64_t boot_info; /* boot info table */ +} +grub_efi_loongson; + +typedef struct +{ + grub_efi_loongson efi; + grub_efi_loongson_reset_system reset_system; +} +grub_efi_loongson_boot_params; + +extern grub_uint64_t grub_efi_loongson_reset_system_addr; + +extern void grub_efi_loongson_reset_cold (void); +extern void grub_efi_loongson_reset_warm (void); +extern void grub_efi_loongson_reset_shutdown (void); +extern void grub_efi_loongson_reset_suspend (void); + +void grub_efi_loongson_init (void); +void grub_efi_loongson_fini (void); +void grub_efi_loongson_alloc_boot_params (void); +void grub_efi_loongson_free_boot_params (void); +void * grub_efi_loongson_get_smbios_table (void); + +int EXPORT_FUNC(grub_efi_is_loongson) (void); + +grub_uint8_t +EXPORT_FUNC(grub_efi_loongson_calculatesum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); + +grub_uint8_t +EXPORT_FUNC(grub_efi_loongson_grub_calculatechecksum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); + + +void * +EXPORT_FUNC(grub_efi_loongson_get_boot_params) (void); + +typedef struct _extention_list_hdr{ + grub_uint64_t signature; + grub_uint32_t length; + grub_uint8_t revision; + grub_uint8_t checksum; + struct _extention_list_hdr *next; +}GRUB_PACKED +ext_list; + +typedef struct bootparamsinterface { + grub_uint64_t signature; //{'B', 'P', 'I', '_', '0', '_', '1'} + grub_efi_system_table_t *systemtable; + ext_list *extlist; +}GRUB_PACKED +bootparamsinterface; + +typedef struct { + ext_list header; // {'M', 'E', 'M'} + grub_uint8_t mapcount; + struct GRUB_PACKED memmap { + grub_uint32_t memtype; + grub_uint64_t memstart; + grub_uint64_t memsize; + } map[GRUB_EFI_LOONGSON_MMAP_MAX]; +}GRUB_PACKED +mem_map; + +typedef struct { + ext_list header; // {VBIOS} + grub_uint64_t vbiosaddr; +}GRUB_PACKED +vbios; + +grub_uint32_t +EXPORT_FUNC (grub_efi_loongson_memmap_sort) (struct memmap array[], grub_uint32_t length, mem_map * bpmem, grub_uint32_t index, grub_uint32_t memtype); +#endif /* ! GRUB_EFI_LOONGSON_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/memory.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/memory.h new file mode 100644 index 0000000..17fceeb --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/memory.h @@ -0,0 +1,7 @@ +#ifndef GRUB_MEMORY_CPU_HEADER +#include + +//#define GRUB_EFI_MAX_USABLE_ADDRESS 0x980000000fffffffUL +#define GRUB_EFI_MAX_USABLE_ADDRESS 0x98000000ffffffffUL + +#endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/time.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/efi/time.h new file mode 100644 index 0000000..e69de29 diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/io.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/io.h new file mode 100644 index 0000000..7761c4c --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/io.h @@ -0,0 +1,62 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_IO_H +#define GRUB_IO_H 1 + +#include + +typedef grub_addr_t grub_port_t; + +static __inline unsigned char +grub_inb (grub_port_t port) +{ + return *(volatile grub_uint8_t *) port; +} + +static __inline unsigned short int +grub_inw (grub_port_t port) +{ + return *(volatile grub_uint16_t *) port; +} + +static __inline unsigned int +grub_inl (grub_port_t port) +{ + return *(volatile grub_uint32_t *) port; +} + +static __inline void +grub_outb (unsigned char value, grub_port_t port) +{ + *(volatile grub_uint8_t *) port = value; +} + +static __inline void +grub_outw (unsigned short int value, grub_port_t port) +{ + *(volatile grub_uint16_t *) port = value; +} + +static __inline void +grub_outl (unsigned int value, grub_port_t port) +{ + *(volatile grub_uint32_t *) port = value; +} + +#endif /* _SYS_IO_H */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/kernel.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/kernel.h new file mode 100644 index 0000000..07ffec3 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/kernel.h @@ -0,0 +1,24 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2006,2007,2008,2009,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_KERNEL_CPU_HEADER +#define GRUB_KERNEL_CPU_HEADER 1 + +#include + +#endif /* ! GRUB_KERNEL_MACHINE_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/memory.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/memory.h new file mode 100644 index 0000000..7cd9c69 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/memory.h @@ -0,0 +1,57 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_MEMORY_CPU_HEADER +#define GRUB_MEMORY_CPU_HEADER 1 + +#ifndef ASM_FILE +#include +#include +#include +#endif + +#ifndef ASM_FILE + +typedef grub_addr_t grub_phys_addr_t; + +static inline grub_phys_addr_t +grub_vtop (void *a) +{ + if (-1 == ((grub_int64_t) a >> 32)) + return ((grub_phys_addr_t) a) & 0x1fffffffUL; + return ((grub_phys_addr_t) a) & 0xffffffffffffUL; +} + +static inline void * +grub_map_memory (grub_phys_addr_t a, grub_size_t size) +{ + if ((a + size) < 0x20000000UL) + return (void *) (a | 0xffffffff80000000UL); +// return (void *) (a | 0x9800000000000000UL); + return (void *) ((a&0x8fffffff) | 0xffffffff00000000UL); +} + +static inline void +grub_unmap_memory (void *a __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} + +#endif + +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/mips.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/mips.h new file mode 100644 index 0000000..7319fbf --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/mips.h @@ -0,0 +1,30 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_REGISTERS_CPU_HEADER +#define GRUB_REGISTERS_CPU_HEADER 1 + +#ifdef ASM_FILE +#define GRUB_CPU_REGISTER_WRAP(x) x +#else +#define GRUB_CPU_REGISTER_WRAP(x) #x +#endif + +#define GRUB_CPU_MIPS_COP0_TIMER_COUNT GRUB_CPU_REGISTER_WRAP($9) + +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/relocator.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/relocator.h new file mode 100644 index 0000000..6849a64 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/relocator.h @@ -0,0 +1,38 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_RELOCATOR_CPU_HEADER +#define GRUB_RELOCATOR_CPU_HEADER 1 + +#include +#include +#include + +struct grub_relocator64_state +{ + /* gpr[0] is ignored since it's hardwired to 0. */ + grub_uint64_t gpr[32]; + /* Register holding target $pc. */ + int jumpreg; +}; + +grub_err_t +grub_relocator64_boot (struct grub_relocator *rel, + struct grub_relocator64_state state); + +#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/setjmp.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/setjmp.h new file mode 100644 index 0000000..3ea01ec --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/setjmp.h @@ -0,0 +1,27 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2006,2007,2009,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_SETJMP_CPU_HEADER +#define GRUB_SETJMP_CPU_HEADER 1 + +typedef grub_uint64_t grub_jmp_buf[12]; + +int grub_setjmp (grub_jmp_buf env) RETURNS_TWICE; +void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn)); + +#endif /* ! GRUB_SETJMP_CPU_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/time.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/time.h new file mode 100644 index 0000000..12e5fac --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/time.h @@ -0,0 +1,39 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2004,2005,2007,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef KERNEL_CPU_TIME_HEADER +#define KERNEL_CPU_TIME_HEADER 1 + +#ifndef GRUB_UTIL + +#define GRUB_TICKS_PER_SECOND (grub_arch_cpuclock / 2) + +void grub_timer_init (grub_uint32_t cpuclock); + +/* Return the real time in ticks. */ +grub_uint64_t grub_get_rtc (void); + +extern grub_uint32_t grub_arch_cpuclock; +#endif + +static inline void +grub_cpu_idle(void) +{ +} + +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/types.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/types.h new file mode 100644 index 0000000..66e9ba6 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/mips64/types.h @@ -0,0 +1,38 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2006,2007,2009,2017 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_TYPES_CPU_HEADER +#define GRUB_TYPES_CPU_HEADER 1 + +/* The size of void *. */ +#define GRUB_TARGET_SIZEOF_VOID_P 8 + +/* The size of long. */ +#define GRUB_TARGET_SIZEOF_LONG 8 + +#ifdef GRUB_CPU_MIPS64EL +/* mips64EL is little-endian. */ +#undef GRUB_TARGET_WORDS_BIGENDIAN +#elif defined (GRUB_CPU_MIPS64) +/* mips64 is big-endian. */ +#define GRUB_TARGET_WORDS_BIGENDIAN +#elif !defined (GRUB_SYMBOL_GENERATOR) +#error Neither GRUB_CPU_MIPS64 nor GRUB_CPU_MIPS64EL is defined +#endif + +#endif /* ! GRUB_TYPES_CPU_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/misc.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/misc.h new file mode 100644 index 0000000..4b6b3d8 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/misc.h @@ -0,0 +1,466 @@ +/* misc.h - prototypes for misc functions */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_MISC_HEADER +#define GRUB_MISC_HEADER 1 + +#include +#include +#include +#include +#include +#include + +#define ALIGN_UP(addr, align) \ + ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1)) +#define ALIGN_UP_OVERHEAD(addr, align) ((-(addr)) & ((typeof (addr)) (align) - 1)) +#define ALIGN_DOWN(addr, align) \ + ((addr) & ~((typeof (addr)) align - 1)) +#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) +#define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } + +#define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__) + +void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n); +char *EXPORT_FUNC(grub_strcpy) (char *dest, const char *src); + +static inline char * +grub_strncpy (char *dest, const char *src, int c) +{ + char *p = dest; + + while ((*p++ = *src++) != '\0' && --c) + ; + + return dest; +} + +static inline char * +grub_stpcpy (char *dest, const char *src) +{ + char *d = dest; + const char *s = src; + + do + *d++ = *s; + while (*s++ != '\0'); + + return d - 1; +} + +/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */ +static inline void * +grub_memcpy (void *dest, const void *src, grub_size_t n) +{ + return grub_memmove (dest, src, n); +} + +#if defined(__x86_64__) && !defined (GRUB_UTIL) +#if defined (__MINGW32__) || defined (__CYGWIN__) || defined (__MINGW64__) +#define GRUB_ASM_ATTR __attribute__ ((sysv_abi)) +#else +#define GRUB_ASM_ATTR +#endif +#endif + +int EXPORT_FUNC(grub_memcmp) (const void *s1, const void *s2, grub_size_t n); +int EXPORT_FUNC(grub_strcmp) (const char *s1, const char *s2); +int EXPORT_FUNC(grub_strncmp) (const char *s1, const char *s2, grub_size_t n); + +char *EXPORT_FUNC(grub_strchr) (const char *s, int c); +char *EXPORT_FUNC(grub_strrchr) (const char *s, int c); +int EXPORT_FUNC(grub_strword) (const char *s, const char *w); + +/* Copied from gnulib. + Written by Bruno Haible , 2005. */ +static inline char * +grub_strstr (const char *haystack, const char *needle) +{ + /* Be careful not to look at the entire extent of haystack or needle + until needed. This is useful because of these two cases: + - haystack may be very long, and a match of needle found early, + - needle may be very long, and not even a short initial segment of + needle may be found in haystack. */ + if (*needle != '\0') + { + /* Speed up the following searches of needle by caching its first + character. */ + char b = *needle++; + + for (;; haystack++) + { + if (*haystack == '\0') + /* No match. */ + return 0; + if (*haystack == b) + /* The first character matches. */ + { + const char *rhaystack = haystack + 1; + const char *rneedle = needle; + + for (;; rhaystack++, rneedle++) + { + if (*rneedle == '\0') + /* Found a match. */ + return (char *) haystack; + if (*rhaystack == '\0') + /* No match. */ + return 0; + if (*rhaystack != *rneedle) + /* Nothing in this round. */ + break; + } + } + } + } + else + return (char *) haystack; +} + +int EXPORT_FUNC(grub_isspace) (int c); + +static inline int +grub_isprint (int c) +{ + return (c >= ' ' && c <= '~'); +} + +static inline int +grub_iscntrl (int c) +{ + return (c >= 0x00 && c <= 0x1F) || c == 0x7F; +} + +static inline int +grub_isalpha (int c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +static inline int +grub_islower (int c) +{ + return (c >= 'a' && c <= 'z'); +} + +static inline int +grub_isupper (int c) +{ + return (c >= 'A' && c <= 'Z'); +} + +static inline int +grub_isgraph (int c) +{ + return (c >= '!' && c <= '~'); +} + +static inline int +grub_isdigit (int c) +{ + return (c >= '0' && c <= '9'); +} + +static inline int +grub_isxdigit (int c) +{ + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +static inline int +grub_isalnum (int c) +{ + return grub_isalpha (c) || grub_isdigit (c); +} + +static inline int +grub_tolower (int c) +{ + if (c >= 'A' && c <= 'Z') + return c - 'A' + 'a'; + + return c; +} + +static inline int +grub_toupper (int c) +{ + if (c >= 'a' && c <= 'z') + return c - 'a' + 'A'; + + return c; +} + +static inline int +grub_strcasecmp (const char *s1, const char *s2) +{ + while (*s1 && *s2) + { + if (grub_tolower ((grub_uint8_t) *s1) + != grub_tolower ((grub_uint8_t) *s2)) + break; + + s1++; + s2++; + } + + return (int) grub_tolower ((grub_uint8_t) *s1) + - (int) grub_tolower ((grub_uint8_t) *s2); +} + +static inline int +grub_strncasecmp (const char *s1, const char *s2, grub_size_t n) +{ + if (n == 0) + return 0; + + while (*s1 && *s2 && --n) + { + if (grub_tolower (*s1) != grub_tolower (*s2)) + break; + + s1++; + s2++; + } + + return (int) grub_tolower ((grub_uint8_t) *s1) + - (int) grub_tolower ((grub_uint8_t) *s2); +} + +unsigned long EXPORT_FUNC(grub_strtoul) (const char *str, char **end, int base); +unsigned long long EXPORT_FUNC(grub_strtoull) (const char *str, char **end, int base); + +static inline long +grub_strtol (const char *str, char **end, int base) +{ + int negative = 0; + unsigned long long magnitude; + + while (*str && grub_isspace (*str)) + str++; + + if (*str == '-') + { + negative = 1; + str++; + } + + magnitude = grub_strtoull (str, end, base); + if (negative) + { + if (magnitude > (unsigned long) GRUB_LONG_MAX + 1) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); + return GRUB_LONG_MIN; + } + return -((long) magnitude); + } + else + { + if (magnitude > GRUB_LONG_MAX) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); + return GRUB_LONG_MAX; + } + return (long) magnitude; + } +} + +char *EXPORT_FUNC(grub_strdup) (const char *s) WARN_UNUSED_RESULT; +char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n) WARN_UNUSED_RESULT; +void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n); +grub_size_t EXPORT_FUNC(grub_strlen) (const char *s) WARN_UNUSED_RESULT; +int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); +int EXPORT_FUNC(grub_printf_) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); + +/* Replace all `ch' characters of `input' with `with' and copy the + result into `output'; return EOS address of `output'. */ +static inline char * +grub_strchrsub (char *output, const char *input, char ch, const char *with) +{ + while (*input) + { + if (*input == ch) + { + grub_strcpy (output, with); + output += grub_strlen (with); + input++; + continue; + } + *output++ = *input++; + } + *output = '\0'; + return output; +} + +extern void (*EXPORT_VAR (grub_xputs)) (const char *str); + +static inline int +grub_puts (const char *s) +{ + const char nl[2] = "\n"; + grub_xputs (s); + grub_xputs (nl); + + return 1; /* Cannot fail. */ +} + +int EXPORT_FUNC(grub_puts_) (const char *s); +void EXPORT_FUNC(grub_real_dprintf) (const char *file, + const int line, + const char *condition, + const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5))); +int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args); +int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) + __attribute__ ((format (GNU_PRINTF, 3, 4))); +int EXPORT_FUNC(grub_vsnprintf) (char *str, grub_size_t n, const char *fmt, + va_list args); +char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...) + __attribute__ ((format (GNU_PRINTF, 1, 2))) WARN_UNUSED_RESULT; +char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) WARN_UNUSED_RESULT; +void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); +grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, + grub_uint64_t d, + grub_uint64_t *r); + +/* Must match softdiv group in gentpl.py. */ +#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \ + (defined(__riscv) && (__riscv_xlen == 32))) +#define GRUB_DIVISION_IN_SOFTWARE 1 +#else +#define GRUB_DIVISION_IN_SOFTWARE 0 +#endif + +/* Some division functions need to be in kernel if compiler generates calls + to them. Otherwise we still need them for consistent tests but they go + into a separate module. */ +#if GRUB_DIVISION_IN_SOFTWARE +#define EXPORT_FUNC_IF_SOFTDIV EXPORT_FUNC +#else +#define EXPORT_FUNC_IF_SOFTDIV(x) x +#endif + +grub_int64_t +EXPORT_FUNC_IF_SOFTDIV(grub_divmod64s) (grub_int64_t n, + grub_int64_t d, + grub_int64_t *r); + +grub_uint32_t +EXPORT_FUNC_IF_SOFTDIV (grub_divmod32) (grub_uint32_t n, + grub_uint32_t d, + grub_uint32_t *r); + +grub_int32_t +EXPORT_FUNC_IF_SOFTDIV (grub_divmod32s) (grub_int32_t n, + grub_int32_t d, + grub_int32_t *r); + +/* Inline functions. */ + +static inline char * +grub_memchr (const void *p, int c, grub_size_t len) +{ + const char *s = (const char *) p; + const char *e = s + len; + + for (; s < e; s++) + if (*s == c) + return (char *) s; + + return 0; +} + + +static inline unsigned int +grub_abs (int x) +{ + if (x < 0) + return (unsigned int) (-x); + else + return (unsigned int) x; +} + +/* Reboot the machine. */ +#if defined (GRUB_MACHINE_EMU) || defined (GRUB_MACHINE_QEMU_MIPS) || \ + defined (GRUB_MACHINE_EFI) +void EXPORT_FUNC(grub_reboot) (void) __attribute__ ((noreturn)); +#else +void grub_reboot (void) __attribute__ ((noreturn)); +#endif + +#if defined (__clang__) && !defined (GRUB_UTIL) +void __attribute__ ((noreturn)) EXPORT_FUNC (abort) (void); +#endif + +#ifdef GRUB_MACHINE_PCBIOS +/* Halt the system, using APM if possible. If NO_APM is true, don't + * use APM even if it is available. */ +void grub_halt (int no_apm) __attribute__ ((noreturn)); +#elif (defined (__mips__) && (_MIPS_SIM != _ABI64)) && !defined (GRUB_MACHINE_EMU) +void EXPORT_FUNC (grub_halt) (void) __attribute__ ((noreturn)); +#else +void grub_halt (void) __attribute__ ((noreturn)); +#endif + +#ifdef GRUB_MACHINE_EMU +/* Flag to check if module loading is available. */ +extern const int EXPORT_VAR(grub_no_modules); +#else +#define grub_no_modules 0 +#endif + +static inline void +grub_error_save (struct grub_error_saved *save) +{ + grub_memcpy (save->errmsg, grub_errmsg, sizeof (save->errmsg)); + save->grub_errno = grub_errno; + grub_errno = GRUB_ERR_NONE; +} + +static inline void +grub_error_load (const struct grub_error_saved *save) +{ + grub_memcpy (grub_errmsg, save->errmsg, sizeof (grub_errmsg)); + grub_errno = save->grub_errno; +} + +#if BOOT_TIME_STATS +struct grub_boot_time +{ + struct grub_boot_time *next; + grub_uint64_t tp; + const char *file; + int line; + char *msg; +}; + +extern struct grub_boot_time *EXPORT_VAR(grub_boot_time_head); + +void EXPORT_FUNC(grub_real_boot_time) (const char *file, + const int line, + const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4))); +#define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__) +#else +#define grub_boot_time(...) +#endif + +#define grub_max(a, b) (((a) > (b)) ? (a) : (b)) +#define grub_min(a, b) (((a) < (b)) ? (a) : (b)) + +#endif /* ! GRUB_MISC_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/normal.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/normal.h new file mode 100644 index 0000000..082dcc4 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/normal.h @@ -0,0 +1,177 @@ +/* normal.h - prototypes for the normal mode */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_NORMAL_HEADER +#define GRUB_NORMAL_HEADER 1 + +#include +#include +#include +#include +#include +#include +#include + +/* The standard left and right margin for some messages. */ +#define STANDARD_MARGIN 6 + +/* The type of a completion item. */ +enum grub_completion_type + { + GRUB_COMPLETION_TYPE_COMMAND, + GRUB_COMPLETION_TYPE_DEVICE, + GRUB_COMPLETION_TYPE_PARTITION, + GRUB_COMPLETION_TYPE_FILE, + GRUB_COMPLETION_TYPE_ARGUMENT + }; +typedef enum grub_completion_type grub_completion_type_t; + +extern struct grub_menu_viewer grub_normal_text_menu_viewer; +extern int grub_normal_exit_level; + +/* Defined in `main.c'. */ +void grub_enter_normal_mode (const char *config); +void grub_normal_execute (const char *config, int nested, int batch); +struct grub_term_screen_geometry +{ + /* The number of entries shown at a time. */ + int num_entries; + int first_entry_y; + int first_entry_x; + int entry_width; + int timeout_y; + int timeout_lines; + int border; + int right_margin; +}; + +void grub_menu_init_page (int nested, int edit, + struct grub_term_screen_geometry *geo, + struct grub_term_output *term); +void grub_normal_init_page (struct grub_term_output *term, int y); +char *grub_file_getline (grub_file_t file); +void grub_cmdline_run (int nested, int force_auth); + +/* Defined in `cmdline.c'. */ +char *grub_cmdline_get (const char *prompt); +grub_err_t grub_set_history (int newsize); + +/* Defined in `completion.c'. */ +char *grub_normal_do_completion (char *buf, int *restore, + void (*hook) (const char *item, grub_completion_type_t type, int count)); + +/* Defined in `misc.c'. */ +grub_err_t grub_normal_print_device_info (const char *name); + +/* Defined in `color.c'. */ +char *grub_env_write_color_normal (struct grub_env_var *var, const char *val); +char *grub_env_write_color_highlight (struct grub_env_var *var, const char *val); +int grub_parse_color_name_pair (grub_uint8_t *ret, const char *name); + +/* Defined in `menu_text.c'. */ +void grub_wait_after_message (void); +void +grub_print_ucs4 (const grub_uint32_t * str, + const grub_uint32_t * last_position, + int margin_left, int margin_right, + struct grub_term_output *term); + +void +grub_print_ucs4_menu (const grub_uint32_t * str, + const grub_uint32_t * last_position, + int margin_left, int margin_right, + struct grub_term_output *term, + int skip_lines, int max_lines, grub_uint32_t contchar, + struct grub_term_pos *pos); +int +grub_ucs4_count_lines (const grub_uint32_t * str, + const grub_uint32_t * last_position, + int margin_left, int margin_right, + struct grub_term_output *term); +grub_size_t grub_getstringwidth (grub_uint32_t * str, + const grub_uint32_t * last_position, + struct grub_term_output *term); +void grub_print_message_indented (const char *msg, int margin_left, + int margin_right, + struct grub_term_output *term); +void +grub_menu_text_register_instances (int entry, grub_menu_t menu, int nested); +grub_err_t +grub_show_menu (grub_menu_t menu, int nested, int autobooted); + +/* Defined in `handler.c'. */ +void read_handler_list (void); +void free_handler_list (void); + +/* Defined in `dyncmd.c'. */ +void read_command_list (const char *prefix); + +/* Defined in `autofs.c'. */ +void read_fs_list (const char *prefix); + +void grub_context_init (void); +void grub_context_fini (void); + +void read_crypto_list (const char *prefix); + +void read_terminal_list (const char *prefix); + +void grub_set_more (int onoff); + +void grub_normal_reset_more (void); + +void grub_xputs_normal (const char *str); + +extern int grub_extractor_level; + +grub_err_t +grub_normal_add_menu_entry (int argc, const char **args, char **classes, + const char *id, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode, + int submenu, int *index, struct bls_entry *bls); + +grub_err_t +grub_normal_set_password (const char *user, const char *password); + +void grub_normal_free_menu (grub_menu_t menu); + +void grub_normal_auth_init (void); +void grub_normal_auth_fini (void); + +void +grub_xnputs (const char *str, grub_size_t msg_len); + +grub_command_t +grub_dyncmd_get_cmd (grub_command_t cmd); + +void +grub_gettext_reread_prefix (const char *val); + +enum grub_human_size_type + { + GRUB_HUMAN_SIZE_NORMAL, + GRUB_HUMAN_SIZE_SHORT, + GRUB_HUMAN_SIZE_SPEED, + }; + +const char * +grub_get_human_size (grub_uint64_t size, enum grub_human_size_type type); + +#endif /* ! GRUB_NORMAL_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/partition.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/partition.h new file mode 100644 index 0000000..3dc4e33 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/partition.h @@ -0,0 +1,141 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2004,2006,2007 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_PART_HEADER +#define GRUB_PART_HEADER 1 + +#include +#include + +struct grub_disk; + +typedef struct grub_partition *grub_partition_t; + +#ifdef GRUB_UTIL +typedef enum +{ + GRUB_EMBED_PCBIOS +} grub_embed_type_t; +#endif + +typedef int (*grub_partition_iterate_hook_t) (struct grub_disk *disk, + const grub_partition_t partition, + void *data); + +/* Partition map type. */ +struct grub_partition_map +{ + /* The next partition map type. */ + struct grub_partition_map *next; + struct grub_partition_map **prev; + + /* The name of the partition map type. */ + const char *name; + + /* Call HOOK with each partition, until HOOK returns non-zero. */ + grub_err_t (*iterate) (struct grub_disk *disk, + grub_partition_iterate_hook_t hook, void *hook_data); +#ifdef GRUB_UTIL + /* Determine sectors available for embedding. */ + grub_err_t (*embed) (struct grub_disk *disk, unsigned int *nsectors, + unsigned int max_nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors); +#endif +}; +typedef struct grub_partition_map *grub_partition_map_t; + +/* Partition description. */ +struct grub_partition +{ + /* The partition number. */ + int number; + + /* The start sector (relative to parent). */ + grub_disk_addr_t start; + + /* The length in sector units. */ + grub_uint64_t len; + + /* The offset of the partition table. */ + grub_disk_addr_t offset; + + /* The index of this partition in the partition table. */ + int index; + + /* Parent partition (physically contains this partition). */ + struct grub_partition *parent; + + /* The type partition map. */ + grub_partition_map_t partmap; + + /* The type of partition whne it's on MSDOS. + Used for embedding detection. */ + grub_uint8_t msdostype; + + /* The attrib field for GPT. Needed for priority detection. */ + grub_uint64_t gpt_attrib; +}; + +grub_partition_t EXPORT_FUNC(grub_partition_probe) (struct grub_disk *disk, + const char *str); +int EXPORT_FUNC(grub_partition_iterate) (struct grub_disk *disk, + grub_partition_iterate_hook_t hook, + void *hook_data); +char *EXPORT_FUNC(grub_partition_get_name) (const grub_partition_t partition); + + +extern grub_partition_map_t EXPORT_VAR(grub_partition_map_list); + +#ifndef GRUB_LST_GENERATOR +static inline void +grub_partition_map_register (grub_partition_map_t partmap) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_partition_map_list), + GRUB_AS_LIST (partmap)); +} +#endif + +static inline void +grub_partition_map_unregister (grub_partition_map_t partmap) +{ + grub_list_remove (GRUB_AS_LIST (partmap)); +} + +#define FOR_PARTITION_MAPS(var) FOR_LIST_ELEMENTS((var), (grub_partition_map_list)) + + +static inline grub_disk_addr_t +grub_partition_get_start (const grub_partition_t p) +{ + grub_partition_t part; + grub_uint64_t part_start = 0; + + for (part = p; part; part = part->parent) + part_start += part->start; + + return part_start; +} + +static inline grub_uint64_t +grub_partition_get_len (const grub_partition_t p) +{ + return p->len; +} + +#endif /* ! GRUB_PART_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/serial.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/serial.h new file mode 100644 index 0000000..d8d6481 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/serial.h @@ -0,0 +1,205 @@ +/* serial.h - serial device interface */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_SERIAL_HEADER +#define GRUB_SERIAL_HEADER 1 + +#include +#if (defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__) +#include +#endif +#include +#include +#include +#ifdef GRUB_MACHINE_IEEE1275 +#include +#endif +#ifdef GRUB_MACHINE_ARC +#include +#endif + +struct grub_serial_port; +struct grub_serial_config; + +struct grub_serial_driver +{ + grub_err_t (*configure) (struct grub_serial_port *port, + struct grub_serial_config *config); + int (*fetch) (struct grub_serial_port *port); + void (*put) (struct grub_serial_port *port, const int c); + void (*fini) (struct grub_serial_port *port); +}; + +/* The type of parity. */ +typedef enum + { + GRUB_SERIAL_PARITY_NONE, + GRUB_SERIAL_PARITY_ODD, + GRUB_SERIAL_PARITY_EVEN, + } grub_serial_parity_t; + +typedef enum + { + GRUB_SERIAL_STOP_BITS_1, + GRUB_SERIAL_STOP_BITS_1_5, + GRUB_SERIAL_STOP_BITS_2, + } grub_serial_stop_bits_t; + +struct grub_serial_config +{ + unsigned speed; + int word_len; + grub_serial_parity_t parity; + grub_serial_stop_bits_t stop_bits; + grub_uint64_t base_clock; + int rtscts; +}; + +struct grub_serial_port +{ + struct grub_serial_port *next; + struct grub_serial_port **prev; + char *name; + struct grub_serial_driver *driver; + struct grub_serial_config config; + int configured; + int broken; + + /* This should be void *data but since serial is useful as an early console + when malloc isn't available it's a union. + */ + union + { +#if (defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__) + grub_port_t port; +#endif + struct + { + grub_usb_device_t usbdev; + int configno; + int interfno; + char buf[64]; + int bufstart, bufend; + struct grub_usb_desc_endp *in_endp; + struct grub_usb_desc_endp *out_endp; + }; + struct grub_escc_descriptor *escc_desc; +#ifdef GRUB_MACHINE_IEEE1275 + struct + { + grub_ieee1275_ihandle_t handle; + struct ofserial_hash_ent *elem; + }; +#endif +#ifdef GRUB_MACHINE_EFI + struct grub_efi_serial_io_interface *interface; +#endif +#ifdef GRUB_MACHINE_ARC + struct + { + grub_arc_fileno_t handle; + int handle_valid; + }; +#endif + }; + grub_term_output_t term_out; + grub_term_input_t term_in; +}; + +grub_err_t EXPORT_FUNC(grub_serial_register) (struct grub_serial_port *port); + +void EXPORT_FUNC(grub_serial_unregister) (struct grub_serial_port *port); + + /* Convenience functions to perform primitive operations on a port. */ +static inline grub_err_t +grub_serial_port_configure (struct grub_serial_port *port, + struct grub_serial_config *config) +{ + return port->driver->configure (port, config); +} + +static inline int +grub_serial_port_fetch (struct grub_serial_port *port) +{ + return port->driver->fetch (port); +} + +static inline void +grub_serial_port_put (struct grub_serial_port *port, const int c) +{ + port->driver->put (port, c); +} + +static inline void +grub_serial_port_fini (struct grub_serial_port *port) +{ + port->driver->fini (port); +} + + /* Set default settings. */ +static inline grub_err_t +grub_serial_config_defaults (struct grub_serial_port *port) +{ + struct grub_serial_config config = + { +#ifdef GRUB_MACHINE_MIPS_LOONGSON + .speed = 115200, + /* On Loongson machines serial port has only 3 wires. */ + .rtscts = 0, +#else + .speed = 9600, + .rtscts = 1, +#endif + .word_len = 8, + .parity = GRUB_SERIAL_PARITY_NONE, + .stop_bits = GRUB_SERIAL_STOP_BITS_1, + .base_clock = 0 + }; + + return port->driver->configure (port, &config); +} + +#if (defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__) +void grub_ns8250_init (void); +char *grub_serial_ns8250_add_port (grub_port_t port); +#endif +#ifdef GRUB_MACHINE_IEEE1275 +void grub_ofserial_init (void); +#endif +#ifdef GRUB_MACHINE_EFI +void +grub_efiserial_init (void); +#endif +#ifdef GRUB_MACHINE_ARC +void +grub_arcserial_init (void); +const char * +grub_arcserial_add_port (const char *path); +#endif + +struct grub_serial_port *grub_serial_find (const char *name); +extern struct grub_serial_driver grub_ns8250_driver; +void EXPORT_FUNC(grub_serial_unregister_driver) (struct grub_serial_driver *driver); + +#ifndef GRUB_MACHINE_EMU +extern void grub_serial_init (void); +extern void grub_serial_fini (void); +#endif + +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/smbios.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/smbios.h new file mode 100644 index 0000000..0b20cad --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/smbios.h @@ -0,0 +1,69 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2019 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_SMBIOS_HEADER +#define GRUB_SMBIOS_HEADER 1 + +#include +#include + +#define GRUB_SMBIOS_TYPE_END_OF_TABLE ((grub_uint8_t)127) + +struct grub_smbios_ieps +{ + grub_uint8_t anchor[5]; /* "_DMI_" */ + grub_uint8_t checksum; + grub_uint16_t table_length; + grub_uint32_t table_address; + grub_uint16_t structures; + grub_uint8_t revision; +} GRUB_PACKED; + +struct grub_smbios_eps +{ + grub_uint8_t anchor[4]; /* "_SM_" */ + grub_uint8_t checksum; + grub_uint8_t length; /* 0x1f */ + grub_uint8_t version_major; + grub_uint8_t version_minor; + grub_uint16_t maximum_structure_size; + grub_uint8_t revision; + grub_uint8_t formatted[5]; + struct grub_smbios_ieps intermediate; +} GRUB_PACKED; + +struct grub_smbios_eps3 +{ + grub_uint8_t anchor[5]; /* "_SM3_" */ + grub_uint8_t checksum; + grub_uint8_t length; /* 0x18 */ + grub_uint8_t version_major; + grub_uint8_t version_minor; + grub_uint8_t docrev; + grub_uint8_t revision; + grub_uint8_t reserved; + grub_uint32_t maximum_table_length; + grub_uint64_t table_address; +} GRUB_PACKED; + +extern struct grub_smbios_eps *grub_machine_smbios_get_eps (void); +extern struct grub_smbios_eps3 *grub_machine_smbios_get_eps3 (void); + +extern struct grub_smbios_eps *EXPORT_FUNC (grub_smbios_get_eps) (void); + +#endif /* ! GRUB_SMBIOS_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/term.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/term.h new file mode 100644 index 0000000..c335906 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/term.h @@ -0,0 +1,466 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_TERM_HEADER +#define GRUB_TERM_HEADER 1 + +#define GRUB_TERM_NO_KEY 0 + +/* Internal codes used by GRUB to represent terminal input. */ +/* Only for keys otherwise not having shifted modification. */ +#define GRUB_TERM_SHIFT 0x01000000 +#define GRUB_TERM_CTRL 0x02000000 +#define GRUB_TERM_ALT 0x04000000 + +/* Keys without associated character. */ +#define GRUB_TERM_EXTENDED 0x00800000 +#define GRUB_TERM_KEY_MASK 0x00ffffff + +#define GRUB_TERM_KEY_LEFT (GRUB_TERM_EXTENDED | 0x4b) +#define GRUB_TERM_KEY_RIGHT (GRUB_TERM_EXTENDED | 0x4d) +#define GRUB_TERM_KEY_UP (GRUB_TERM_EXTENDED | 0x48) +#define GRUB_TERM_KEY_DOWN (GRUB_TERM_EXTENDED | 0x50) +#define GRUB_TERM_KEY_HOME (GRUB_TERM_EXTENDED | 0x47) +#define GRUB_TERM_KEY_END (GRUB_TERM_EXTENDED | 0x4f) +#define GRUB_TERM_KEY_DC (GRUB_TERM_EXTENDED | 0x53) +#define GRUB_TERM_KEY_PPAGE (GRUB_TERM_EXTENDED | 0x49) +#define GRUB_TERM_KEY_NPAGE (GRUB_TERM_EXTENDED | 0x51) +#define GRUB_TERM_KEY_F1 (GRUB_TERM_EXTENDED | 0x3b) +#define GRUB_TERM_KEY_F2 (GRUB_TERM_EXTENDED | 0x3c) +#define GRUB_TERM_KEY_F3 (GRUB_TERM_EXTENDED | 0x3d) +#define GRUB_TERM_KEY_F4 (GRUB_TERM_EXTENDED | 0x3e) +#define GRUB_TERM_KEY_F5 (GRUB_TERM_EXTENDED | 0x3f) +#define GRUB_TERM_KEY_F6 (GRUB_TERM_EXTENDED | 0x40) +#define GRUB_TERM_KEY_F7 (GRUB_TERM_EXTENDED | 0x41) +#define GRUB_TERM_KEY_F8 (GRUB_TERM_EXTENDED | 0x42) +#define GRUB_TERM_KEY_F9 (GRUB_TERM_EXTENDED | 0x43) +#define GRUB_TERM_KEY_F10 (GRUB_TERM_EXTENDED | 0x44) +#define GRUB_TERM_KEY_F11 (GRUB_TERM_EXTENDED | 0x57) +#define GRUB_TERM_KEY_F12 (GRUB_TERM_EXTENDED | 0x58) +#define GRUB_TERM_KEY_INSERT (GRUB_TERM_EXTENDED | 0x52) +#define GRUB_TERM_KEY_CENTER (GRUB_TERM_EXTENDED | 0x4c) + +/* Hex value is used for ESC, since '\e' is nonstandard */ +#define GRUB_TERM_ESC 0x1b +#define GRUB_TERM_TAB '\t' +#define GRUB_TERM_BACKSPACE '\b' + +#define GRUB_PROGRESS_NO_UPDATE -1 +#define GRUB_PROGRESS_FAST 0 +#define GRUB_PROGRESS_SLOW 2 + +#ifndef ASM_FILE + +#include +#include +#include +#include +#include + +/* These are used to represent the various color states we use. */ +typedef enum + { + /* The color used to display all text that does not use the + user defined colors below. */ + GRUB_TERM_COLOR_STANDARD, + /* The user defined colors for normal text. */ + GRUB_TERM_COLOR_NORMAL, + /* The user defined colors for highlighted text. */ + GRUB_TERM_COLOR_HIGHLIGHT + } +grub_term_color_state; + +/* Flags for representing the capabilities of a terminal. */ +/* Some notes about the flags: + - These flags are used by higher-level functions but not terminals + themselves. + - If a terminal is dumb, you may assume that only putchar, getkey and + checkkey are called. + - Some fancy features (setcolorstate, setcolor and setcursor) can be set + to NULL. */ + +/* Set when input characters shouldn't be echoed back. */ +#define GRUB_TERM_NO_ECHO (1 << 0) +/* Set when the editing feature should be disabled. */ +#define GRUB_TERM_NO_EDIT (1 << 1) +/* Set when the terminal cannot do fancy things. */ +#define GRUB_TERM_DUMB (1 << 2) +/* Which encoding does terminal expect stream to be. */ +#define GRUB_TERM_CODE_TYPE_SHIFT 3 +#define GRUB_TERM_CODE_TYPE_MASK (7 << GRUB_TERM_CODE_TYPE_SHIFT) +/* Only ASCII characters accepted. */ +#define GRUB_TERM_CODE_TYPE_ASCII (0 << GRUB_TERM_CODE_TYPE_SHIFT) +/* Expects CP-437 characters (ASCII + pseudographics). */ +#define GRUB_TERM_CODE_TYPE_CP437 (1 << GRUB_TERM_CODE_TYPE_SHIFT) +/* UTF-8 stream in logical order. Usually used for terminals + which just forward the stream to another computer. */ +#define GRUB_TERM_CODE_TYPE_UTF8_LOGICAL (2 << GRUB_TERM_CODE_TYPE_SHIFT) +/* UTF-8 in visual order. Like UTF-8 logical but for buggy endpoints. */ +#define GRUB_TERM_CODE_TYPE_UTF8_VISUAL (3 << GRUB_TERM_CODE_TYPE_SHIFT) +/* Glyph description in visual order. */ +#define GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS (4 << GRUB_TERM_CODE_TYPE_SHIFT) + + +/* Bitmasks for modifier keys returned by grub_getkeystatus. */ +#define GRUB_TERM_STATUS_RSHIFT (1 << 0) +#define GRUB_TERM_STATUS_LSHIFT (1 << 1) +#define GRUB_TERM_STATUS_RCTRL (1 << 2) +#define GRUB_TERM_STATUS_RALT (1 << 3) +#define GRUB_TERM_STATUS_SCROLL (1 << 4) +#define GRUB_TERM_STATUS_NUM (1 << 5) +#define GRUB_TERM_STATUS_CAPS (1 << 6) +#define GRUB_TERM_STATUS_LCTRL (1 << 8) +#define GRUB_TERM_STATUS_LALT (1 << 9) + +/* Menu-related geometrical constants. */ + +/* The number of columns/lines between messages/borders/etc. */ +#define GRUB_TERM_MARGIN 1 + +/* The number of columns of scroll information. */ +#define GRUB_TERM_SCROLL_WIDTH 1 + +struct grub_term_input +{ + /* The next terminal. */ + struct grub_term_input *next; + struct grub_term_input **prev; + + /* The terminal name. */ + const char *name; + + /* Initialize the terminal. */ + grub_err_t (*init) (struct grub_term_input *term); + + /* Clean up the terminal. */ + grub_err_t (*fini) (struct grub_term_input *term); + + /* Get a character if any input character is available. Otherwise return -1 */ + int (*getkey) (struct grub_term_input *term); + + /* Get keyboard modifier status. */ + int (*getkeystatus) (struct grub_term_input *term); + + void *data; +}; +typedef struct grub_term_input *grub_term_input_t; + +/* Made in a way to fit into uint32_t and so be passed in a register. */ +struct grub_term_coordinate +{ + grub_uint16_t x; + grub_uint16_t y; +}; + +struct grub_term_output +{ + /* The next terminal. */ + struct grub_term_output *next; + struct grub_term_output **prev; + + /* The terminal name. */ + const char *name; + + /* Initialize the terminal. */ + grub_err_t (*init) (struct grub_term_output *term); + + /* Clean up the terminal. */ + grub_err_t (*fini) (struct grub_term_output *term); + + /* Put a character. C is encoded in Unicode. */ + void (*putchar) (struct grub_term_output *term, + const struct grub_unicode_glyph *c); + + /* Get the number of columns occupied by a given character C. C is + encoded in Unicode. */ + grub_size_t (*getcharwidth) (struct grub_term_output *term, + const struct grub_unicode_glyph *c); + + /* Get the screen size. */ + struct grub_term_coordinate (*getwh) (struct grub_term_output *term); + + /* Get the cursor position. The return value is ((X << 8) | Y). */ + struct grub_term_coordinate (*getxy) (struct grub_term_output *term); + + /* Go to the position (X, Y). */ + void (*gotoxy) (struct grub_term_output *term, + struct grub_term_coordinate pos); + + /* Clear the screen. */ + void (*cls) (struct grub_term_output *term); + + /* Set the current color to be used */ + void (*setcolorstate) (struct grub_term_output *term, + grub_term_color_state state); + + /* Turn on/off the cursor. */ + void (*setcursor) (struct grub_term_output *term, int on); + + /* Update the screen. */ + void (*refresh) (struct grub_term_output *term); + + /* gfxterm only: put in fullscreen mode. */ + grub_err_t (*fullscreen) (void); + + /* The feature flags defined above. */ + grub_uint32_t flags; + + /* Progress data. */ + grub_uint32_t progress_update_divisor; + grub_uint32_t progress_update_counter; + + void *data; +}; +typedef struct grub_term_output *grub_term_output_t; + +#define GRUB_TERM_DEFAULT_NORMAL_COLOR 0x07 +#define GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR 0x70 +#define GRUB_TERM_DEFAULT_STANDARD_COLOR 0x07 + +/* Current color state. */ +extern grub_uint8_t EXPORT_VAR(grub_term_normal_color); +extern grub_uint8_t EXPORT_VAR(grub_term_highlight_color); + +extern struct grub_term_output *EXPORT_VAR(grub_term_outputs_disabled); +extern struct grub_term_input *EXPORT_VAR(grub_term_inputs_disabled); +extern struct grub_term_output *EXPORT_VAR(grub_term_outputs); +extern struct grub_term_input *EXPORT_VAR(grub_term_inputs); + +static inline void +grub_term_register_input (const char *name __attribute__ ((unused)), + grub_term_input_t term) +{ + if (grub_term_inputs) + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); + else + { + /* If this is the first terminal, enable automatically. */ + if (! term->init || term->init (term) == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs), GRUB_AS_LIST (term)); + } +} + +static inline void +grub_term_register_input_inactive (const char *name __attribute__ ((unused)), + grub_term_input_t term) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); +} + +static inline void +grub_term_register_input_active (const char *name __attribute__ ((unused)), + grub_term_input_t term) +{ + if (! term->init || term->init (term) == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs), GRUB_AS_LIST (term)); +} + +static inline void +grub_term_register_output (const char *name __attribute__ ((unused)), + grub_term_output_t term) +{ + if (grub_term_outputs) + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs_disabled), + GRUB_AS_LIST (term)); + else + { + /* If this is the first terminal, enable automatically. */ + if (! term->init || term->init (term) == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs), + GRUB_AS_LIST (term)); + } +} + +static inline void +grub_term_register_output_inactive (const char *name __attribute__ ((unused)), + grub_term_output_t term) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs_disabled), + GRUB_AS_LIST (term)); +} + +static inline void +grub_term_register_output_active (const char *name __attribute__ ((unused)), + grub_term_output_t term) +{ + if (! term->init || term->init (term) == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs), + GRUB_AS_LIST (term)); +} + +static inline void +grub_term_unregister_input (grub_term_input_t term) +{ + grub_list_remove (GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); +} + +static inline void +grub_term_unregister_output (grub_term_output_t term) +{ + grub_list_remove (GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); +} + +#define FOR_ACTIVE_TERM_INPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_inputs)) +#define FOR_DISABLED_TERM_INPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_inputs_disabled)) +#define FOR_ACTIVE_TERM_OUTPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_outputs)) +#define FOR_DISABLED_TERM_OUTPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_outputs_disabled)) + +void grub_putcode (grub_uint32_t code, struct grub_term_output *term); +int EXPORT_FUNC(grub_getkey) (void); +int EXPORT_FUNC(grub_getkey_noblock) (void); +extern int (*EXPORT_VAR (grub_key_remap))(int key); +void grub_cls (void); +void EXPORT_FUNC(grub_refresh) (void); +void grub_puts_terminal (const char *str, struct grub_term_output *term); +struct grub_term_coordinate *grub_term_save_pos (void); +void grub_term_restore_pos (struct grub_term_coordinate *pos); + +static inline unsigned grub_term_width (struct grub_term_output *term) +{ + return term->getwh(term).x ? : 80; +} + +static inline unsigned grub_term_height (struct grub_term_output *term) +{ + return term->getwh(term).y ? : 24; +} + +static inline struct grub_term_coordinate +grub_term_getxy (struct grub_term_output *term) +{ + return term->getxy (term); +} + +static inline void +grub_term_refresh (struct grub_term_output *term) +{ + if (term->refresh) + term->refresh (term); +} + +static inline void +grub_term_gotoxy (struct grub_term_output *term, struct grub_term_coordinate pos) +{ + term->gotoxy (term, pos); +} + +static inline void +grub_term_setcolorstate (struct grub_term_output *term, + grub_term_color_state state) +{ + if (term->setcolorstate) + term->setcolorstate (term, state); +} + +static inline void +grub_setcolorstate (grub_term_color_state state) +{ + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_term_setcolorstate (term, state); +} + +/* Turn on/off the cursor. */ +static inline void +grub_term_setcursor (struct grub_term_output *term, int on) +{ + if (term->setcursor) + term->setcursor (term, on); +} + +static inline void +grub_term_cls (struct grub_term_output *term) +{ + if (term->cls) + (term->cls) (term); + else + { + grub_putcode ('\n', term); + grub_term_refresh (term); + } +} + +#if HAVE_FONT_SOURCE + +grub_size_t +grub_unicode_estimate_width (const struct grub_unicode_glyph *c); + +#else + +static inline grub_size_t +grub_unicode_estimate_width (const struct grub_unicode_glyph *c __attribute__ ((unused))) +{ + if (grub_unicode_get_comb_type (c->base)) + return 0; + return 1; +} + +#endif + +#define GRUB_TERM_TAB_WIDTH 8 + +static inline grub_size_t +grub_term_getcharwidth (struct grub_term_output *term, + const struct grub_unicode_glyph *c) +{ + if (c->base == '\t') + return GRUB_TERM_TAB_WIDTH; + + if (term->getcharwidth) + return term->getcharwidth (term, c); + else if (((term->flags & GRUB_TERM_CODE_TYPE_MASK) + == GRUB_TERM_CODE_TYPE_UTF8_LOGICAL) + || ((term->flags & GRUB_TERM_CODE_TYPE_MASK) + == GRUB_TERM_CODE_TYPE_UTF8_VISUAL) + || ((term->flags & GRUB_TERM_CODE_TYPE_MASK) + == GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS)) + return grub_unicode_estimate_width (c); + else + return 1; +} + +struct grub_term_autoload +{ + struct grub_term_autoload *next; + char *name; + char *modname; +}; + +extern struct grub_term_autoload *grub_term_input_autoload; +extern struct grub_term_autoload *grub_term_output_autoload; + +static inline void +grub_print_spaces (struct grub_term_output *term, int number_spaces) +{ + while (--number_spaces >= 0) + grub_putcode (' ', term); +} + +extern void (*EXPORT_VAR (grub_term_poll_usb)) (int wait_for_completion); + +#define GRUB_TERM_REPEAT_PRE_INTERVAL 400 +#define GRUB_TERM_REPEAT_INTERVAL 50 + +#endif /* ! ASM_FILE */ + +#endif /* ! GRUB_TERM_HEADER */ diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/util/install.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/util/install.h new file mode 100644 index 0000000..1570271 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/util/install.h @@ -0,0 +1,269 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_UTIL_INSTALL_HEADER +#define GRUB_UTIL_INSTALL_HEADER 1 + +#include +#include + +#include +#include +#include + +#define GRUB_INSTALL_OPTIONS \ + { "modules", GRUB_INSTALL_OPTIONS_MODULES, N_("MODULES"), \ + 0, N_("pre-load specified modules MODULES"), 1 }, \ + { "dtb", GRUB_INSTALL_OPTIONS_DTB, N_("FILE"), \ + 0, N_("embed a specific DTB"), 1 }, \ + { "install-modules", GRUB_INSTALL_OPTIONS_INSTALL_MODULES, \ + N_("MODULES"), 0, \ + N_("install only MODULES and their dependencies [default=all]"), 1 }, \ + { "themes", GRUB_INSTALL_OPTIONS_INSTALL_THEMES, N_("THEMES"), \ + 0, N_("install THEMES [default=%s]"), 1 }, \ + { "fonts", GRUB_INSTALL_OPTIONS_INSTALL_FONTS, N_("FONTS"), \ + 0, N_("install FONTS [default=%s]"), 1 }, \ + { "locales", GRUB_INSTALL_OPTIONS_INSTALL_LOCALES, N_("LOCALES"),\ + 0, N_("install only LOCALES [default=all]"), 1 }, \ + { "compress", GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS, \ + "no|xz|gz|lzo", 0, \ + N_("compress GRUB files [optional]"), 1 }, \ + {"core-compress", GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, \ + "xz|none|auto", \ + 0, N_("choose the compression to use for core image"), 2}, \ + /* TRANSLATORS: platform here isn't identifier. It can be translated. */ \ + { "directory", 'd', N_("DIR"), 0, \ + N_("use images and modules under DIR [default=%s/]"), 1 }, \ + { "override-directory", GRUB_INSTALL_OPTIONS_DIRECTORY2, \ + N_("DIR"), OPTION_HIDDEN, \ + N_("use images and modules under DIR [default=%s/]"), 1 }, \ + { "locale-directory", GRUB_INSTALL_OPTIONS_LOCALE_DIRECTORY, \ + N_("DIR"), 0, \ + N_("use translations under DIR [default=%s]"), 1 }, \ + { "themes-directory", GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY, \ + N_("DIR"), OPTION_HIDDEN, \ + N_("use themes under DIR [default=%s]"), 1 }, \ + { "grub-mkimage", GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE, \ + "FILE", OPTION_HIDDEN, 0, 1 }, \ + /* TRANSLATORS: "embed" is a verb (command description). "*/ \ + { "pubkey", 'k', N_("FILE"), 0, \ + N_("embed FILE as public key for signature checking"), 0}, \ + { "verbose", 'v', 0, 0, \ + N_("print verbose messages."), 1 } + +int +grub_install_parse (int key, char *arg); + +void +grub_install_push_module (const char *val); + +void +grub_install_pop_module (void); + +char * +grub_install_help_filter (int key, const char *text, + void *input __attribute__ ((unused))); + +enum grub_install_plat + { + GRUB_INSTALL_PLATFORM_I386_PC, + GRUB_INSTALL_PLATFORM_I386_EFI, + GRUB_INSTALL_PLATFORM_I386_QEMU, + GRUB_INSTALL_PLATFORM_I386_COREBOOT, + GRUB_INSTALL_PLATFORM_I386_MULTIBOOT, + GRUB_INSTALL_PLATFORM_I386_IEEE1275, + GRUB_INSTALL_PLATFORM_X86_64_EFI, + GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, + GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275, + GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275, + GRUB_INSTALL_PLATFORM_MIPSEL_ARC, + GRUB_INSTALL_PLATFORM_MIPS_ARC, + GRUB_INSTALL_PLATFORM_IA64_EFI, + GRUB_INSTALL_PLATFORM_ARM_UBOOT, + GRUB_INSTALL_PLATFORM_ARM_EFI, + GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS, + GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS, + GRUB_INSTALL_PLATFORM_I386_XEN, + GRUB_INSTALL_PLATFORM_X86_64_XEN, + GRUB_INSTALL_PLATFORM_I386_XEN_PVH, + GRUB_INSTALL_PLATFORM_ARM64_EFI, + GRUB_INSTALL_PLATFORM_MIPS64EL_EFI, + GRUB_INSTALL_PLATFORM_ARM_COREBOOT, + GRUB_INSTALL_PLATFORM_RISCV32_EFI, + GRUB_INSTALL_PLATFORM_RISCV64_EFI, + GRUB_INSTALL_PLATFORM_MAX + }; + +enum grub_install_options { + GRUB_INSTALL_OPTIONS_DIRECTORY = 'd', + GRUB_INSTALL_OPTIONS_VERBOSITY = 'v', + GRUB_INSTALL_OPTIONS_MODULES = 0x201, + GRUB_INSTALL_OPTIONS_INSTALL_MODULES, + GRUB_INSTALL_OPTIONS_INSTALL_THEMES, + GRUB_INSTALL_OPTIONS_INSTALL_FONTS, + GRUB_INSTALL_OPTIONS_INSTALL_LOCALES, + GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS, + GRUB_INSTALL_OPTIONS_DIRECTORY2, + GRUB_INSTALL_OPTIONS_LOCALE_DIRECTORY, + GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY, + GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE, + GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, + GRUB_INSTALL_OPTIONS_DTB +}; + +extern char *grub_install_source_directory; + +enum grub_install_plat +grub_install_get_target (const char *src); +void +grub_install_mkdir_p (const char *dst); + +void +grub_install_copy_files (const char *src, + const char *dst, + enum grub_install_plat platid); +char * +grub_install_get_platform_name (enum grub_install_plat platid); + +const char * +grub_install_get_platform_cpu (enum grub_install_plat platid); + +const char * +grub_install_get_platform_platform (enum grub_install_plat platid); + +char * +grub_install_get_platforms_string (void); + +typedef enum { + GRUB_COMPRESSION_AUTO, + GRUB_COMPRESSION_NONE, + GRUB_COMPRESSION_XZ, + GRUB_COMPRESSION_LZMA +} grub_compression_t; + +void +grub_install_make_image_wrap (const char *dir, const char *prefix, + const char *outname, char *memdisk_path, + char *config_path, + const char *format, int note); +void +grub_install_make_image_wrap_file (const char *dir, const char *prefix, + FILE *fp, const char *outname, + char *memdisk_path, + char *config_path, + const char *mkimage_target, int note); + +int +grub_install_copy_file (const char *src, + const char *dst, + int is_critical); + +struct grub_install_image_target_desc; + +void +grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, + const char *outname, char *mods[], + char *memdisk_path, char **pubkey_paths, + size_t npubkeys, + char *config_path, + const struct grub_install_image_target_desc *image_target, + int note, + grub_compression_t comp, const char *dtb_file); + +const struct grub_install_image_target_desc * +grub_install_get_image_target (const char *arg); + +void +grub_util_bios_setup (const char *dir, + const char *boot_file, const char *core_file, + const char *dest, int force, + int fs_probe, int allow_floppy, + int add_rs_codes); +void +grub_util_sparc_setup (const char *dir, + const char *boot_file, const char *core_file, + const char *dest, int force, + int fs_probe, int allow_floppy, + int add_rs_codes); + +char * +grub_install_get_image_targets_string (void); + +const char * +grub_util_get_target_dirname (const struct grub_install_image_target_desc *t); + +void +grub_install_create_envblk_file (const char *name); + +const char * +grub_install_get_default_arm_platform (void); + +const char * +grub_install_get_default_x86_platform (void); + +int +grub_install_register_efi (grub_device_t efidir_grub_dev, + const char *efifile_path, + const char *efi_distributor); + +void +grub_install_register_ieee1275 (int is_prep, const char *install_device, + int partno, const char *relpath); + +void +grub_install_sgi_setup (const char *install_device, + const char *imgfile, const char *destname); + +int +grub_install_compress_gzip (const char *src, const char *dest); +int +grub_install_compress_lzop (const char *src, const char *dest); +int +grub_install_compress_xz (const char *src, const char *dest); + +void +grub_install_get_blocklist (grub_device_t root_dev, + const char *core_path, const char *core_img, + size_t core_size, + void (*callback) (grub_disk_addr_t sector, + unsigned offset, + unsigned length, + void *data), + void *hook_data); + +void +grub_util_create_envblk_file (const char *name); + +void +grub_util_glue_efi (const char *file32, const char *file64, const char *out); + +void +grub_util_render_label (const char *label_font, + const char *label_bgcolor, + const char *label_color, + const char *label_string, + const char *label); + +const char * +grub_util_get_target_name (const struct grub_install_image_target_desc *t); + +extern char *grub_install_copy_buffer; +#define GRUB_INSTALL_COPY_BUFFER_SIZE 1048576 + +#endif diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/ventoy.h b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/ventoy.h new file mode 100644 index 0000000..47f3d42 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/include/grub/ventoy.h @@ -0,0 +1,331 @@ +/****************************************************************************** + * ventoy.h + * + * Copyright (c) 2020, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#ifndef __VENTOY_H__ +#define __VENTOY_H__ + +#define COMPILE_ASSERT(a, expr) extern char __compile_assert##a[(expr) ? 1 : -1] + +#define VENTOY_COMPATIBLE_STR "VENTOY COMPATIBLE" +#define VENTOY_COMPATIBLE_STR_LEN 17 + +#define VENTOY_GUID { 0x77772020, 0x2e77, 0x6576, { 0x6e, 0x74, 0x6f, 0x79, 0x2e, 0x6e, 0x65, 0x74 }} + +typedef enum ventoy_fs_type +{ + ventoy_fs_exfat = 0, /* 0: exfat */ + ventoy_fs_ntfs, /* 1: NTFS */ + ventoy_fs_ext, /* 2: ext2/ext3/ext4 */ + ventoy_fs_xfs, /* 3: XFS */ + ventoy_fs_udf, /* 4: UDF */ + ventoy_fs_fat, /* 5: FAT */ + ventoy_fs_btrfs, /* 6: BTRFS */ + + ventoy_fs_max +}ventoy_fs_type; + +typedef enum ventoy_chain_type +{ + ventoy_chain_linux = 0, /* 0: linux */ + ventoy_chain_windows, /* 1: windows */ + ventoy_chain_wim, /* 2: wim */ + + ventoy_chain_max +}ventoy_chain_type; + +#pragma pack(1) + +typedef struct ventoy_guid +{ + grub_uint32_t data1; + grub_uint16_t data2; + grub_uint16_t data3; + grub_uint8_t data4[8]; +}ventoy_guid; + + +typedef struct ventoy_image_disk_region +{ + grub_uint32_t image_sector_count; /* image sectors contained in this region (in 2048) */ + grub_uint32_t image_start_sector; /* image sector start (in 2048) */ + grub_uint64_t disk_start_sector; /* disk sector start (in 512) */ +}ventoy_image_disk_region; + +typedef struct ventoy_image_location +{ + ventoy_guid guid; + + /* image sector size, 2048/512 */ + grub_uint32_t image_sector_size; + + /* disk sector size, normally the value is 512 */ + grub_uint32_t disk_sector_size; + + grub_uint32_t region_count; + + /* + * disk region data (region_count) + * If the image file has more than one fragments in disk, + * there will be more than one region data here. + * + */ + ventoy_image_disk_region regions[1]; + + /* ventoy_image_disk_region regions[2~region_count-1] */ +}ventoy_image_location; + + +typedef struct ventoy_os_param +{ + ventoy_guid guid; // VENTOY_GUID + grub_uint8_t chksum; // checksum + + grub_uint8_t vtoy_disk_guid[16]; + grub_uint64_t vtoy_disk_size; // disk size in bytes + grub_uint16_t vtoy_disk_part_id; // begin with 1 + grub_uint16_t vtoy_disk_part_type; // 0:exfat 1:ntfs other: reserved + char vtoy_img_path[384]; // It seems to be enough, utf-8 format + grub_uint64_t vtoy_img_size; // image file size in bytes + + /* + * Ventoy will write a copy of ventoy_image_location data into runtime memory + * this is the physically address and length of that memory. + * Address 0 means no such data exist. + * Address will be aligned by 4KB. + * + */ + grub_uint64_t vtoy_img_location_addr; + grub_uint32_t vtoy_img_location_len; + + /* + * These 32 bytes are reserved by ventoy. + * + * vtoy_reserved[0]: vtoy_break_level + * vtoy_reserved[1]: vtoy_debug_level + * vtoy_reserved[2]: vtoy_chain_type 0:Linux 1:Windows 2:wimfile + * vtoy_reserved[3]: vtoy_iso_format 0:iso9660 1:udf + * vtoy_reserved[4]: vtoy_windows_cd_prompt + * vtoy_reserved[5]: vtoy_linux_remount + * vtoy_reserved[6]: vtoy_vlnk + * vtoy_reserved[7~10]: vtoy_disk_sig[4] used for vlnk + * vtoy_reserved[11]: vtoy_win_uefi_max_res + * + */ + grub_uint8_t vtoy_reserved[32]; // Internal use by ventoy + + grub_uint8_t vtoy_disk_signature[4]; + + grub_uint8_t reserved[27]; +}ventoy_os_param; + + +typedef struct ventoy_windows_data +{ + char auto_install_script[384]; + char injection_archive[384]; + grub_uint8_t windows11_bypass_check; + + grub_uint32_t auto_install_len; + + grub_uint8_t windows11_bypass_nro; + + grub_uint8_t reserved[255 - 5]; + + /* auto_intall file buf */ + /* ...... + auto_install_len */ +}ventoy_windows_data; + + +typedef struct ventoy_secure_data +{ + grub_uint8_t magic1[16]; /* VENTOY_GUID */ + grub_uint8_t diskuuid[16]; + grub_uint8_t Checksum[16]; + grub_uint8_t adminSHA256[32]; + grub_uint8_t reserved[4000]; + grub_uint8_t magic2[16]; /* VENTOY_GUID */ +}ventoy_secure_data; + + +typedef struct ventoy_vlnk +{ + ventoy_guid guid; // VENTOY_GUID + grub_uint32_t crc32; // crc32 + grub_uint32_t disk_signature; + grub_uint64_t part_offset; // in bytes + char filepath[384]; + grub_uint8_t reserved[96]; +}ventoy_vlnk; + +#pragma pack() + +// compile assert check : sizeof(ventoy_os_param) must be 512 +COMPILE_ASSERT(1,sizeof(ventoy_os_param) == 512); +COMPILE_ASSERT(2,sizeof(ventoy_secure_data) == 4096); +COMPILE_ASSERT(3,sizeof(ventoy_vlnk) == 512); + + + + + + + +#pragma pack(4) + +typedef struct ventoy_chain_head +{ + ventoy_os_param os_param; + + grub_uint32_t disk_drive; + grub_uint32_t drive_map; + grub_uint32_t disk_sector_size; + + grub_uint64_t real_img_size_in_bytes; + grub_uint64_t virt_img_size_in_bytes; + grub_uint32_t boot_catalog; + grub_uint8_t boot_catalog_sector[2048]; + + grub_uint32_t img_chunk_offset; + grub_uint32_t img_chunk_num; + + grub_uint32_t override_chunk_offset; + grub_uint32_t override_chunk_num; + + grub_uint32_t virt_chunk_offset; + grub_uint32_t virt_chunk_num; +}ventoy_chain_head; + +typedef struct ventoy_image_desc +{ + grub_uint64_t disk_size; + grub_uint64_t part1_size; + grub_uint8_t disk_uuid[16]; + grub_uint8_t disk_signature[4]; + grub_uint32_t img_chunk_count; + /* ventoy_img_chunk list */ +}ventoy_image_desc; + + + +typedef struct ventoy_img_chunk +{ + grub_uint32_t img_start_sector; // sector size: 2KB + grub_uint32_t img_end_sector; // included + + grub_uint64_t disk_start_sector; // in disk_sector_size + grub_uint64_t disk_end_sector; // included +}ventoy_img_chunk; + + +typedef struct ventoy_override_chunk +{ + grub_uint64_t img_offset; + grub_uint32_t override_size; + grub_uint8_t override_data[512]; +}ventoy_override_chunk; + +typedef struct ventoy_virt_chunk +{ + grub_uint32_t mem_sector_start; + grub_uint32_t mem_sector_end; + grub_uint32_t mem_sector_offset; + grub_uint32_t remap_sector_start; + grub_uint32_t remap_sector_end; + grub_uint32_t org_sector_start; +}ventoy_virt_chunk; + +#define DEFAULT_CHUNK_NUM 1024 +typedef struct ventoy_img_chunk_list +{ + char *buf; + grub_uint32_t last_off; + grub_uint32_t err_code; + + grub_uint32_t max_chunk; + grub_uint32_t cur_chunk; + ventoy_img_chunk *chunk; +}ventoy_img_chunk_list; + +#pragma pack() + +#define ventoy_filt_register grub_file_filter_register + +#pragma pack(1) + +#define VTOY_MAX_CONF_REPLACE 2 +#define GRUB_FILE_REPLACE_MAGIC 0x1258BEEF +#define GRUB_IMG_REPLACE_MAGIC 0x1259BEEF + +typedef const char * (*grub_env_get_pf)(const char *name); +typedef int (*grub_env_set_pf)(const char *name, const char *val); +typedef int (*grub_env_printf_pf)(const char *fmt, ...); + +typedef struct ventoy_grub_param_file_replace +{ + grub_uint32_t magic; + char old_file_name[4][256]; + grub_uint32_t old_name_cnt; + grub_uint32_t new_file_virtual_id; +}ventoy_grub_param_file_replace; + +typedef struct ventoy_grub_param +{ + grub_env_get_pf grub_env_get; + grub_env_set_pf grub_env_set; + ventoy_grub_param_file_replace file_replace; + ventoy_grub_param_file_replace img_replace[VTOY_MAX_CONF_REPLACE]; + grub_env_printf_pf grub_env_printf; +}ventoy_grub_param; + +#pragma pack() + +#define VTOY_CHUNK_BUF_SIZE (4 * 1024 * 1024) + +typedef enum vtoy_chunk_err +{ + VTOY_CHUNK_ERR_NONE = 0, + VTOY_CHUNK_ERR_MULTI_DEV, + VTOY_CHUNK_ERR_RAID, + VTOY_CHUNK_ERR_COMPRESS, + VTOY_CHUNK_ERR_NOT_FLAT, + VTOY_CHUNK_ERR_OVER_FLOW, + VTOY_CHUNK_ERR_MAX +}vtoy_chunk_err; + +int grub_ext_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list); +int grub_btrfs_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list); +int grub_fat_get_file_chunk(grub_uint64_t part_start, grub_file_t file, ventoy_img_chunk_list *chunk_list); +void grub_iso9660_set_nojoliet(int nojoliet); +int grub_iso9660_is_joliet(void); +grub_uint64_t grub_iso9660_get_last_read_pos(grub_file_t file); +grub_uint64_t grub_iso9660_get_last_file_dirent_pos(grub_file_t file); +grub_uint64_t grub_udf_get_file_offset(grub_file_t file); +grub_uint64_t grub_udf_get_last_pd_size_offset(void); +grub_uint64_t grub_udf_get_last_file_attr_offset +( + grub_file_t file, + grub_uint32_t *startBlock, + grub_uint64_t *fe_entry_size_offset +); +int ventoy_is_efi_os(void); +void ventoy_memfile_env_set(const char *prefix, const void *buf, unsigned long long len); + +#endif /* __VENTOY_H__ */ + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/install.sh b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/install.sh new file mode 100644 index 0000000..a4fd730 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/install.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +VT_DIR=$PWD/../../.. + +rm -rf $VT_DIR/GRUB2/INSTALL +rm -rf $VT_DIR/GRUB2/PXE +mkdir -p $VT_DIR/GRUB2/INSTALL +mkdir -p $VT_DIR/GRUB2/PXE + +make install + +PATH=$VT_DIR/GRUB2/INSTALL/bin/:$VT_DIR/GRUB2/INSTALL/sbin/:$PATH + +net_modules_legacy="net tftp http" +all_modules_legacy="file date drivemap blocklist newc vga_text ntldr search at_keyboard usb_keyboard gcry_md5 hashsum gzio xzio lzopio lspci pci ext2 xfs ventoy chain read halt iso9660 linux16 test true sleep reboot echo videotest videoinfo videotest_checksum video_colors video_cirrus video_bochs vga vbe font video gettext extcmd terminal linux minicmd help configfile tr trig boot biosdisk disk ls tar squash4 password_pbkdf2 all_video png jpeg part_gpt part_msdos fat exfat ntfs loopback gzio normal video_fb udf gfxmenu gfxterm gfxterm_background gfxterm_menu smbios" + +net_modules_uefi="efinet net tftp http" +all_modules_uefi="file setkey blocklist ventoy test true regexp newc search at_keyboard usb_keyboard gcry_md5 hashsum gzio xzio lzopio ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux relocator jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop efi_uga video_bochs video_cirrus video video_fb gfxterm_background gfxterm_menu mouse fwload smbios zfs" + +all_modules_arm64_uefi="file setkey blocklist ventoy test true regexp newc search gcry_md5 hashsum gzio xzio lzopio ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop video video_fb gfxterm_background gfxterm_menu zfs" + +all_modules_mips64el_uefi="file setkey blocklist ventoy test true regexp newc search gcry_md5 hashsum gzio xzio lzopio ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop video video_fb gfxterm_background gfxterm_menu zfs" + + +if [ "$1" = "uefi" ]; then + all_modules="$net_modules_uefi $all_modules_uefi " + + grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/x86_64-efi" --prefix '(,2)/grub' --output "$VT_DIR/INSTALL/EFI/BOOT/grubx64_real.efi" --format 'x86_64-efi' --compression 'auto' $all_modules_uefi + + #grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/x86_64-efi" -c "$VT_DIR/LiveCD/GRUB/embed.cfg" --prefix '/EFI/boot' --output "$VT_DIR/LiveCD/GRUB/bootx64.efi" --format 'x86_64-efi' --compression 'auto' $all_modules_uefi 'fat' 'part_msdos' +elif [ "$1" = "i386efi" ]; then + all_modules="$net_modules_uefi $all_modules_uefi " + + grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/i386-efi" --prefix '(,2)/grub' --output "$VT_DIR/INSTALL/EFI/BOOT/grubia32_real.efi" --format 'i386-efi' --compression 'auto' $all_modules_uefi +elif [ "$1" = "arm64" ]; then + all_modules="$net_modules_uefi $all_modules_arm64_uefi " + + grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/arm64-efi" --prefix '(,2)/grub' --output "$VT_DIR/INSTALL/EFI/BOOT/BOOTAA64.EFI" --format 'arm64-efi' --compression 'auto' $all_modules_arm64_uefi +elif [ "$1" = "mips64el" ]; then + all_modules="$net_modules_uefi $all_modules_mips64el_uefi " + + grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/mips64el-efi" --prefix '(,2)/grub' --output "$VT_DIR/INSTALL/EFI/BOOT/BOOTMIPS.EFI" --format 'mips64el-efi' --compression 'auto' $all_modules_mips64el_uefi +else + all_modules="$net_modules_legacy $all_modules_legacy " + grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc" --prefix '(,2)/grub' --output "$VT_DIR/INSTALL/grub/i386-pc/core.img" --format 'i386-pc' --compression 'auto' $all_modules_legacy 'fat' 'part_msdos' 'biosdisk' + + #grub-mkimage -v --directory "$VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc" -c "$VT_DIR/LiveCD/GRUB/embed.cfg" --prefix '/EFI/boot' --output "$VT_DIR/LiveCD/GRUB/cdrom.img" --format 'i386-pc-eltorito' --compression 'auto' $all_modules_legacy 'biosdisk' 'iso9660' 'fat' 'part_msdos' + #rm -f $VT_DIR/LiveCD/GRUB/boot_hybrid.img + #cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc/boot_hybrid.img $VT_DIR/LiveCD/GRUB/boot_hybrid.img +fi + +grub-mknetdir --modules="$all_modules" --net-directory=$VT_DIR/GRUB2/PXE --subdir=grub2 --locales=en@quot || exit 1 + +if [ "$1" = "uefi" ]; then + rm -f $VT_DIR/GRUB2/NBP/core.efi + cp -a $VT_DIR/GRUB2/PXE/grub2/x86_64-efi/core.efi $VT_DIR/GRUB2/NBP/core.efi || exit 1 + + rm -rf $VT_DIR/INSTALL/grub/x86_64-efi + mkdir -p $VT_DIR/INSTALL/grub/x86_64-efi + + cp -a $VT_DIR/GRUB2/PXE/grub2/x86_64-efi/normal.mod $VT_DIR/INSTALL/grub/x86_64-efi/normal.mod || exit 1 + + #copy other modules + ls -1 $VT_DIR/GRUB2/INSTALL/lib/grub/x86_64-efi/ | egrep '\.(lst|mod)$' | while read line; do + if ! echo $all_modules | grep -q " ${line%.mod} "; then + echo "Copy $line ..." + cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/x86_64-efi/$line $VT_DIR/INSTALL/grub/x86_64-efi/ + fi + done +elif [ "$1" = "i386efi" ]; then + rm -f $VT_DIR/GRUB2/NBP/core.efi + cp -a $VT_DIR/GRUB2/PXE/grub2/i386-efi/core.efi $VT_DIR/GRUB2/NBP/core.efi || exit 1 + + rm -rf $VT_DIR/INSTALL/grub/i386-efi + mkdir -p $VT_DIR/INSTALL/grub/i386-efi + + cp -a $VT_DIR/GRUB2/PXE/grub2/i386-efi/normal.mod $VT_DIR/INSTALL/grub/i386-efi/normal.mod || exit 1 + + #copy other modules + ls -1 $VT_DIR/GRUB2/INSTALL/lib/grub/i386-efi/ | egrep '\.(lst|mod)$' | while read line; do + if ! echo $all_modules | grep -q " ${line%.mod} "; then + echo "Copy $line ..." + cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/i386-efi/$line $VT_DIR/INSTALL/grub/i386-efi/ + fi + done +elif [ "$1" = "arm64" ]; then + rm -f $VT_DIR/GRUB2/NBP/core.efi + cp -a $VT_DIR/GRUB2/PXE/grub2/arm64-efi/core.efi $VT_DIR/GRUB2/NBP/core.efi || exit 1 + + rm -rf $VT_DIR/INSTALL/grub/arm64-efi + mkdir -p $VT_DIR/INSTALL/grub/arm64-efi + + cp -a $VT_DIR/GRUB2/PXE/grub2/arm64-efi/normal.mod $VT_DIR/INSTALL/grub/arm64-efi/normal.mod || exit 1 + + #copy other modules + ls -1 $VT_DIR/GRUB2/INSTALL/lib/grub/arm64-efi/ | egrep '\.(lst|mod)$' | while read line; do + if ! echo $all_modules | grep -q " ${line%.mod} "; then + echo "Copy $line ..." + cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/arm64-efi/$line $VT_DIR/INSTALL/grub/arm64-efi/ + xz $VT_DIR/INSTALL/grub/arm64-efi/$line + mv $VT_DIR/INSTALL/grub/arm64-efi/${line}.xz $VT_DIR/INSTALL/grub/arm64-efi/${line} + fi + done +elif [ "$1" = "mips64el" ]; then + rm -f $VT_DIR/GRUB2/NBP/core.efi + cp -a $VT_DIR/GRUB2/PXE/grub2/mips64el-efi/core.efi $VT_DIR/GRUB2/NBP/core.efi || exit 1 + + rm -rf $VT_DIR/INSTALL/grub/mips64el-efi + mkdir -p $VT_DIR/INSTALL/grub/mips64el-efi + + cp -a $VT_DIR/GRUB2/PXE/grub2/mips64el-efi/normal.mod $VT_DIR/INSTALL/grub/mips64el-efi/normal.mod || exit 1 + + #copy other modules + ls -1 $VT_DIR/GRUB2/INSTALL/lib/grub/mips64el-efi/ | egrep '\.(lst|mod)$' | while read line; do + if ! echo $all_modules | grep -q " ${line%.mod} "; then + echo "Copy $line ..." + cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/mips64el-efi/$line $VT_DIR/INSTALL/grub/mips64el-efi/ + xz $VT_DIR/INSTALL/grub/mips64el-efi/$line + mv $VT_DIR/INSTALL/grub/mips64el-efi/${line}.xz $VT_DIR/INSTALL/grub/mips64el-efi/${line} + fi + done +else + rm -f $VT_DIR/GRUB2/NBP/core.0 + cp -a $VT_DIR/GRUB2/PXE/grub2/i386-pc/core.0 $VT_DIR/GRUB2/NBP/core.0 || exit 1 + + rm -f $VT_DIR/INSTALL/grub/i386-pc/boot.img + cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc/boot.img $VT_DIR/INSTALL/grub/i386-pc/boot.img || exit 1 + + #copy other modules + ls -1 $VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc/ | egrep '\.(lst|mod)$' | while read line; do + if ! echo $all_modules | grep -q " ${line%.mod} "; then + echo "Copy $line ..." + rm -f $VT_DIR/INSTALL/grub/i386-pc/$line + cp -a $VT_DIR/GRUB2/INSTALL/lib/grub/i386-pc/$line $VT_DIR/INSTALL/grub/i386-pc/ + fi + done +fi diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-install-common.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-install-common.c new file mode 100644 index 0000000..1ae79fd --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-install-common.c @@ -0,0 +1,1000 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +char * +grub_install_help_filter (int key, const char *text, + void *input __attribute__ ((unused))) +{ + switch (key) + { + case GRUB_INSTALL_OPTIONS_INSTALL_THEMES: + return xasprintf(text, "starfield"); + case GRUB_INSTALL_OPTIONS_INSTALL_FONTS: + return xasprintf(text, "unicode"); + case GRUB_INSTALL_OPTIONS_DIRECTORY: + case GRUB_INSTALL_OPTIONS_DIRECTORY2: + return xasprintf(text, grub_util_get_pkglibdir ()); + case GRUB_INSTALL_OPTIONS_LOCALE_DIRECTORY: + return xasprintf(text, grub_util_get_localedir ()); + case GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY: + return grub_util_path_concat (2, grub_util_get_pkgdatadir (), "themes"); + default: + return (char *) text; + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +static int (*compress_func) (const char *src, const char *dest) = NULL; +char *grub_install_copy_buffer; +static char *dtb; + +int +grub_install_copy_file (const char *src, + const char *dst, + int is_needed) +{ + grub_util_fd_t in, out; + ssize_t r; + + grub_util_info ("copying `%s' -> `%s'", src, dst); + + in = grub_util_fd_open (src, GRUB_UTIL_FD_O_RDONLY); + if (!GRUB_UTIL_FD_IS_VALID (in)) + { + if (is_needed) + grub_util_error (_("cannot open `%s': %s"), src, grub_util_fd_strerror ()); + else + grub_util_info (_("cannot open `%s': %s"), src, grub_util_fd_strerror ()); + return 0; + } + out = grub_util_fd_open (dst, GRUB_UTIL_FD_O_WRONLY + | GRUB_UTIL_FD_O_CREATTRUNC); + if (!GRUB_UTIL_FD_IS_VALID (out)) + { + grub_util_error (_("cannot open `%s': %s"), dst, + grub_util_fd_strerror ()); + grub_util_fd_close (in); + return 0; + } + + if (!grub_install_copy_buffer) + grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE); + + while (1) + { + r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE); + if (r <= 0) + break; + r = grub_util_fd_write (out, grub_install_copy_buffer, r); + if (r <= 0) + break; + } + if (grub_util_fd_sync (out) < 0) + r = -1; + if (grub_util_fd_close (in) < 0) + r = -1; + if (grub_util_fd_close (out) < 0) + r = -1; + + if (r < 0) + grub_util_error (_("cannot copy `%s' to `%s': %s"), + src, dst, grub_util_fd_strerror ()); + + return 1; +} + +static int +grub_install_compress_file (const char *in_name, + const char *out_name, + int is_needed) +{ + int ret; + + if (!compress_func) + ret = grub_install_copy_file (in_name, out_name, is_needed); + else + { + grub_util_info ("compressing `%s' -> `%s'", in_name, out_name); + ret = !compress_func (in_name, out_name); + if (!ret && is_needed) + grub_util_warn (_("can't compress `%s' to `%s'"), in_name, out_name); + } + + if (!ret && is_needed) + grub_util_error (_("cannot copy `%s' to `%s': %s"), + in_name, out_name, grub_util_fd_strerror ()); + + return ret; +} + +static int +is_path_separator (char c) +{ +#if defined (__MINGW32__) || defined (__CYGWIN__) + if (c == '\\') + return 1; +#endif + if (c == '/') + return 1; + return 0; +} + +void +grub_install_mkdir_p (const char *dst) +{ + char *t = xstrdup (dst); + char *p; + for (p = t; *p; p++) + { + if (is_path_separator (*p)) + { + char s = *p; + *p = '\0'; + grub_util_mkdir (t); + *p = s; + } + } + grub_util_mkdir (t); + free (t); +} + +static void +clean_grub_dir (const char *di) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + + d = grub_util_fd_opendir (di); + if (!d) + grub_util_error (_("cannot open directory `%s': %s"), + di, grub_util_fd_strerror ()); + + while ((de = grub_util_fd_readdir (d))) + { + const char *ext = strrchr (de->d_name, '.'); + if ((ext && (strcmp (ext, ".mod") == 0 + || strcmp (ext, ".lst") == 0 + || strcmp (ext, ".img") == 0 + || strcmp (ext, ".mo") == 0) + && strcmp (de->d_name, "menu.lst") != 0) + || strcmp (de->d_name, "efiemu32.o") == 0 + || strcmp (de->d_name, "efiemu64.o") == 0) + { + char *x = grub_util_path_concat (2, di, de->d_name); + if (grub_util_unlink (x) < 0) + grub_util_error (_("cannot delete `%s': %s"), x, + grub_util_fd_strerror ()); + free (x); + } + } + grub_util_fd_closedir (d); +} + +struct install_list +{ + int is_default; + char **entries; + size_t n_entries; + size_t n_alloc; +}; + +struct install_list install_modules = { 1, 0, 0, 0 }; +struct install_list modules = { 1, 0, 0, 0 }; +struct install_list install_locales = { 1, 0, 0, 0 }; +struct install_list install_fonts = { 1, 0, 0, 0 }; +struct install_list install_themes = { 1, 0, 0, 0 }; +char *grub_install_source_directory = NULL; +char *grub_install_locale_directory = NULL; +char *grub_install_themes_directory = NULL; + +void +grub_install_push_module (const char *val) +{ + modules.is_default = 0; + if (modules.n_entries + 1 >= modules.n_alloc) + { + modules.n_alloc <<= 1; + if (modules.n_alloc < 16) + modules.n_alloc = 16; + modules.entries = xrealloc (modules.entries, + modules.n_alloc * sizeof (*modules.entries)); + } + modules.entries[modules.n_entries++] = xstrdup (val); + modules.entries[modules.n_entries] = NULL; +} + +void +grub_install_pop_module (void) +{ + modules.n_entries--; + free (modules.entries[modules.n_entries]); + modules.entries[modules.n_entries] = NULL; +} + + +static void +handle_install_list (struct install_list *il, const char *val, + int default_all) +{ + const char *ptr; + char **ce; + il->is_default = 0; + free (il->entries); + il->entries = NULL; + il->n_entries = 0; + if (strcmp (val, "all") == 0 && default_all) + { + il->is_default = 1; + return; + } + ptr = val; + while (1) + { + while (*ptr && grub_isspace (*ptr)) + ptr++; + if (!*ptr) + break; + while (*ptr && !grub_isspace (*ptr)) + ptr++; + il->n_entries++; + } + il->n_alloc = il->n_entries + 1; + il->entries = xmalloc (il->n_alloc * sizeof (il->entries[0])); + ptr = val; + for (ce = il->entries; ; ce++) + { + const char *bptr; + while (*ptr && grub_isspace (*ptr)) + ptr++; + if (!*ptr) + break; + bptr = ptr; + while (*ptr && !grub_isspace (*ptr)) + ptr++; + *ce = xmalloc (ptr - bptr + 1); + memcpy (*ce, bptr, ptr - bptr); + (*ce)[ptr - bptr] = '\0'; + } + *ce = NULL; +} + +static char **pubkeys; +static size_t npubkeys; +static grub_compression_t compression; + +int +grub_install_parse (int key, char *arg) +{ + switch (key) + { + case 'C': + if (grub_strcmp (arg, "xz") == 0) + { +#ifdef HAVE_LIBLZMA + compression = GRUB_COMPRESSION_XZ; +#else + grub_util_error ("%s", + _("grub-mkimage is compiled without XZ support")); +#endif + } + else if (grub_strcmp (arg, "none") == 0) + compression = GRUB_COMPRESSION_NONE; + else if (grub_strcmp (arg, "auto") == 0) + compression = GRUB_COMPRESSION_AUTO; + else + grub_util_error (_("Unknown compression format %s"), arg); + return 1; + case 'k': + pubkeys = xrealloc (pubkeys, + sizeof (pubkeys[0]) + * (npubkeys + 1)); + pubkeys[npubkeys++] = xstrdup (arg); + return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; + return 1; + + case GRUB_INSTALL_OPTIONS_DIRECTORY: + case GRUB_INSTALL_OPTIONS_DIRECTORY2: + free (grub_install_source_directory); + grub_install_source_directory = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_LOCALE_DIRECTORY: + free (grub_install_locale_directory); + grub_install_locale_directory = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY: + free (grub_install_themes_directory); + grub_install_themes_directory = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_MODULES: + handle_install_list (&install_modules, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_MODULES: + handle_install_list (&modules, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_LOCALES: + handle_install_list (&install_locales, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_THEMES: + handle_install_list (&install_themes, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_FONTS: + handle_install_list (&install_fonts, arg, 0); + return 1; + case GRUB_INSTALL_OPTIONS_DTB: + if (dtb) + free (dtb); + dtb = xstrdup (arg); + return 1; + case GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS: + if (strcmp (arg, "no") == 0 + || strcmp (arg, "none") == 0) + { + compress_func = NULL; + return 1; + } + if (strcmp (arg, "gz") == 0) + { + compress_func = grub_install_compress_gzip; + return 1; + } + if (strcmp (arg, "xz") == 0) + { + compress_func = grub_install_compress_xz; + return 1; + } + if (strcmp (arg, "lzo") == 0) + { + compress_func = grub_install_compress_lzop; + return 1; + } + grub_util_error (_("Unrecognized compression `%s'"), arg); + case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE: + return 1; + default: + return 0; + } +} + +static int +decompressors (void) +{ + if (compress_func == grub_install_compress_gzip) + { + grub_install_push_module ("gzio"); + return 1; + } + if (compress_func == grub_install_compress_xz) + { + grub_install_push_module ("xzio"); + grub_install_push_module ("gcry_crc"); + return 2; + } + if (compress_func == grub_install_compress_lzop) + { + grub_install_push_module ("lzopio"); + grub_install_push_module ("adler32"); + grub_install_push_module ("gcry_crc"); + return 3; + } + return 0; +} + +void +grub_install_make_image_wrap_file (const char *dir, const char *prefix, + FILE *fp, const char *outname, + char *memdisk_path, + char *config_path, + const char *mkimage_target, int note) +{ + const struct grub_install_image_target_desc *tgt; + const char *const compnames[] = + { + [GRUB_COMPRESSION_AUTO] = "auto", + [GRUB_COMPRESSION_NONE] = "none", + [GRUB_COMPRESSION_XZ] = "xz", + [GRUB_COMPRESSION_LZMA] = "lzma", + }; + grub_size_t slen = 1; + char *s, *p; + char **pk, **md; + int dc = decompressors (); + + if (memdisk_path) + slen += 20 + grub_strlen (memdisk_path); + if (config_path) + slen += 20 + grub_strlen (config_path); + + for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) + slen += 20 + grub_strlen (*pk); + + for (md = modules.entries; *md; md++) + { + slen += 10 + grub_strlen (*md); + } + + p = s = xmalloc (slen); + if (memdisk_path) + { + p = grub_stpcpy (p, "--memdisk '"); + p = grub_stpcpy (p, memdisk_path); + *p++ = '\''; + *p++ = ' '; + } + if (config_path) + { + p = grub_stpcpy (p, "--config '"); + p = grub_stpcpy (p, config_path); + *p++ = '\''; + *p++ = ' '; + } + for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) + { + p = grub_stpcpy (p, "--pubkey '"); + p = grub_stpcpy (p, *pk); + *p++ = '\''; + *p++ = ' '; + } + + for (md = modules.entries; *md; md++) + { + *p++ = '\''; + p = grub_stpcpy (p, *md); + *p++ = '\''; + *p++ = ' '; + } + + *p = '\0'; + + grub_util_info ("grub-mkimage --directory '%s' --prefix '%s'" + " --output '%s' " + " --dtb '%s' " + "--format '%s' --compression '%s' %s %s\n", + dir, prefix, + outname, dtb ? : "", mkimage_target, + compnames[compression], note ? "--note" : "", s); + free (s); + + tgt = grub_install_get_image_target (mkimage_target); + if (!tgt) + grub_util_error (_("unknown target format %s"), mkimage_target); + + grub_install_generate_image (dir, prefix, fp, outname, + modules.entries, memdisk_path, + pubkeys, npubkeys, config_path, tgt, + note, compression, dtb); + while (dc--) + grub_install_pop_module (); +} + +void +grub_install_make_image_wrap (const char *dir, const char *prefix, + const char *outname, char *memdisk_path, + char *config_path, + const char *mkimage_target, int note) +{ + FILE *fp; + + fp = grub_util_fopen (outname, "wb"); + if (! fp) + grub_util_error (_("cannot open `%s': %s"), outname, + strerror (errno)); + grub_install_make_image_wrap_file (dir, prefix, fp, outname, + memdisk_path, config_path, + mkimage_target, note); + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), outname, strerror (errno)); + fclose (fp); +} + +static void +copy_by_ext (const char *srcd, + const char *dstd, + const char *extf, + int req) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + + d = grub_util_fd_opendir (srcd); + if (!d && !req) + return; + if (!d) + grub_util_error (_("cannot open directory `%s': %s"), + srcd, grub_util_fd_strerror ()); + + while ((de = grub_util_fd_readdir (d))) + { + const char *ext = strrchr (de->d_name, '.'); + if (ext && strcmp (ext, extf) == 0) + { + char *srcf = grub_util_path_concat (2, srcd, de->d_name); + char *dstf = grub_util_path_concat (2, dstd, de->d_name); + grub_install_compress_file (srcf, dstf, 1); + free (srcf); + free (dstf); + } + } + grub_util_fd_closedir (d); +} + +static void +copy_all (const char *srcd, + const char *dstd) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + + d = grub_util_fd_opendir (srcd); + if (!d) + grub_util_error (_("cannot open directory `%s': %s"), + srcd, grub_util_fd_strerror ()); + + while ((de = grub_util_fd_readdir (d))) + { + char *srcf; + char *dstf; + if (strcmp (de->d_name, ".") == 0 + || strcmp (de->d_name, "..") == 0) + continue; + srcf = grub_util_path_concat (2, srcd, de->d_name); + if (grub_util_is_special_file (srcf) + || grub_util_is_directory (srcf)) + continue; + dstf = grub_util_path_concat (2, dstd, de->d_name); + grub_install_compress_file (srcf, dstf, 1); + free (srcf); + free (dstf); + } + grub_util_fd_closedir (d); +} + +#if !(defined (GRUB_UTIL) && defined(ENABLE_NLS) && ENABLE_NLS) +static const char * +get_localedir (void) +{ + if (grub_install_locale_directory) + return grub_install_locale_directory; + else + return grub_util_get_localedir (); +} + +static void +copy_locales (const char *dstd) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + const char *locale_dir = get_localedir (); + + d = grub_util_fd_opendir (locale_dir); + if (!d) + { + grub_util_warn (_("cannot open directory `%s': %s"), + locale_dir, grub_util_fd_strerror ()); + return; + } + + while ((de = grub_util_fd_readdir (d))) + { + char *srcf; + char *dstf; + char *ext; + if (strcmp (de->d_name, ".") == 0) + continue; + if (strcmp (de->d_name, "..") == 0) + continue; + ext = grub_strrchr (de->d_name, '.'); + if (ext && (grub_strcmp (ext, ".mo") == 0 + || grub_strcmp (ext, ".gmo") == 0)) + { + srcf = grub_util_path_concat (2, locale_dir, de->d_name); + dstf = grub_util_path_concat (2, dstd, de->d_name); + ext = grub_strrchr (dstf, '.'); + grub_strcpy (ext, ".mo"); + } + else + { + srcf = grub_util_path_concat_ext (4, locale_dir, de->d_name, + "LC_MESSAGES", PACKAGE, ".mo"); + dstf = grub_util_path_concat_ext (2, dstd, de->d_name, ".mo"); + } + grub_install_compress_file (srcf, dstf, 0); + free (srcf); + free (dstf); + } + grub_util_fd_closedir (d); +} +#endif + +static void +grub_install_copy_nls(const char *src __attribute__ ((unused)), + const char *dst __attribute__ ((unused))) +{ +#if !(defined (GRUB_UTIL) && defined(ENABLE_NLS) && ENABLE_NLS) + char *dst_locale; + + dst_locale = grub_util_path_concat (2, dst, "locale"); + grub_install_mkdir_p (dst_locale); + clean_grub_dir (dst_locale); + + if (install_locales.is_default) + { + char *srcd = grub_util_path_concat (2, src, "po"); + copy_by_ext (srcd, dst_locale, ".mo", 0); + copy_locales (dst_locale); + free (srcd); + } + else + { + size_t i; + const char *locale_dir = get_localedir (); + + for (i = 0; i < install_locales.n_entries; i++) + { + char *srcf = grub_util_path_concat_ext (3, src, "po", + install_locales.entries[i], + ".mo"); + char *dstf = grub_util_path_concat_ext (2, dst_locale, + install_locales.entries[i], + ".mo"); + if (grub_install_compress_file (srcf, dstf, 0)) + { + free (srcf); + free (dstf); + continue; + } + free (srcf); + srcf = grub_util_path_concat_ext (4, locale_dir, + install_locales.entries[i], + "LC_MESSAGES", PACKAGE, ".mo"); + if (grub_install_compress_file (srcf, dstf, 0) == 0) + grub_util_error (_("cannot find locale `%s'"), + install_locales.entries[i]); + free (srcf); + free (dstf); + } + } + free (dst_locale); +#endif +} + +static struct +{ + const char *cpu; + const char *platform; +} platforms[GRUB_INSTALL_PLATFORM_MAX] = + { + [GRUB_INSTALL_PLATFORM_I386_PC] = { "i386", "pc" }, + [GRUB_INSTALL_PLATFORM_I386_EFI] = { "i386", "efi" }, + [GRUB_INSTALL_PLATFORM_I386_QEMU] = { "i386", "qemu" }, + [GRUB_INSTALL_PLATFORM_I386_COREBOOT] = { "i386", "coreboot" }, + [GRUB_INSTALL_PLATFORM_I386_MULTIBOOT] = { "i386", "multiboot" }, + [GRUB_INSTALL_PLATFORM_I386_IEEE1275] = { "i386", "ieee1275" }, + [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64", "efi" }, + [GRUB_INSTALL_PLATFORM_I386_XEN] = { "i386", "xen" }, + [GRUB_INSTALL_PLATFORM_X86_64_XEN] = { "x86_64", "xen" }, + [GRUB_INSTALL_PLATFORM_I386_XEN_PVH] = { "i386", "xen_pvh" }, + [GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON] = { "mipsel", "loongson" }, + [GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS] = { "mipsel", "qemu_mips" }, + [GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS] = { "mips", "qemu_mips" }, + [GRUB_INSTALL_PLATFORM_MIPSEL_ARC] = { "mipsel", "arc" }, + [GRUB_INSTALL_PLATFORM_MIPS_ARC] = { "mips", "arc" }, + [GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] = { "sparc64", "ieee1275" }, + [GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] = { "powerpc", "ieee1275" }, + [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64", "efi" }, + [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm", "efi" }, + [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64", "efi" }, + [GRUB_INSTALL_PLATFORM_MIPS64EL_EFI] = { "mips64el","efi" }, + [GRUB_INSTALL_PLATFORM_ARM_UBOOT] = { "arm", "uboot" }, + [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] = { "arm", "coreboot" }, + [GRUB_INSTALL_PLATFORM_RISCV32_EFI] = { "riscv32", "efi" }, + [GRUB_INSTALL_PLATFORM_RISCV64_EFI] = { "riscv64", "efi" }, + }; + +char * +grub_install_get_platforms_string (void) +{ + char **arr = xmalloc (sizeof (char *) * ARRAY_SIZE (platforms)); + int platform_strins_len = 0; + char *platforms_string; + char *ptr; + unsigned i; + for (i = 0; i < ARRAY_SIZE (platforms); i++) + { + arr[i] = xasprintf ("%s-%s", platforms[i].cpu, + platforms[i].platform); + platform_strins_len += strlen (arr[i]) + 2; + } + ptr = platforms_string = xmalloc (platform_strins_len); + qsort (arr, ARRAY_SIZE (platforms), sizeof (char *), grub_qsort_strcmp); + for (i = 0; i < ARRAY_SIZE (platforms); i++) + { + strcpy (ptr, arr[i]); + ptr += strlen (arr[i]); + *ptr++ = ','; + *ptr++ = ' '; + free (arr[i]); + } + ptr[-2] = 0; + free (arr); + + return platforms_string; +} + +char * +grub_install_get_platform_name (enum grub_install_plat platid) +{ + return xasprintf ("%s-%s", platforms[platid].cpu, + platforms[platid].platform); +} + +const char * +grub_install_get_platform_cpu (enum grub_install_plat platid) +{ + return platforms[platid].cpu; +} + +const char * +grub_install_get_platform_platform (enum grub_install_plat platid) +{ + return platforms[platid].platform; +} + + +void +grub_install_copy_files (const char *src, + const char *dst, + enum grub_install_plat platid) +{ + char *dst_platform, *dst_fonts; + const char *pkgdatadir = grub_util_get_pkgdatadir (); + char *themes_dir; + + { + char *platform; + platform = xasprintf ("%s-%s", platforms[platid].cpu, + platforms[platid].platform); + dst_platform = grub_util_path_concat (2, dst, platform); + free (platform); + } + dst_fonts = grub_util_path_concat (2, dst, "fonts"); + grub_install_mkdir_p (dst_platform); + clean_grub_dir (dst); + clean_grub_dir (dst_platform); + + grub_install_copy_nls(src, dst); + + if (install_modules.is_default) + copy_by_ext (src, dst_platform, ".mod", 1); + else + { + struct grub_util_path_list *path_list, *p; + + path_list = grub_util_resolve_dependencies (src, "moddep.lst", + install_modules.entries); + for (p = path_list; p; p = p->next) + { + const char *srcf = p->name; + const char *dir; + char *dstf; + + dir = grub_strrchr (srcf, '/'); + if (dir) + dir++; + else + dir = srcf; + dstf = grub_util_path_concat (2, dst_platform, dir); + grub_install_compress_file (srcf, dstf, 1); + free (dstf); + } + + grub_util_free_path_list (path_list); + } + + const char *pkglib_DATA[] = {"efiemu32.o", "efiemu64.o", + "moddep.lst", "command.lst", + "fs.lst", "partmap.lst", + "parttool.lst", + "video.lst", "crypto.lst", + "terminal.lst", "modinfo.sh" }; + size_t i; + + for (i = 0; i < ARRAY_SIZE (pkglib_DATA); i++) + { + char *srcf = grub_util_path_concat (2, src, pkglib_DATA[i]); + char *dstf = grub_util_path_concat (2, dst_platform, pkglib_DATA[i]); + if (i == 0 || i == 1) + grub_install_compress_file (srcf, dstf, 0); + else + grub_install_compress_file (srcf, dstf, 1); + free (srcf); + free (dstf); + } + + if (install_themes.is_default) + { + install_themes.is_default = 0; + install_themes.n_entries = 1; + install_themes.entries = xmalloc (2 * sizeof (install_themes.entries[0])); + install_themes.entries[0] = xstrdup ("starfield"); + install_themes.entries[1] = NULL; + } + + if (grub_install_themes_directory) + themes_dir = xstrdup (grub_install_themes_directory); + else + themes_dir = grub_util_path_concat (2, grub_util_get_pkgdatadir (), + "themes"); + + for (i = 0; i < install_themes.n_entries; i++) + { + char *srcf = grub_util_path_concat (3, themes_dir, + install_themes.entries[i], + "theme.txt"); + if (grub_util_is_regular (srcf)) + { + char *srcd = grub_util_path_concat (2, themes_dir, + install_themes.entries[i]); + char *dstd = grub_util_path_concat (3, dst, "themes", + install_themes.entries[i]); + grub_install_mkdir_p (dstd); + copy_all (srcd, dstd); + free (srcd); + free (dstd); + } + free (srcf); + } + + free (themes_dir); + + if (install_fonts.is_default) + { + install_fonts.is_default = 0; + install_fonts.n_entries = 1; + install_fonts.entries = xmalloc (2 * sizeof (install_fonts.entries[0])); + install_fonts.entries[0] = xstrdup ("unicode"); + install_fonts.entries[1] = NULL; + } + + grub_install_mkdir_p (dst_fonts); + + for (i = 0; i < install_fonts.n_entries; i++) + { + char *srcf = grub_util_path_concat_ext (2, pkgdatadir, + install_fonts.entries[i], + ".pf2"); + char *dstf = grub_util_path_concat_ext (2, dst_fonts, + install_fonts.entries[i], + ".pf2"); + + grub_install_compress_file (srcf, dstf, 0); + free (srcf); + free (dstf); + } + + free (dst_platform); + free (dst_fonts); +} + +enum grub_install_plat +grub_install_get_target (const char *src) +{ + char *fn; + grub_util_fd_t f; + char buf[8192]; + ssize_t r; + char *c, *pl, *p; + size_t i; + fn = grub_util_path_concat (2, src, "modinfo.sh"); + f = grub_util_fd_open (fn, GRUB_UTIL_FD_O_RDONLY); + if (!GRUB_UTIL_FD_IS_VALID (f)) + grub_util_error (_("%s doesn't exist. Please specify --target or --directory"), + fn); + r = grub_util_fd_read (f, buf, sizeof (buf) - 1); + if (r < 0) + grub_util_error (_("cannot read `%s': %s"), fn, strerror (errno)); + grub_util_fd_close (f); + buf[r] = '\0'; + c = strstr (buf, "grub_modinfo_target_cpu="); + if (!c || (c != buf && !grub_isspace (*(c-1)))) + grub_util_error (_("invalid modinfo file `%s'"), fn); + pl = strstr (buf, "grub_modinfo_platform="); + if (!pl || (pl != buf && !grub_isspace (*(pl-1)))) + grub_util_error (_("invalid modinfo file `%s'"), fn); + c += sizeof ("grub_modinfo_target_cpu=") - 1; + pl += sizeof ("grub_modinfo_platform=") - 1; + for (p = c; *p && !grub_isspace (*p); p++); + *p = '\0'; + for (p = pl; *p && !grub_isspace (*p); p++); + *p = '\0'; + + for (i = 0; i < ARRAY_SIZE (platforms); i++) + if (strcmp (platforms[i].cpu, c) == 0 + && strcmp (platforms[i].platform, pl) == 0) + { + free (fn); + return i; + } + grub_util_error (_("Unknown platform `%s-%s'"), c, pl); +} + + +void +grub_util_unlink_recursive (const char *name) +{ + grub_util_fd_dir_t d; + grub_util_fd_dirent_t de; + + d = grub_util_fd_opendir (name); + + while ((de = grub_util_fd_readdir (d))) + { + char *fp; + if (strcmp (de->d_name, ".") == 0) + continue; + if (strcmp (de->d_name, "..") == 0) + continue; + fp = grub_util_path_concat (2, name, de->d_name); + if (grub_util_is_special_file (fp)) + { + free (fp); + continue; + } + if (grub_util_is_regular (fp)) + grub_util_unlink (fp); + else if (grub_util_is_directory (fp)) + grub_util_unlink_recursive (fp); + free (fp); + } + grub_util_rmdir (name); + grub_util_fd_closedir (d); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-install.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-install.c new file mode 100644 index 0000000..b45a4c0 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-install.c @@ -0,0 +1,1982 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include "progname.h" + +static char *target; +static int removable = 0; +static int recheck = 0; +static int update_nvram = 1; +static char *install_device = NULL; +static char *debug_image = NULL; +static char *rootdir = NULL; +static char *bootdir = NULL; +static int allow_floppy = 0; +static int force_file_id = 0; +static char *disk_module = NULL; +static char *efidir = NULL; +static char *macppcdir = NULL; +static int force = 0; +static int have_abstractions = 0; +static int have_cryptodisk = 0; +static char * bootloader_id; +static int have_load_cfg = 0; +static FILE * load_cfg_f = NULL; +static char *load_cfg; +static int install_bootsector = 1; +static char *label_font; +static char *label_color; +static char *label_bgcolor; +static char *product_version; +static int add_rs_codes = 1; + +enum + { + OPTION_BOOT_DIRECTORY = 0x301, + OPTION_ROOT_DIRECTORY, + OPTION_TARGET, + OPTION_SETUP, + OPTION_MKRELPATH, + OPTION_MKDEVICEMAP, + OPTION_PROBE, + OPTION_EDITENV, + OPTION_ALLOW_FLOPPY, + OPTION_RECHECK, + OPTION_FORCE, + OPTION_FORCE_FILE_ID, + OPTION_NO_NVRAM, + OPTION_REMOVABLE, + OPTION_BOOTLOADER_ID, + OPTION_EFI_DIRECTORY, + OPTION_FONT, + OPTION_DEBUG, + OPTION_DEBUG_IMAGE, + OPTION_NO_FLOPPY, + OPTION_DISK_MODULE, + OPTION_NO_BOOTSECTOR, + OPTION_NO_RS_CODES, + OPTION_MACPPC_DIRECTORY, + OPTION_LABEL_FONT, + OPTION_LABEL_COLOR, + OPTION_LABEL_BGCOLOR, + OPTION_PRODUCT_VERSION + }; + +static int fs_probe = 1; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + if (grub_install_parse (key, arg)) + return 0; + switch (key) + { + case OPTION_FORCE_FILE_ID: + force_file_id = 1; + return 0; + case 's': + fs_probe = 0; + return 0; + + case OPTION_SETUP: + if (!grub_strstr (arg, "setup")) + install_bootsector = 0; + return 0; + + case OPTION_PRODUCT_VERSION: + free (product_version); + product_version = xstrdup (arg); + return 0; + case OPTION_LABEL_FONT: + free (label_font); + label_font = xstrdup (arg); + return 0; + + case OPTION_LABEL_COLOR: + free (label_color); + label_color = xstrdup (arg); + return 0; + + case OPTION_LABEL_BGCOLOR: + free (label_bgcolor); + label_bgcolor = xstrdup (arg); + return 0; + + /* Accept and ignore for compatibility. */ + case OPTION_FONT: + case OPTION_MKRELPATH: + case OPTION_PROBE: + case OPTION_EDITENV: + case OPTION_MKDEVICEMAP: + case OPTION_NO_FLOPPY: + return 0; + case OPTION_ROOT_DIRECTORY: + /* Accept for compatibility. */ + free (rootdir); + rootdir = xstrdup (arg); + return 0; + + case OPTION_BOOT_DIRECTORY: + free (bootdir); + bootdir = xstrdup (arg); + return 0; + + case OPTION_MACPPC_DIRECTORY: + free (macppcdir); + macppcdir = xstrdup (arg); + return 0; + + case OPTION_EFI_DIRECTORY: + free (efidir); + efidir = xstrdup (arg); + return 0; + + case OPTION_DISK_MODULE: + free (disk_module); + disk_module = xstrdup (arg); + return 0; + + case OPTION_TARGET: + free (target); + target = xstrdup (arg); + return 0; + + case OPTION_DEBUG_IMAGE: + free (debug_image); + debug_image = xstrdup (arg); + return 0; + + case OPTION_NO_NVRAM: + update_nvram = 0; + return 0; + + case OPTION_FORCE: + force = 1; + return 0; + + case OPTION_RECHECK: + recheck = 1; + return 0; + + case OPTION_REMOVABLE: + removable = 1; + return 0; + + case OPTION_ALLOW_FLOPPY: + allow_floppy = 1; + return 0; + + case OPTION_NO_BOOTSECTOR: + install_bootsector = 0; + return 0; + + case OPTION_NO_RS_CODES: + add_rs_codes = 0; + return 0; + + case OPTION_DEBUG: + verbosity++; + return 0; + + case OPTION_BOOTLOADER_ID: + free (bootloader_id); + bootloader_id = xstrdup (arg); + return 0; + + case ARGP_KEY_ARG: + if (install_device) + grub_util_error ("%s", _("More than one install device?")); + install_device = xstrdup (arg); + return 0; + + default: + return ARGP_ERR_UNKNOWN; + } +} + + +static struct argp_option options[] = { + GRUB_INSTALL_OPTIONS, + {"boot-directory", OPTION_BOOT_DIRECTORY, N_("DIR"), + 0, N_("install GRUB images under the directory DIR/%s instead of the %s directory"), 2}, + {"root-directory", OPTION_ROOT_DIRECTORY, N_("DIR"), + OPTION_HIDDEN, 0, 2}, + {"font", OPTION_FONT, N_("FILE"), + OPTION_HIDDEN, 0, 2}, + {"target", OPTION_TARGET, N_("TARGET"), + /* TRANSLATORS: "TARGET" as in "target platform". */ + 0, N_("install GRUB for TARGET platform [default=%s]; available targets: %s"), 2}, + {"grub-setup", OPTION_SETUP, "FILE", OPTION_HIDDEN, 0, 2}, + {"grub-mkrelpath", OPTION_MKRELPATH, "FILE", OPTION_HIDDEN, 0, 2}, + {"grub-mkdevicemap", OPTION_MKDEVICEMAP, "FILE", OPTION_HIDDEN, 0, 2}, + {"grub-probe", OPTION_PROBE, "FILE", OPTION_HIDDEN, 0, 2}, + {"grub-editenv", OPTION_EDITENV, "FILE", OPTION_HIDDEN, 0, 2}, + {"allow-floppy", OPTION_ALLOW_FLOPPY, 0, 0, + /* TRANSLATORS: "may break" doesn't just mean that option wouldn't have any + effect but that it will make the resulting install unbootable from HDD. */ + N_("make the drive also bootable as floppy (default for fdX devices)." + " May break on some BIOSes."), 2}, + {"recheck", OPTION_RECHECK, 0, 0, + N_("delete device map if it already exists"), 2}, + {"force", OPTION_FORCE, 0, 0, + N_("install even if problems are detected"), 2}, + {"force-file-id", OPTION_FORCE_FILE_ID, 0, 0, + N_("use identifier file even if UUID is available"), 2}, + {"disk-module", OPTION_DISK_MODULE, N_("MODULE"), 0, + N_("disk module to use (biosdisk or native). " + "This option is only available on BIOS target."), 2}, + {"no-nvram", OPTION_NO_NVRAM, 0, 0, + N_("don't update the `boot-device'/`Boot*' NVRAM variables. " + "This option is only available on EFI and IEEE1275 targets."), 2}, + {"skip-fs-probe",'s',0, 0, + N_("do not probe for filesystems in DEVICE"), 0}, + {"no-bootsector", OPTION_NO_BOOTSECTOR, 0, 0, + N_("do not install bootsector"), 0}, + {"no-rs-codes", OPTION_NO_RS_CODES, 0, 0, + N_("Do not apply any reed-solomon codes when embedding core.img. " + "This option is only available on x86 BIOS targets."), 0}, + + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"no-floppy", OPTION_NO_FLOPPY, 0, OPTION_HIDDEN, 0, 2}, + {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, + {"removable", OPTION_REMOVABLE, 0, 0, + N_("the installation device is removable. " + "This option is only available on EFI."), 2}, + {"bootloader-id", OPTION_BOOTLOADER_ID, N_("ID"), 0, + N_("the ID of bootloader. This option is only available on EFI and Macs."), 2}, + {"efi-directory", OPTION_EFI_DIRECTORY, N_("DIR"), 0, + N_("use DIR as the EFI System Partition root."), 2}, + {"macppc-directory", OPTION_MACPPC_DIRECTORY, N_("DIR"), 0, + N_("use DIR for PPC MAC install."), 2}, + {"label-font", OPTION_LABEL_FONT, N_("FILE"), 0, N_("use FILE as font for label"), 2}, + {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2}, + {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2}, + {"product-version", OPTION_PRODUCT_VERSION, N_("STRING"), 0, N_("use STRING as product version"), 2}, + {0, 0, 0, 0, 0, 0} +}; + +static const char * +get_default_platform (void) +{ +#ifdef __powerpc__ + return "powerpc-ieee1275"; +#elif defined (__sparc__) || defined (__sparc64__) + return "sparc64-ieee1275"; +#elif defined (__MIPSEL__) +#if _MIPS_SIM == _ABI64 + return "mips64el-efi"; +#else + return "mipsel-loongson"; +#endif +#elif defined (__MIPSEB__) + return "mips-arc"; +#elif defined (__ia64__) + return "ia64-efi"; +#elif defined (__arm__) + return grub_install_get_default_arm_platform (); +#elif defined (__aarch64__) + return "arm64-efi"; +#elif defined (__amd64__) || defined (__x86_64__) || defined (__i386__) + return grub_install_get_default_x86_platform (); +#else + return NULL; +#endif +} + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case OPTION_BOOT_DIRECTORY: + return xasprintf (text, GRUB_DIR_NAME, GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME); + case OPTION_TARGET: + { + char *plats = grub_install_get_platforms_string (); + char *ret; + ret = xasprintf (text, get_default_platform (), plats); + free (plats); + return ret; + } + case ARGP_KEY_HELP_POST_DOC: + return xasprintf (text, program_name, GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME); + default: + return grub_install_help_filter (key, text, input); + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +/* TRANSLATORS: INSTALL_DEVICE isn't an identifier and is the DEVICE you + install to. */ +struct argp argp = { + options, argp_parser, N_("[OPTION] [INSTALL_DEVICE]"), + N_("Install GRUB on your drive.")"\v" + N_("INSTALL_DEVICE must be system device filename.\n" + "%s copies GRUB images into %s. On some platforms, it" + " may also install GRUB into the boot sector."), + NULL, help_filter, NULL +}; + +static int +probe_raid_level (grub_disk_t disk) +{ + /* disk might be NULL in the case of a LVM physical volume with no LVM + signature. Ignore such cases here. */ + if (!disk) + return -1; + + if (disk->dev->id != GRUB_DISK_DEVICE_DISKFILTER_ID) + return -1; + + if (disk->name[0] != 'm' || disk->name[1] != 'd') + return -1; + + if (!((struct grub_diskfilter_lv *) disk->data)->segments) + return -1; + return ((struct grub_diskfilter_lv *) disk->data)->segments->type; +} + +static void +push_partmap_module (const char *map, void *data __attribute__ ((unused))) +{ + char buf[50]; + + if (strcmp (map, "openbsd") == 0 || strcmp (map, "netbsd") == 0) + { + grub_install_push_module ("part_bsd"); + return; + } + + snprintf (buf, sizeof (buf), "part_%s", map); + grub_install_push_module (buf); +} + +static void +push_cryptodisk_module (const char *mod, void *data __attribute__ ((unused))) +{ + grub_install_push_module (mod); +} + +static void +probe_mods (grub_disk_t disk) +{ + grub_partition_t part; + grub_disk_memberlist_t list = NULL, tmp; + int raid_level; + + if (disk->partition == NULL) + grub_util_info ("no partition map found for %s", disk->name); + + for (part = disk->partition; part; part = part->parent) + push_partmap_module (part->partmap->name, NULL); + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID) + { + grub_diskfilter_get_partmap (disk, push_partmap_module, NULL); + have_abstractions = 1; + } + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID + && (grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0 || + grub_memcmp (disk->name, "lvmid/", sizeof ("lvmid/") - 1) == 0)) + grub_install_push_module ("lvm"); + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID + && grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0) + grub_install_push_module ("ldm"); + + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + { + grub_util_cryptodisk_get_abstraction (disk, + push_cryptodisk_module, NULL); + have_abstractions = 1; + have_cryptodisk = 1; + } + + raid_level = probe_raid_level (disk); + if (raid_level >= 0) + { + grub_install_push_module ("diskfilter"); + if (disk->dev->disk_raidname) + grub_install_push_module (disk->dev->disk_raidname (disk)); + } + if (raid_level == 5) + grub_install_push_module ("raid5rec"); + if (raid_level == 6) + grub_install_push_module ("raid6rec"); + + /* In case of LVM/RAID, check the member devices as well. */ + if (disk->dev->disk_memberlist) + list = disk->dev->disk_memberlist (disk); + while (list) + { + probe_mods (list->disk); + tmp = list->next; + free (list); + list = tmp; + } +} + +static int +have_bootdev (enum grub_install_plat pl) +{ + switch (pl) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + return 1; + + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + return 0; + + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + return 0; + } + return 0; +} + +static void +probe_cryptodisk_uuid (grub_disk_t disk) +{ + grub_disk_memberlist_t list = NULL, tmp; + + /* In case of LVM/RAID, check the member devices as well. */ + if (disk->dev->disk_memberlist) + { + list = disk->dev->disk_memberlist (disk); + } + while (list) + { + probe_cryptodisk_uuid (list->disk); + tmp = list->next; + free (list); + list = tmp; + } + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + { + const char *uuid = grub_util_cryptodisk_get_uuid (disk); + if (!load_cfg_f) + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + have_load_cfg = 1; + + fprintf (load_cfg_f, "cryptomount -u %s\n", + uuid); + } +} + +static int +is_same_disk (const char *a, const char *b) +{ + while (1) + { + if ((*a == ',' || *a == '\0') && (*b == ',' || *b == '\0')) + return 1; + if (*a != *b) + return 0; + if (*a == '\\') + { + if (a[1] != b[1]) + return 0; + a += 2; + b += 2; + continue; + } + a++; + b++; + } +} + +static char * +get_rndstr (void) +{ + grub_uint8_t rnd[15]; + const size_t sz = sizeof (rnd) * GRUB_CHAR_BIT / 5; + char * ret = xmalloc (sz + 1); + size_t i; + if (grub_get_random (rnd, sizeof (rnd))) + grub_util_error ("%s", _("couldn't retrieve random data")); + for (i = 0; i < sz; i++) + { + grub_size_t b = i * 5; + grub_uint8_t r; + grub_size_t f1 = GRUB_CHAR_BIT - b % GRUB_CHAR_BIT; + grub_size_t f2; + if (f1 > 5) + f1 = 5; + f2 = 5 - f1; + r = (rnd[b / GRUB_CHAR_BIT] >> (b % GRUB_CHAR_BIT)) & ((1 << f1) - 1); + if (f2) + r |= (rnd[b / GRUB_CHAR_BIT + 1] & ((1 << f2) - 1)) << f1; + if (r < 10) + ret[i] = '0' + r; + else + ret[i] = 'a' + (r - 10); + } + ret[sz] = '\0'; + return ret; +} + +static char * +escape (const char *in) +{ + char *ptr; + char *ret; + int overhead = 0; + + for (ptr = (char*)in; *ptr; ptr++) + if (*ptr == '\'') + overhead += 3; + ret = grub_malloc (ptr - in + overhead + 1); + if (!ret) + return NULL; + + grub_strchrsub (ret, in, '\'', "'\\''"); + return ret; +} + +static struct grub_util_config config; + +static void +device_map_check_duplicates (const char *dev_map) +{ + FILE *fp; + char buf[1024]; /* XXX */ + size_t alloced = 8; + size_t filled = 0; + char **d; + size_t i; + + if (dev_map[0] == '\0') + return; + + fp = grub_util_fopen (dev_map, "r"); + if (! fp) + return; + + d = xmalloc (alloced * sizeof (d[0])); + + while (fgets (buf, sizeof (buf), fp)) + { + char *p = buf; + char *e; + + /* Skip leading spaces. */ + while (*p && grub_isspace (*p)) + p++; + + /* If the first character is `#' or NUL, skip this line. */ + if (*p == '\0' || *p == '#') + continue; + + if (*p != '(') + continue; + + p++; + + e = p; + p = strchr (p, ')'); + if (! p) + continue; + + if (filled >= alloced) + { + alloced *= 2; + d = xrealloc (d, alloced * sizeof (d[0])); + } + + *p = '\0'; + + d[filled++] = xstrdup (e); + } + + fclose (fp); + + qsort (d, filled, sizeof (d[0]), grub_qsort_strcmp); + + for (i = 0; i + 1 < filled; i++) + if (strcmp (d[i], d[i+1]) == 0) + { + grub_util_error (_("the drive %s is defined multiple times in the device map %s"), + d[i], dev_map); + } + + for (i = 0; i < filled; i++) + free (d[i]); + + free (d); +} + +static grub_err_t +write_to_disk (grub_device_t dev, const char *fn) +{ + char *core_img; + size_t core_size; + grub_err_t err; + + core_size = grub_util_get_image_size (fn); + + core_img = grub_util_read_image (fn); + + grub_util_info ("writing `%s' to `%s'", fn, dev->disk->name); + err = grub_disk_write (dev->disk, 0, 0, + core_size, core_img); + free (core_img); + return err; +} + +static int +is_prep_partition (grub_device_t dev) +{ + if (!dev->disk) + return 0; + if (!dev->disk->partition) + return 0; + if (strcmp(dev->disk->partition->partmap->name, "msdos") == 0) + return (dev->disk->partition->msdostype == 0x41); + + if (strcmp (dev->disk->partition->partmap->name, "gpt") == 0) + { + struct grub_gpt_partentry gptdata; + grub_partition_t p = dev->disk->partition; + int ret = 0; + dev->disk->partition = dev->disk->partition->parent; + + if (grub_disk_read (dev->disk, p->offset, p->index, + sizeof (gptdata), &gptdata) == 0) + { + const grub_gpt_part_guid_t template = { + grub_cpu_to_le32_compile_time (0x9e1a2d38), + grub_cpu_to_le16_compile_time (0xc612), + grub_cpu_to_le16_compile_time (0x4316), + { 0xaa, 0x26, 0x8b, 0x49, 0x52, 0x1e, 0x5a, 0x8b } + }; + + ret = grub_memcmp (&template, &gptdata.type, + sizeof (template)) == 0; + } + dev->disk->partition = p; + return ret; + } + + return 0; +} + +static int +is_prep_empty (grub_device_t dev) +{ + grub_disk_addr_t dsize, addr; + grub_uint32_t buffer[32768]; + + dsize = grub_disk_get_size (dev->disk); + for (addr = 0; addr < dsize; + addr += sizeof (buffer) / GRUB_DISK_SECTOR_SIZE) + { + grub_size_t sz = sizeof (buffer); + grub_uint32_t *ptr; + + if (sizeof (buffer) / GRUB_DISK_SECTOR_SIZE > dsize - addr) + sz = (dsize - addr) * GRUB_DISK_SECTOR_SIZE; + grub_disk_read (dev->disk, addr, 0, sz, buffer); + + if (addr == 0 && grub_memcmp (buffer, ELFMAG, SELFMAG) == 0) + return 1; + + for (ptr = buffer; ptr < buffer + sz / sizeof (*buffer); ptr++) + if (*ptr) + return 0; + } + + return 1; +} + +static void +bless (grub_device_t dev, const char *path, int x86) +{ + struct stat st; + grub_err_t err; + + grub_util_info ("blessing %s", path); + + if (stat (path, &st) < 0) + grub_util_error (N_("cannot stat `%s': %s"), + path, strerror (errno)); + + err = grub_mac_bless_inode (dev, st.st_ino, S_ISDIR (st.st_mode), x86); + if (err) + grub_util_error ("%s", grub_errmsg); + grub_util_info ("blessed"); +} + +static void +fill_core_services (const char *core_services) +{ + char *label; + FILE *f; + char *label_text; + char *label_string = xasprintf ("%s %s", bootloader_id, product_version); + char *sysv_plist; + + label = grub_util_path_concat (2, core_services, ".disk_label"); + grub_util_info ("rendering label %s", label_string); + grub_util_render_label (label_font, label_bgcolor ? : "white", + label_color ? : "black", label_string, label); + grub_util_info ("label rendered"); + free (label); + label_text = grub_util_path_concat (2, core_services, ".disk_label.contentDetails"); + f = grub_util_fopen (label_text, "wb"); + fprintf (f, "%s\n", label_string); + fclose (f); + free (label_string); + free (label_text); + + sysv_plist = grub_util_path_concat (2, core_services, "SystemVersion.plist"); + f = grub_util_fopen (sysv_plist, "wb"); + fprintf (f, + "\n" + "\n" + " ProductBuildVersion\n" + " \n" + " ProductName\n" + " %s\n" + " ProductVersion\n" + " %s\n" + "\n" + "\n", bootloader_id, product_version); + fclose (f); + free (sysv_plist); +} + +int +main (int argc, char *argv[]) +{ + int is_efi = 0; + const char *efi_distributor = NULL; + const char *efi_file = NULL; + char **grub_devices; + grub_fs_t grub_fs; + grub_device_t grub_dev = NULL; + enum grub_install_plat platform; + char *grubdir, *device_map; + char **curdev, **curdrive; + char **grub_drives; + char *relative_grubdir; + char **efidir_device_names = NULL; + grub_device_t efidir_grub_dev = NULL; + char *efidir_grub_devname; + int efidir_is_mac = 0; + int is_prep = 0; + const char *pkgdatadir; + + grub_util_host_init (&argc, &argv); + product_version = xstrdup (PACKAGE_VERSION); + pkgdatadir = grub_util_get_pkgdatadir (); + label_font = grub_util_path_concat (2, pkgdatadir, "unicode.pf2"); + + argp_parse (&argp, argc, argv, 0, 0, 0); + + if (verbosity > 1) + grub_env_set ("debug", "all"); + + grub_util_load_config (&config); + + if (!bootloader_id && config.grub_distributor) + { + char *ptr; + bootloader_id = xstrdup (config.grub_distributor); + for (ptr = bootloader_id; *ptr && *ptr != ' '; ptr++) + if (*ptr >= 'A' && *ptr <= 'Z') + *ptr = *ptr - 'A' + 'a'; + *ptr = '\0'; + } + if (!bootloader_id || bootloader_id[0] == '\0') + { + free (bootloader_id); + bootloader_id = xstrdup ("grub"); + } + + if (!grub_install_source_directory) + { + if (!target) + { + const char * t; + t = get_default_platform (); + if (!t) + grub_util_error ("%s", + _("Unable to determine your platform." + " Use --target.") + ); + target = xstrdup (t); + } + grub_install_source_directory + = grub_util_path_concat (2, grub_util_get_pkglibdir (), target); + } + + platform = grub_install_get_target (grub_install_source_directory); + + { + char *platname = grub_install_get_platform_name (platform); + fprintf (stderr, _("Installing for %s platform.\n"), platname); + free (platname); + } + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + if (!disk_module) + disk_module = xstrdup ("biosdisk"); + break; + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + break; + + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + disk_module = xstrdup ("native"); + break; + + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + if (!install_device) + grub_util_error ("%s", _("install device isn't specified")); + break; + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + if (install_device) + is_prep = 1; + break; + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + break; + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + free (install_device); + install_device = NULL; + break; + + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + if (!bootdir) + bootdir = grub_util_path_concat (3, "/", rootdir, GRUB_BOOT_DIR_NAME); + + { + char * t = grub_util_path_concat (2, bootdir, GRUB_DIR_NAME); + grub_install_mkdir_p (t); + grubdir = grub_canonicalize_file_name (t); + if (!grubdir) + grub_util_error (_("failed to get canonical path of `%s'"), t); + free (t); + } + device_map = grub_util_path_concat (2, grubdir, "device.map"); + + if (recheck) + grub_util_unlink (device_map); + + device_map_check_duplicates (device_map); + grub_util_biosdisk_init (device_map); + + /* Initialize all modules. */ + grub_init_all (); + grub_gcry_init_all (); + grub_hostfs_init (); + grub_host_init (); + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + is_efi = 1; + break; + default: + is_efi = 0; + break; + + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + /* Find the EFI System Partition. */ + + if (is_efi) + { + grub_fs_t fs; + free (install_device); + install_device = NULL; + if (!efidir) + { + char *d = grub_util_path_concat (2, bootdir, "efi"); + char *dr = NULL; + if (!grub_util_is_directory (d)) + { + free (d); + d = grub_util_path_concat (2, bootdir, "EFI"); + } + /* + The EFI System Partition may have been given directly using + --root-directory. + */ + if (!grub_util_is_directory (d) + && rootdir && grub_strcmp (rootdir, "/") != 0) + { + free (d); + d = xstrdup (rootdir); + } + if (grub_util_is_directory (d)) + dr = grub_make_system_path_relative_to_its_root (d); + /* Is it a mount point? */ + if (dr && dr[0] == '\0') + efidir = d; + else + free (d); + free (dr); + } + if (!efidir) + grub_util_error ("%s", _("cannot find EFI directory")); + efidir_device_names = grub_guess_root_devices (efidir); + if (!efidir_device_names || !efidir_device_names[0]) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), + efidir); + install_device = efidir_device_names[0]; + + for (curdev = efidir_device_names; *curdev; curdev++) + grub_util_pull_device (*curdev); + + efidir_grub_devname = grub_util_get_grub_dev (efidir_device_names[0]); + if (!efidir_grub_devname) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + efidir_device_names[0]); + + efidir_grub_dev = grub_device_open (efidir_grub_devname); + if (! efidir_grub_dev) + grub_util_error ("%s", grub_errmsg); + + fs = grub_fs_probe (efidir_grub_dev); + if (! fs) + grub_util_error ("%s", grub_errmsg); + + efidir_is_mac = 0; + + if (grub_strcmp (fs->name, "hfs") == 0 + || grub_strcmp (fs->name, "hfsplus") == 0) + efidir_is_mac = 1; + + if (!efidir_is_mac && grub_strcmp (fs->name, "fat") != 0) + grub_util_error (_("%s doesn't look like an EFI partition"), efidir); + + /* The EFI specification requires that an EFI System Partition must + contain an "EFI" subdirectory, and that OS loaders are stored in + subdirectories below EFI. Vendors are expected to pick names that do + not collide with other vendors. To minimise collisions, we use the + name of our distributor if possible. + */ + char *t; + efi_distributor = bootloader_id; + if (removable) + { + /* The specification makes stricter requirements of removable + devices, in order that only one image can be automatically loaded + from them. The image must always reside under /EFI/BOOT, and it + must have a specific file name depending on the architecture. + */ + efi_distributor = "BOOT"; + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + efi_file = "BOOTIA32.EFI"; + break; + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + efi_file = "BOOTX64.EFI"; + break; + case GRUB_INSTALL_PLATFORM_IA64_EFI: + efi_file = "BOOTIA64.EFI"; + break; + case GRUB_INSTALL_PLATFORM_ARM_EFI: + efi_file = "BOOTARM.EFI"; + break; + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + efi_file = "BOOTAA64.EFI"; + break; + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + efi_file = "BOOTMIPS64EL.EFI"; + break; + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + efi_file = "BOOTRISCV32.EFI"; + break; + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + efi_file = "BOOTRISCV64.EFI"; + break; + default: + grub_util_error ("%s", _("You've found a bug")); + break; + } + } + else + { + /* It is convenient for each architecture to have a different + efi_file, so that different versions can be installed in parallel. + */ + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + efi_file = "grubia32.efi"; + break; + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + efi_file = "grubx64.efi"; + break; + case GRUB_INSTALL_PLATFORM_IA64_EFI: + efi_file = "grubia64.efi"; + break; + case GRUB_INSTALL_PLATFORM_ARM_EFI: + efi_file = "grubarm.efi"; + break; + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + efi_file = "grubaa64.efi"; + break; + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + efi_file = "grubmips64el.efi"; + break; + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + efi_file = "grubriscv32.efi"; + break; + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + efi_file = "grubriscv64.efi"; + break; + default: + efi_file = "grub.efi"; + break; + } + } + t = grub_util_path_concat (3, efidir, "EFI", efi_distributor); + free (efidir); + efidir = t; + grub_install_mkdir_p (efidir); + } + + if (platform == GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275) + { + int is_guess = 0; + if (!macppcdir) + { + char *d; + + is_guess = 1; + d = grub_util_path_concat (2, bootdir, "macppc"); + if (!grub_util_is_directory (d)) + { + free (d); + d = grub_util_path_concat (2, bootdir, "efi"); + } + /* Find the Mac HFS(+) System Partition. */ + if (!grub_util_is_directory (d)) + { + free (d); + d = grub_util_path_concat (2, bootdir, "EFI"); + } + if (!grub_util_is_directory (d)) + { + free (d); + d = 0; + } + if (d) + macppcdir = d; + } + if (macppcdir) + { + char **macppcdir_device_names = NULL; + grub_device_t macppcdir_grub_dev = NULL; + char *macppcdir_grub_devname; + grub_fs_t fs; + + macppcdir_device_names = grub_guess_root_devices (macppcdir); + if (!macppcdir_device_names || !macppcdir_device_names[0]) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), + macppcdir); + + for (curdev = macppcdir_device_names; *curdev; curdev++) + grub_util_pull_device (*curdev); + + macppcdir_grub_devname = grub_util_get_grub_dev (macppcdir_device_names[0]); + if (!macppcdir_grub_devname) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + macppcdir_device_names[0]); + + macppcdir_grub_dev = grub_device_open (macppcdir_grub_devname); + if (! macppcdir_grub_dev) + grub_util_error ("%s", grub_errmsg); + + fs = grub_fs_probe (macppcdir_grub_dev); + if (! fs) + grub_util_error ("%s", grub_errmsg); + + if (grub_strcmp (fs->name, "hfs") != 0 + && grub_strcmp (fs->name, "hfsplus") != 0 + && !is_guess) + grub_util_error (_("filesystem on %s is neither HFS nor HFS+"), + macppcdir); + if (grub_strcmp (fs->name, "hfs") == 0 + || grub_strcmp (fs->name, "hfsplus") == 0) + { + install_device = macppcdir_device_names[0]; + is_prep = 0; + } + } + } + + grub_install_copy_files (grub_install_source_directory, + grubdir, platform); + + char *envfile = grub_util_path_concat (2, grubdir, "grubenv"); + if (!grub_util_is_regular (envfile)) + grub_util_create_envblk_file (envfile); + + size_t ndev = 0; + + /* Write device to a variable so we don't have to traverse /dev every time. */ + grub_devices = grub_guess_root_devices (grubdir); + if (!grub_devices || !grub_devices[0]) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), + grubdir); + + for (curdev = grub_devices; *curdev; curdev++) + { + grub_util_pull_device (*curdev); + ndev++; + } + + grub_drives = xmalloc (sizeof (grub_drives[0]) * (ndev + 1)); + + for (curdev = grub_devices, curdrive = grub_drives; *curdev; curdev++, + curdrive++) + { + *curdrive = grub_util_get_grub_dev (*curdev); + if (! *curdrive) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + *curdev); + } + *curdrive = 0; + + grub_dev = grub_device_open (grub_drives[0]); + if (! grub_dev) + grub_util_error ("%s", grub_errmsg); + + grub_fs = grub_fs_probe (grub_dev); + if (! grub_fs) + grub_util_error ("%s", grub_errmsg); + + grub_install_push_module (grub_fs->name); + + if (grub_dev->disk) + probe_mods (grub_dev->disk); + + for (curdrive = grub_drives + 1; *curdrive; curdrive++) + { + grub_device_t dev = grub_device_open (*curdrive); + if (!dev) + continue; + if (dev->disk) + probe_mods (dev->disk); + grub_device_close (dev); + } + + if (!config.is_cryptodisk_enabled && have_cryptodisk) + grub_util_error (_("attempt to install to encrypted disk without cryptodisk enabled. " + "Set `%s' in file `%s'"), "GRUB_ENABLE_CRYPTODISK=y", + grub_util_get_config_filename ()); + + if (disk_module && grub_strcmp (disk_module, "ata") == 0) + grub_install_push_module ("pata"); + else if (disk_module && grub_strcmp (disk_module, "native") == 0) + { + grub_install_push_module ("pata"); + grub_install_push_module ("ahci"); + grub_install_push_module ("ohci"); + grub_install_push_module ("uhci"); + grub_install_push_module ("ehci"); + grub_install_push_module ("usbms"); + } + else if (disk_module && disk_module[0]) + grub_install_push_module (disk_module); + + relative_grubdir = grub_make_system_path_relative_to_its_root (grubdir); + if (relative_grubdir[0] == '\0') + { + free (relative_grubdir); + relative_grubdir = xstrdup ("/"); + } + + char *platname = grub_install_get_platform_name (platform); + char *platdir; + { + char *t = grub_util_path_concat (2, grubdir, + platname); + platdir = grub_canonicalize_file_name (t); + if (!platdir) + grub_util_error (_("failed to get canonical path of `%s'"), + t); + free (t); + } + load_cfg = grub_util_path_concat (2, platdir, + "load.cfg"); + + grub_util_unlink (load_cfg); + + if (debug_image && debug_image[0]) + { + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + have_load_cfg = 1; + fprintf (load_cfg_f, "set debug='%s'\n", + debug_image); + } + char *prefix_drive = NULL; + char *install_drive = NULL; + + if (install_device) + { + if (install_device[0] == '(' + && install_device[grub_strlen (install_device) - 1] == ')') + { + size_t len = grub_strlen (install_device) - 2; + install_drive = xmalloc (len + 1); + memcpy (install_drive, install_device + 1, len); + install_drive[len] = '\0'; + } + else + { + grub_util_pull_device (install_device); + install_drive = grub_util_get_grub_dev (install_device); + if (!install_drive) + grub_util_error (_("cannot find a GRUB drive for %s. Check your device.map"), + install_device); + } + } + + if (!have_abstractions) + { + if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0) + || grub_drives[1] + || (!install_drive + && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275) + || (install_drive && !is_same_disk (grub_drives[0], install_drive)) + || !have_bootdev (platform)) + { + char *uuid = NULL; + /* generic method (used on coreboot and ata mod). */ + if (!force_file_id + && grub_fs->fs_uuid && grub_fs->fs_uuid (grub_dev, &uuid)) + { + grub_print_error (); + grub_errno = 0; + uuid = NULL; + } + + if (!load_cfg_f) + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + have_load_cfg = 1; + if (uuid) + { + fprintf (load_cfg_f, "search.fs_uuid %s root ", + uuid); + grub_install_push_module ("search_fs_uuid"); + } + else + { + char *rndstr = get_rndstr (); + char *fl = grub_util_path_concat (3, grubdir, + "uuid", rndstr); + char *fldir = grub_util_path_concat (2, grubdir, + "uuid"); + char *relfl; + FILE *flf; + grub_install_mkdir_p (fldir); + flf = grub_util_fopen (fl, "w"); + if (!flf) + grub_util_error (_("Can't create file: %s"), strerror (errno)); + fclose (flf); + relfl = grub_make_system_path_relative_to_its_root (fl); + fprintf (load_cfg_f, "search.file %s root ", + relfl); + grub_install_push_module ("search_fs_file"); + } + for (curdev = grub_devices, curdrive = grub_drives; *curdev; curdev++, + curdrive++) + { + const char *map; + char *g = NULL; + grub_device_t dev; + if (curdrive == grub_drives) + dev = grub_dev; + else + dev = grub_device_open (*curdrive); + if (!dev) + continue; + + if (dev->disk->dev->id != GRUB_DISK_DEVICE_HOSTDISK_ID) + { + grub_util_fprint_full_disk_name (load_cfg_f, + dev->disk->name, + dev); + fprintf (load_cfg_f, " "); + if (dev != grub_dev) + grub_device_close (dev); + continue; + } + + map = grub_util_biosdisk_get_compatibility_hint (dev->disk); + + if (map) + { + grub_util_fprint_full_disk_name (load_cfg_f, map, dev); + fprintf (load_cfg_f, " "); + } + + + if (disk_module && disk_module[0] + && grub_strcmp (disk_module, "biosdisk") != 0) + g = grub_util_guess_baremetal_drive (*curdev); + else + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + g = grub_util_guess_bios_drive (*curdev); + break; + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + g = grub_util_guess_efi_drive (*curdev); + break; + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + { + const char * ofpath = grub_util_devname_to_ofpath (*curdev); + g = xasprintf ("ieee1275/%s", ofpath); + break; + } + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + g = grub_util_guess_baremetal_drive (*curdev); + break; + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + grub_util_warn ("%s", _("no hints available for your platform. Expect reduced performance")); + break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + if (g) + { + grub_util_fprint_full_disk_name (load_cfg_f, g, dev); + fprintf (load_cfg_f, " "); + free (g); + } + if (dev != grub_dev) + grub_device_close (dev); + } + fprintf (load_cfg_f, "\n"); + char *escaped_relpath = escape (relative_grubdir); + fprintf (load_cfg_f, "set prefix=($root)'%s'\n", + escaped_relpath); + } + else + { + /* We need to hardcode the partition number in the core image's prefix. */ + char *p; + for (p = grub_drives[0]; *p; ) + { + if (*p == '\\' && p[1]) + { + p += 2; + continue; + } + if (*p == ',' || *p == '\0') + break; + p++; + } + prefix_drive = xasprintf ("(%s)", p); + } + } + else + { + if (config.is_cryptodisk_enabled) + { + if (grub_dev->disk) + probe_cryptodisk_uuid (grub_dev->disk); + + for (curdrive = grub_drives + 1; *curdrive; curdrive++) + { + grub_device_t dev = grub_device_open (*curdrive); + if (!dev) + continue; + if (dev->disk) + probe_cryptodisk_uuid (dev->disk); + grub_device_close (dev); + } + } + prefix_drive = xasprintf ("(%s)", grub_drives[0]); + } + + char mkimage_target[200]; + const char *core_name = NULL; + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + core_name = "core.efi"; + snprintf (mkimage_target, sizeof (mkimage_target), + "%s-%s", + grub_install_get_platform_cpu (platform), + grub_install_get_platform_platform (platform)); + break; + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + core_name = "core.elf"; + snprintf (mkimage_target, sizeof (mkimage_target), + "%s-%s-elf", + grub_install_get_platform_cpu (platform), + grub_install_get_platform_platform (platform)); + break; + + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + core_name = "core.elf"; + snprintf (mkimage_target, sizeof (mkimage_target), + "%s-%s", + grub_install_get_platform_cpu (platform), + grub_install_get_platform_platform (platform)); + break; + + + case GRUB_INSTALL_PLATFORM_I386_PC: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + snprintf (mkimage_target, sizeof (mkimage_target), + "%s-%s", + grub_install_get_platform_cpu (platform), + grub_install_get_platform_platform (platform)); + core_name = "core.img"; + break; + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + strcpy (mkimage_target, "sparc64-ieee1275-raw"); + core_name = "core.img"; + break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + if (!core_name) + grub_util_error ("%s", _("You've found a bug")); + + if (load_cfg_f) + fclose (load_cfg_f); + + char *imgfile = grub_util_path_concat (2, platdir, + core_name); + char *prefix = xasprintf ("%s%s", prefix_drive ? : "", + relative_grubdir); + grub_install_make_image_wrap (/* source dir */ grub_install_source_directory, + /*prefix */ prefix, + /* output */ imgfile, + /* memdisk */ NULL, + have_load_cfg ? load_cfg : NULL, + /* image target */ mkimage_target, 0); + /* Backward-compatibility kludges. */ + switch (platform) + { + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + { + char *dst = grub_util_path_concat (2, bootdir, "grub.elf"); + grub_install_copy_file (imgfile, dst, 1); + free (dst); + } + break; + + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + { + char *dst = grub_util_path_concat (2, grubdir, "grub"); + grub_install_copy_file (imgfile, dst, 1); + free (dst); + } + break; + + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + { + char *dst = grub_util_path_concat (2, platdir, "grub.efi"); + grub_install_make_image_wrap (/* source dir */ grub_install_source_directory, + /* prefix */ "", + /* output */ dst, + /* memdisk */ NULL, + have_load_cfg ? load_cfg : NULL, + /* image target */ mkimage_target, 0); + } + break; + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_I386_PC: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + /* Perform the platform-dependent install */ + + switch (platform) + { + case GRUB_INSTALL_PLATFORM_I386_PC: + { + char *boot_img_src = grub_util_path_concat (2, + grub_install_source_directory, + "boot.img"); + char *boot_img = grub_util_path_concat (2, platdir, + "boot.img"); + grub_install_copy_file (boot_img_src, boot_img, 1); + + grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory='%s' --device-map='%s' '%s'", + /* TRANSLATORS: This is a prefix in the log to indicate that usually + a command would be executed but due to an option was skipped. */ + install_bootsector ? "" : _("NOT RUNNING: "), + allow_floppy ? "--allow-floppy " : "", + verbosity ? "--verbose " : "", + force ? "--force " : "", + !fs_probe ? "--skip-fs-probe" : "", + !add_rs_codes ? "--no-rs-codes" : "", + platdir, + device_map, + install_device); + + /* Now perform the installation. */ + if (install_bootsector) + grub_util_bios_setup (platdir, "boot.img", "core.img", + install_drive, force, + fs_probe, allow_floppy, add_rs_codes); + break; + } + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + { + char *boot_img_src = grub_util_path_concat (2, + grub_install_source_directory, + "boot.img"); + char *boot_img = grub_util_path_concat (2, platdir, + "boot.img"); + grub_install_copy_file (boot_img_src, boot_img, 1); + + grub_util_info ("%sgrub-sparc64-setup %s %s %s %s --directory='%s' --device-map='%s' '%s'", + install_bootsector ? "" : "NOT RUNNING: ", + allow_floppy ? "--allow-floppy " : "", + verbosity ? "--verbose " : "", + force ? "--force " : "", + !fs_probe ? "--skip-fs-probe" : "", + platdir, + device_map, + install_drive); + + /* Now perform the installation. */ + if (install_bootsector) + grub_util_sparc_setup (platdir, "boot.img", "core.img", + install_drive, force, + fs_probe, allow_floppy, + 0 /* unused */ ); + break; + } + + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: + if (macppcdir) + { + char *core_services = grub_util_path_concat (4, macppcdir, + "System", "Library", + "CoreServices"); + char *mach_kernel = grub_util_path_concat (2, macppcdir, + "mach_kernel"); + char *grub_elf, *bootx; + FILE *f; + grub_device_t ins_dev; + char *grub_chrp = grub_util_path_concat (2, + grub_install_source_directory, + "grub.chrp"); + + grub_install_mkdir_p (core_services); + + bootx = grub_util_path_concat (2, core_services, "BootX"); + grub_install_copy_file (grub_chrp, bootx, 1); + + grub_elf = grub_util_path_concat (2, core_services, "grub.elf"); + grub_install_copy_file (imgfile, grub_elf, 1); + + f = grub_util_fopen (mach_kernel, "a+"); + if (!f) + grub_util_error (_("Can't create file: %s"), strerror (errno)); + fclose (f); + + fill_core_services (core_services); + + ins_dev = grub_device_open (install_drive); + + bless (ins_dev, core_services, 0); + + if (update_nvram) + { + const char *dev; + int partno; + + partno = ins_dev->disk->partition + ? ins_dev->disk->partition->number + 1 : 0; + dev = grub_util_get_os_disk (install_device); + grub_install_register_ieee1275 (0, dev, partno, + "\\\\BootX"); + } + grub_device_close (ins_dev); + free (grub_elf); + free (bootx); + free (mach_kernel); + free (grub_chrp); + break; + } + /* If a install device is defined, copy the core.elf to PReP partition. */ + if (is_prep && install_device && install_device[0]) + { + grub_device_t ins_dev; + ins_dev = grub_device_open (install_drive); + if (!ins_dev || !is_prep_partition (ins_dev)) + { + grub_util_error ("%s", _("the chosen partition is not a PReP partition")); + } + if (is_prep_empty (ins_dev)) + { + if (write_to_disk (ins_dev, imgfile)) + grub_util_error ("%s", _("failed to copy Grub to the PReP partition")); + } + else + { + char *s = xasprintf ("dd if=/dev/zero of=%s", install_device); + grub_util_error (_("the PReP partition is not empty. If you are sure you want to use it, run dd to clear it: `%s'"), + s); + } + grub_device_close (ins_dev); + if (update_nvram) + grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_device), + 0, NULL); + break; + } + /* fallthrough. */ + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + if (update_nvram) + { + const char *dev; + char *relpath; + int partno; + relpath = grub_make_system_path_relative_to_its_root (imgfile); + partno = grub_dev->disk->partition + ? grub_dev->disk->partition->number + 1 : 0; + dev = grub_util_get_os_disk (grub_devices[0]); + grub_install_register_ieee1275 (0, dev, + partno, relpath); + } + break; + case GRUB_INSTALL_PLATFORM_MIPS_ARC: + grub_install_sgi_setup (install_device, imgfile, "grub"); + break; + + case GRUB_INSTALL_PLATFORM_I386_EFI: + if (!efidir_is_mac) + { + char *dst = grub_util_path_concat (2, efidir, "grub.efi"); + /* For old macs. Suggested by Peter Jones. */ + grub_install_copy_file (imgfile, dst, 1); + free (dst); + } + /* Fallthrough. */ + case GRUB_INSTALL_PLATFORM_X86_64_EFI: + if (efidir_is_mac) + { + char *boot_efi; + char *core_services = grub_util_path_concat (4, efidir, + "System", "Library", + "CoreServices"); + char *mach_kernel = grub_util_path_concat (2, efidir, + "mach_kernel"); + FILE *f; + grub_device_t ins_dev; + + grub_install_mkdir_p (core_services); + + boot_efi = grub_util_path_concat (2, core_services, "boot.efi"); + grub_install_copy_file (imgfile, boot_efi, 1); + + f = grub_util_fopen (mach_kernel, "r+"); + if (!f) + grub_util_error (_("Can't create file: %s"), strerror (errno)); + fclose (f); + + fill_core_services(core_services); + + ins_dev = grub_device_open (install_drive); + + bless (ins_dev, boot_efi, 1); + if (!removable && update_nvram) + { + /* Try to make this image bootable using the EFI Boot Manager, if available. */ + int ret; + ret = grub_install_register_efi (efidir_grub_dev, + "\\System\\Library\\CoreServices", + efi_distributor); + if (ret) + grub_util_error (_("efibootmgr failed to register the boot entry: %s"), + strerror (ret)); + } + + grub_device_close (ins_dev); + free (boot_efi); + free (mach_kernel); + break; + } + /* FALLTHROUGH */ + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI: + case GRUB_INSTALL_PLATFORM_RISCV32_EFI: + case GRUB_INSTALL_PLATFORM_RISCV64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + { + char *dst = grub_util_path_concat (2, efidir, efi_file); + grub_install_copy_file (imgfile, dst, 1); + free (dst); + } + if (!removable && update_nvram) + { + char * efifile_path; + char * part; + int ret; + + /* Try to make this image bootable using the EFI Boot Manager, if available. */ + if (!efi_distributor || efi_distributor[0] == '\0') + grub_util_error ("%s", _("EFI bootloader id isn't specified.")); + efifile_path = xasprintf ("\\EFI\\%s\\%s", + efi_distributor, + efi_file); + part = (efidir_grub_dev->disk->partition + ? grub_partition_get_name (efidir_grub_dev->disk->partition) + : 0); + grub_util_info ("Registering with EFI: distributor = `%s'," + " path = `%s', ESP at %s%s%s", + efi_distributor, efifile_path, + efidir_grub_dev->disk->name, + (part ? ",": ""), (part ? : "")); + grub_free (part); + ret = grub_install_register_efi (efidir_grub_dev, + efifile_path, efi_distributor); + if (ret) + grub_util_error (_("efibootmgr failed to register the boot entry: %s"), + strerror (ret)); + } + break; + + case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: + case GRUB_INSTALL_PLATFORM_ARM_COREBOOT: + case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT: + case GRUB_INSTALL_PLATFORM_MIPSEL_ARC: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: + case GRUB_INSTALL_PLATFORM_I386_XEN: + case GRUB_INSTALL_PLATFORM_X86_64_XEN: + case GRUB_INSTALL_PLATFORM_I386_XEN_PVH: + grub_util_warn ("%s", + _("WARNING: no platform-specific install was performed")); + break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; + } + + fprintf (stderr, "%s\n", _("Installation finished. No error reported.")); + + /* Free resources. */ + grub_gcry_fini_all (); + grub_fini_all (); + + return 0; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mkconfig_lib.in b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mkconfig_lib.in new file mode 100644 index 0000000..394cd8e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mkconfig_lib.in @@ -0,0 +1,373 @@ +# Helper library for grub-mkconfig +# Copyright (C) 2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +datadir="@datadir@" +bindir="@bindir@" +sbindir="@sbindir@" +if [ "x$pkgdatadir" = x ]; then + pkgdatadir="${datadir}/@PACKAGE@" +fi + +if test "x$grub_probe" = x; then + grub_probe="${sbindir}/@grub_probe@" +fi +if test "x$grub_file" = x; then + grub_file="${bindir}/@grub_file@" +fi +if test "x$grub_mkrelpath" = x; then + grub_mkrelpath="${bindir}/@grub_mkrelpath@" +fi + +if which gettext >/dev/null 2>/dev/null; then + : +else + gettext () { + printf "%s" "$@" + } +fi + +grub_warn () +{ + echo "$(gettext "Warning:")" "$@" >&2 +} + +make_system_path_relative_to_its_root () +{ + "${grub_mkrelpath}" "$1" +} + +is_path_readable_by_grub () +{ + path="$1" + + # abort if path doesn't exist + if test -e "$path" ; then : ;else + return 1 + fi + + # abort if file is in a filesystem we can't read + if "${grub_probe}" -t fs "$path" > /dev/null 2>&1 ; then : ; else + return 1 + fi + + # ... or if we can't figure out the abstraction module, for example if + # memberlist fails on an LVM volume group. + if abstractions="`"${grub_probe}" -t abstraction "$path"`" 2> /dev/null ; then + : + else + return 1 + fi + + if [ x$GRUB_ENABLE_CRYPTODISK = xy ]; then + return 0 + fi + + for abstraction in $abstractions; do + if [ "x$abstraction" = xcryptodisk ]; then + return 1 + fi + done + + return 0 +} + +convert_system_path_to_grub_path () +{ + path="$1" + + grub_warn "convert_system_path_to_grub_path() is deprecated. Use prepare_grub_to_access_device() instead." + + # abort if GRUB can't access the path + if is_path_readable_by_grub "${path}" ; then : ; else + return 1 + fi + + if drive="`"${grub_probe}" -t drive "$path"`" ; then : ; else + return 1 + fi + + if relative_path="`make_system_path_relative_to_its_root "$path"`" ; then : ; else + return 1 + fi + + echo "${drive}${relative_path}" +} + +save_default_entry () +{ + if [ "x${GRUB_SAVEDEFAULT}" = "xtrue" ] ; then + cat << EOF +savedefault +EOF + fi +} + +prepare_grub_to_access_device () +{ + old_ifs="$IFS" + IFS=' +' +:<<\EOF + partmap="`"${grub_probe}" --device $@ --target=partmap`" + for module in ${partmap} ; do + case "${module}" in + netbsd | openbsd) + echo "insmod part_bsd";; + *) + echo "insmod part_${module}";; + esac + done +EOF + + # Abstraction modules aren't auto-loaded. + abstraction="`"${grub_probe}" --device $@ --target=abstraction`" + for module in ${abstraction} ; do + echo "insmod ${module}" + done + +# fs="`"${grub_probe}" --device $@ --target=fs`" +# for module in ${fs} ; do +# echo "insmod ${module}" +# done + + if [ x$GRUB_ENABLE_CRYPTODISK = xy ]; then + for uuid in `"${grub_probe}" --device $@ --target=cryptodisk_uuid`; do + echo "cryptomount -u $uuid" + done + fi + + # If there's a filesystem UUID that GRUB is capable of identifying, use it; + # otherwise set root as per value in device.map. + fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`" + if [ "x$fs_hint" != x ]; then + echo "set root='$fs_hint'" + fi + if fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then + hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints= + echo "if [ x\$feature_platform_search_hint = xy ]; then" + echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}" + echo "else" + echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}" + echo "fi" + fi + IFS="$old_ifs" +} + +grub_get_device_id () +{ + old_ifs="$IFS" + IFS=' +' + device="$1" + if fs_uuid="`"${grub_probe}" --device ${device} --target=fs_uuid 2> /dev/null`" ; then + echo "$fs_uuid"; + else + echo $device |sed 's, ,_,g' + fi + IFS="$old_ifs" +} + +grub_file_is_not_garbage () +{ + if test -f "$1" ; then + case "$1" in + *.dpkg-*) return 1 ;; # debian dpkg + *.rpmsave|*.rpmnew) return 1 ;; + README*|*/README*) return 1 ;; # documentation + *.sig) return 1 ;; # signatures + esac + else + return 1 + fi + return 0 +} + +version_sort () +{ + case $version_sort_sort_has_v in + yes) + LC_ALL=C sort -V;; + no) + LC_ALL=C sort -n;; + *) + if sort -V /dev/null 2>&1; then + version_sort_sort_has_v=yes + LC_ALL=C sort -V + else + version_sort_sort_has_v=no + LC_ALL=C sort -n + fi;; + esac +} + +version_test_numeric () +{ + version_test_numeric_a="$1" + version_test_numeric_cmp="$2" + version_test_numeric_b="$3" + if [ "$version_test_numeric_a" = "$version_test_numeric_b" ] ; then + case "$version_test_numeric_cmp" in + ge|eq|le) return 0 ;; + gt|lt) return 1 ;; + esac + fi + if [ "$version_test_numeric_cmp" = "lt" ] ; then + version_test_numeric_c="$version_test_numeric_a" + version_test_numeric_a="$version_test_numeric_b" + version_test_numeric_b="$version_test_numeric_c" + fi + if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | version_sort | head -n 1 | grep -qx "$version_test_numeric_b" ; then + return 0 + else + return 1 + fi +} + +version_test_gt () +{ + version_test_gt_a="`echo "$1" | sed -e "s/[^-]*-//"`" + version_test_gt_b="`echo "$2" | sed -e "s/[^-]*-//"`" + version_test_gt_cmp=gt + if [ "x$version_test_gt_b" = "x" ] ; then + return 0 + fi + case "$version_test_gt_a:$version_test_gt_b" in + *.old:*.old) ;; + *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;; + *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;; + esac + version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b" + return "$?" +} + +version_find_latest () +{ + version_find_latest_a="" + for i in "$@" ; do + if version_test_gt "$i" "$version_find_latest_a" ; then + version_find_latest_a="$i" + fi + done + echo "$version_find_latest_a" +} + +# One layer of quotation is eaten by "" and the second by sed; so this turns +# ' into \'. +grub_quote () { + sed "s/'/'\\\\''/g" +} + +gettext_quoted () { + gettext "$@" | grub_quote +} + +# Run the first argument through gettext, and then pass that and all +# remaining arguments to printf. This is a useful abbreviation and tends to +# be easier to type. +gettext_printf () { + gettext_printf_format="$1" + shift + printf "$(gettext "$gettext_printf_format")" "$@" +} + +uses_abstraction () { + device="$1" + old_ifs="$IFS" + IFS=' +' + + abstraction="`"${grub_probe}" --device ${device} --target=abstraction`" + for module in ${abstraction}; do + if test "x${module}" = "x$2"; then + IFS="$old_ifs" + return 0 + fi + done + IFS="$old_ifs" + return 1 +} + +print_option_help () { + if test x$print_option_help_wc = x; then + if wc -L /dev/null 2>&1; then + print_option_help_wc=-L + elif wc -m /dev/null 2>&1; then + print_option_help_wc=-m + else + print_option_help_wc=-b + fi + fi + if test x$grub_have_fmt = x; then + if fmt -w 40 /dev/null 2>&1; then + grub_have_fmt=y; + else + grub_have_fmt=n; + fi + fi + print_option_help_lead=" $1" + print_option_help_lspace="$(echo "$print_option_help_lead" | wc $print_option_help_wc)" + print_option_help_fill="$((26 - print_option_help_lspace))" + printf "%s" "$print_option_help_lead" + if test $print_option_help_fill -le 0; then + print_option_help_nl=y + echo + else + print_option_help_i=0; + while test $print_option_help_i -lt $print_option_help_fill; do + printf " " + print_option_help_i=$((print_option_help_i+1)) + done + print_option_help_nl=n + fi + if test x$grub_have_fmt = xy; then + print_option_help_split="$(echo "$2" | fmt -w 50)" + else + print_option_help_split="$2" + fi + if test x$print_option_help_nl = xy; then + echo "$print_option_help_split" | awk \ + '{ print " " $0; }' + else + echo "$print_option_help_split" | awk 'BEGIN { n = 0 } + { if (n == 1) print " " $0; else print $0; n = 1 ; }' + fi +} + +grub_fmt () { + if test x$grub_have_fmt = x; then + if fmt -w 40 < /dev/null > /dev/null; then + grub_have_fmt=y; + else + grub_have_fmt=n; + fi + fi + + if test x$grub_have_fmt = xy; then + fmt + else + cat + fi +} + +grub_tab=" " + +grub_add_tab () { + sed -e "s/^/$grub_tab/" +} + diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mkimagexx.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mkimagexx.c new file mode 100644 index 0000000..a63ddbb --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mkimagexx.c @@ -0,0 +1,2689 @@ +/* grub-mkimage.c - make a bootable image */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#pragma GCC diagnostic ignored "-Wcast-align" + +#define GRUB_MKIMAGEXX +#if !defined(MKIMAGE_ELF32) && !defined(MKIMAGE_ELF64) +#if __SIZEOF_POINTER__ == 8 +#include "grub-mkimage64.c" +#else +#include "grub-mkimage32.c" +#endif +#endif + +/* These structures are defined according to the CHRP binding to IEEE1275, + "Client Program Format" section. */ + +struct grub_ieee1275_note_desc +{ + grub_uint32_t real_mode; + grub_uint32_t real_base; + grub_uint32_t real_size; + grub_uint32_t virt_base; + grub_uint32_t virt_size; + grub_uint32_t load_base; +}; + +#define GRUB_IEEE1275_NOTE_NAME "PowerPC" +#define GRUB_IEEE1275_NOTE_TYPE 0x1275 + +struct grub_ieee1275_note +{ + Elf32_Nhdr header; + char name[ALIGN_UP(sizeof (GRUB_IEEE1275_NOTE_NAME), 4)]; + struct grub_ieee1275_note_desc descriptor; +}; + +#define GRUB_XEN_NOTE_NAME "Xen" + +struct fixup_block_list +{ + struct fixup_block_list *next; + int state; + struct grub_pe32_fixup_block b; +}; + +#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) + +struct section_metadata +{ + Elf_Half num_sections; + Elf_Shdr *sections; + Elf_Addr *addrs; + Elf_Addr *vaddrs; + Elf_Half section_entsize; + Elf_Shdr *symtab; + const char *strtab; +}; + +static int +is_relocatable (const struct grub_install_image_target_desc *image_target) +{ + return image_target->id == IMAGE_EFI || image_target->id == IMAGE_UBOOT + || (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM); +} + +#ifdef MKIMAGE_ELF32 + +/* + * R_ARM_THM_CALL/THM_JUMP24 + * + * Relocate Thumb (T32) instruction set relative branches: + * B.W, BL and BLX + */ +static grub_err_t +grub_arm_reloc_thm_call (grub_uint16_t *target, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + + offset = grub_arm_thm_call_get_offset (target); + + grub_dprintf ("dl", " sym_addr = 0x%08x", sym_addr); + + offset += sym_addr; + + grub_dprintf("dl", " BL*: target=%p, sym_addr=0x%08x, offset=%d\n", + target, sym_addr, offset); + + /* Keep traditional (pre-Thumb2) limits on blx. In any case if the kernel + is bigger than 2M (currently under 150K) then we probably have a problem + somewhere else. */ + if (offset < -0x200000 || offset >= 0x200000) + return grub_error (GRUB_ERR_BAD_MODULE, + "THM_CALL Relocation out of range."); + + grub_dprintf ("dl", " relative destination = %p", + (char *) target + offset); + + return grub_arm_thm_call_set_offset (target, offset); +} + +/* + * R_ARM_THM_JUMP19 + * + * Relocate conditional Thumb (T32) B.W + */ +static grub_err_t +grub_arm_reloc_thm_jump19 (grub_uint16_t *target, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + + if (!(sym_addr & 1)) + return grub_error (GRUB_ERR_BAD_MODULE, + "Relocation targeting wrong execution state"); + + offset = grub_arm_thm_jump19_get_offset (target); + + /* Adjust and re-truncate offset */ + offset += sym_addr; + + if (!grub_arm_thm_jump19_check_offset (offset)) + return grub_error (GRUB_ERR_BAD_MODULE, + "THM_JUMP19 Relocation out of range."); + + grub_arm_thm_jump19_set_offset (target, offset); + + return GRUB_ERR_NONE; +} + +/* + * R_ARM_JUMP24 + * + * Relocate ARM (A32) B + */ +static grub_err_t +grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) +{ + grub_int32_t offset; + + if (sym_addr & 1) + return grub_error (GRUB_ERR_BAD_MODULE, + "Relocation targeting wrong execution state"); + + offset = grub_arm_jump24_get_offset (target); + offset += sym_addr; + + if (!grub_arm_jump24_check_offset (offset)) + return grub_error (GRUB_ERR_BAD_MODULE, + "JUMP24 Relocation out of range."); + + + grub_arm_jump24_set_offset (target, offset); + + return GRUB_ERR_NONE; +} + +#endif + +void +SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, + int note, char **core_img, size_t *core_size, + Elf_Addr target_addr, + struct grub_mkimage_layout *layout) +{ + char *elf_img; + size_t program_size; + Elf_Ehdr *ehdr; + Elf_Phdr *phdr; + Elf_Shdr *shdr; + int header_size, footer_size = 0; + int phnum = 1; + int shnum = 4; + int string_size = sizeof (".text") + sizeof ("mods") + 1; + + if (image_target->id != IMAGE_LOONGSON_ELF) + phnum += 2; + + if (note) + { + phnum++; + footer_size += sizeof (struct grub_ieee1275_note); + } + if (image_target->id == IMAGE_XEN || image_target->id == IMAGE_XEN_PVH) + { + phnum++; + shnum++; + string_size += sizeof (".xen"); + footer_size += (image_target->id == IMAGE_XEN) ? XEN_NOTE_SIZE : XEN_PVH_NOTE_SIZE; + } + header_size = ALIGN_UP (sizeof (*ehdr) + phnum * sizeof (*phdr) + + shnum * sizeof (*shdr) + string_size, layout->align); + + program_size = ALIGN_ADDR (*core_size); + + elf_img = xmalloc (program_size + header_size + footer_size); + memset (elf_img, 0, program_size + header_size + footer_size); + memcpy (elf_img + header_size, *core_img, *core_size); + ehdr = (void *) elf_img; + phdr = (void *) (elf_img + sizeof (*ehdr)); + shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)); + memcpy (ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELFCLASSXX; + if (!image_target->bigendian) + ehdr->e_ident[EI_DATA] = ELFDATA2LSB; + else + ehdr->e_ident[EI_DATA] = ELFDATA2MSB; + ehdr->e_ident[EI_VERSION] = EV_CURRENT; + ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE; + ehdr->e_type = grub_host_to_target16 (ET_EXEC); + ehdr->e_machine = grub_host_to_target16 (image_target->elf_target); + ehdr->e_version = grub_host_to_target32 (EV_CURRENT); + + ehdr->e_phoff = grub_host_to_target32 ((char *) phdr - (char *) ehdr); + ehdr->e_phentsize = grub_host_to_target16 (sizeof (*phdr)); + ehdr->e_phnum = grub_host_to_target16 (phnum); + + ehdr->e_shoff = grub_host_to_target32 ((grub_uint8_t *) shdr + - (grub_uint8_t *) ehdr); + if (image_target->id == IMAGE_LOONGSON_ELF) + ehdr->e_shentsize = grub_host_to_target16 (0); + else + ehdr->e_shentsize = grub_host_to_target16 (sizeof (Elf_Shdr)); + ehdr->e_shnum = grub_host_to_target16 (shnum); + ehdr->e_shstrndx = grub_host_to_target16 (1); + + ehdr->e_ehsize = grub_host_to_target16 (sizeof (*ehdr)); + + phdr->p_type = grub_host_to_target32 (PT_LOAD); + phdr->p_offset = grub_host_to_target32 (header_size); + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + + ehdr->e_entry = grub_host_to_target32 (target_addr); + phdr->p_vaddr = grub_host_to_target32 (target_addr); + phdr->p_paddr = grub_host_to_target32 (target_addr); + phdr->p_align = grub_host_to_target32 (layout->align > image_target->link_align ? + layout->align : image_target->link_align); + if (image_target->id == IMAGE_LOONGSON_ELF) + ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER + | EF_MIPS_PIC | EF_MIPS_CPIC); + else + ehdr->e_flags = 0; + if (image_target->id == IMAGE_LOONGSON_ELF) + { + phdr->p_filesz = grub_host_to_target32 (*core_size); + phdr->p_memsz = grub_host_to_target32 (*core_size); + } + else + { + grub_uint32_t target_addr_mods; + phdr->p_filesz = grub_host_to_target32 (layout->kernel_size); + if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM) + phdr->p_memsz = grub_host_to_target32 (layout->kernel_size); + else + phdr->p_memsz = grub_host_to_target32 (layout->kernel_size + layout->bss_size); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_GNU_STACK); + phdr->p_offset = grub_host_to_target32 (header_size + layout->kernel_size); + phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0; + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + phdr->p_align = grub_host_to_target32 (image_target->link_align); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_LOAD); + phdr->p_offset = grub_host_to_target32 (header_size + layout->kernel_size); + phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X); + phdr->p_filesz = phdr->p_memsz + = grub_host_to_target32 (*core_size - layout->kernel_size); + + if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_386) + target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR; + else if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM) + target_addr_mods = ALIGN_UP (target_addr + layout->end + + image_target->mod_gap, + image_target->mod_align); + else + target_addr_mods = ALIGN_UP (target_addr + layout->kernel_size + layout->bss_size + + image_target->mod_gap, + image_target->mod_align); + phdr->p_vaddr = grub_host_to_target_addr (target_addr_mods); + phdr->p_paddr = grub_host_to_target_addr (target_addr_mods); + phdr->p_align = grub_host_to_target32 (image_target->link_align); + } + + if (image_target->id == IMAGE_XEN) + { + char *note_start = (elf_img + program_size + header_size); + Elf_Nhdr *note_ptr; + char *ptr = (char *) note_start; + + grub_util_info ("adding XEN NOTE segment"); + + /* Guest OS. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (sizeof (PACKAGE_NAME)); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_GUEST_OS); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memcpy (ptr, PACKAGE_NAME, sizeof (PACKAGE_NAME)); + ptr += ALIGN_UP (sizeof (PACKAGE_NAME), 4); + + /* Loader. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (sizeof ("generic")); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_LOADER); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memcpy (ptr, "generic", sizeof ("generic")); + ptr += ALIGN_UP (sizeof ("generic"), 4); + + /* Version. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (sizeof ("xen-3.0")); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_XEN_VERSION); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memcpy (ptr, "xen-3.0", sizeof ("xen-3.0")); + ptr += ALIGN_UP (sizeof ("xen-3.0"), 4); + + /* Entry. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_ENTRY); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memset (ptr, 0, image_target->voidp_sizeof); + ptr += image_target->voidp_sizeof; + + /* Virt base. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_VIRT_BASE); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memset (ptr, 0, image_target->voidp_sizeof); + ptr += image_target->voidp_sizeof; + + /* PAE. */ + if (image_target->elf_target == EM_386) + { + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (sizeof ("yes,bimodal")); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_PAE_MODE); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memcpy (ptr, "yes", sizeof ("yes")); + ptr += ALIGN_UP (sizeof ("yes"), 4); + } + + assert (XEN_NOTE_SIZE == (ptr - note_start)); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_NOTE); + phdr->p_flags = grub_host_to_target32 (PF_R); + phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); + phdr->p_vaddr = 0; + phdr->p_paddr = 0; + phdr->p_filesz = grub_host_to_target32 (XEN_NOTE_SIZE); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + + if (image_target->id == IMAGE_XEN_PVH) + { + char *note_start = (elf_img + program_size + header_size); + Elf_Nhdr *note_ptr; + char *ptr = (char *) note_start; + + grub_util_info ("adding XEN NOTE segment"); + + /* Phys32 Entry. */ + note_ptr = (Elf_Nhdr *) ptr; + note_ptr->n_namesz = grub_host_to_target32 (sizeof (GRUB_XEN_NOTE_NAME)); + note_ptr->n_descsz = grub_host_to_target32 (image_target->voidp_sizeof); + note_ptr->n_type = grub_host_to_target32 (XEN_ELFNOTE_PHYS32_ENTRY); + ptr += sizeof (Elf_Nhdr); + memcpy (ptr, GRUB_XEN_NOTE_NAME, sizeof (GRUB_XEN_NOTE_NAME)); + ptr += ALIGN_UP (sizeof (GRUB_XEN_NOTE_NAME), 4); + memset (ptr, 0, image_target->voidp_sizeof); + *(grub_uint32_t *) ptr = GRUB_KERNEL_I386_XEN_PVH_LINK_ADDR; + ptr += image_target->voidp_sizeof; + + assert (XEN_PVH_NOTE_SIZE == (ptr - note_start)); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_NOTE); + phdr->p_flags = grub_host_to_target32 (PF_R); + phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); + phdr->p_vaddr = 0; + phdr->p_paddr = 0; + phdr->p_filesz = grub_host_to_target32 (XEN_PVH_NOTE_SIZE); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + + if (note) + { + int note_size = sizeof (struct grub_ieee1275_note); + struct grub_ieee1275_note *note_ptr = (struct grub_ieee1275_note *) + (elf_img + program_size + header_size); + + grub_util_info ("adding CHRP NOTE segment"); + + note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_IEEE1275_NOTE_NAME)); + note_ptr->header.n_descsz = grub_host_to_target32 (note_size); + note_ptr->header.n_type = grub_host_to_target32 (GRUB_IEEE1275_NOTE_TYPE); + strcpy (note_ptr->name, GRUB_IEEE1275_NOTE_NAME); + note_ptr->descriptor.real_mode = grub_host_to_target32 (0xffffffff); + note_ptr->descriptor.real_base = grub_host_to_target32 (0x00c00000); + note_ptr->descriptor.real_size = grub_host_to_target32 (0xffffffff); + note_ptr->descriptor.virt_base = grub_host_to_target32 (0xffffffff); + note_ptr->descriptor.virt_size = grub_host_to_target32 (0xffffffff); + note_ptr->descriptor.load_base = grub_host_to_target32 (0x00004000); + + phdr++; + phdr->p_type = grub_host_to_target32 (PT_NOTE); + phdr->p_flags = grub_host_to_target32 (PF_R); + phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); + phdr->p_vaddr = 0; + phdr->p_paddr = 0; + phdr->p_filesz = grub_host_to_target32 (note_size); + phdr->p_memsz = 0; + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + + { + char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr) + + shnum * sizeof (*shdr)); + char *ptr = str_start + 1; + + shdr++; + + shdr->sh_name = grub_host_to_target32 (0); + shdr->sh_type = grub_host_to_target32 (SHT_STRTAB); + shdr->sh_addr = grub_host_to_target_addr (0); + shdr->sh_offset = grub_host_to_target_addr (str_start - elf_img); + shdr->sh_size = grub_host_to_target32 (string_size); + shdr->sh_link = grub_host_to_target32 (0); + shdr->sh_info = grub_host_to_target32 (0); + shdr->sh_addralign = grub_host_to_target32 (layout->align); + shdr->sh_entsize = grub_host_to_target32 (0); + shdr++; + + memcpy (ptr, ".text", sizeof (".text")); + + shdr->sh_name = grub_host_to_target32 (ptr - str_start); + ptr += sizeof (".text"); + shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS); + shdr->sh_addr = grub_host_to_target_addr (target_addr); + shdr->sh_offset = grub_host_to_target_addr (header_size); + shdr->sh_size = grub_host_to_target32 (layout->kernel_size); + shdr->sh_link = grub_host_to_target32 (0); + shdr->sh_info = grub_host_to_target32 (0); + shdr->sh_addralign = grub_host_to_target32 (layout->align); + shdr->sh_entsize = grub_host_to_target32 (0); + shdr++; + + memcpy (ptr, "mods", sizeof ("mods")); + shdr->sh_name = grub_host_to_target32 (ptr - str_start); + ptr += sizeof ("mods"); + shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS); + shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size); + shdr->sh_offset = grub_host_to_target_addr (header_size + layout->kernel_size); + shdr->sh_size = grub_host_to_target32 (*core_size - layout->kernel_size); + shdr->sh_link = grub_host_to_target32 (0); + shdr->sh_info = grub_host_to_target32 (0); + shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof); + shdr->sh_entsize = grub_host_to_target32 (0); + shdr++; + + if (image_target->id == IMAGE_XEN || image_target->id == IMAGE_XEN_PVH) + { + memcpy (ptr, ".xen", sizeof (".xen")); + shdr->sh_name = grub_host_to_target32 (ptr - str_start); + ptr += sizeof (".xen"); + shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS); + shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size); + shdr->sh_offset = grub_host_to_target_addr (program_size + header_size); + if (image_target->id == IMAGE_XEN) + shdr->sh_size = grub_host_to_target32 (XEN_NOTE_SIZE); + else + shdr->sh_size = grub_host_to_target32 (XEN_PVH_NOTE_SIZE); + shdr->sh_link = grub_host_to_target32 (0); + shdr->sh_info = grub_host_to_target32 (0); + shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof); + shdr->sh_entsize = grub_host_to_target32 (0); + shdr++; + } + } + + free (*core_img); + *core_img = elf_img; + *core_size = program_size + header_size + footer_size; +} + +/* Relocate symbols; note that this function overwrites the symbol table. + Return the address of a start symbol. */ +static Elf_Addr +SUFFIX (relocate_symbols) (Elf_Ehdr *e, struct section_metadata *smd, + void *jumpers, Elf_Addr jumpers_addr, + Elf_Addr bss_start, Elf_Addr end, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Word symtab_size, sym_size, num_syms; + Elf_Off symtab_offset; + Elf_Addr start_address = (Elf_Addr) -1; + Elf_Sym *sym; + Elf_Word i; + Elf_Shdr *symtab_section; + const char *symtab; + grub_uint64_t *jptr = jumpers; + + symtab_section = (Elf_Shdr *) ((char *) smd->sections + + grub_target_to_host32 (smd->symtab->sh_link) + * smd->section_entsize); + symtab = (char *) e + grub_target_to_host (symtab_section->sh_offset); + + symtab_size = grub_target_to_host (smd->symtab->sh_size); + sym_size = grub_target_to_host (smd->symtab->sh_entsize); + symtab_offset = grub_target_to_host (smd->symtab->sh_offset); + num_syms = symtab_size / sym_size; + + for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset); + i < num_syms; + i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) + { + Elf_Section cur_index; + const char *name; + + name = symtab + grub_target_to_host32 (sym->st_name); + + cur_index = grub_target_to_host16 (sym->st_shndx); + if (cur_index == STN_ABS) + { + continue; + } + else if (cur_index == STN_UNDEF) + { + if (sym->st_name && grub_strcmp (name, "__bss_start") == 0) + sym->st_value = bss_start; + else if (sym->st_name && grub_strcmp (name, "_end") == 0) + sym->st_value = end; + else if (sym->st_name) + grub_util_error ("undefined symbol %s", name); + else + continue; + } + else if (cur_index >= smd->num_sections) + grub_util_error ("section %d does not exist", cur_index); + else + { + sym->st_value = (grub_target_to_host (sym->st_value) + + smd->vaddrs[cur_index]); + } + + if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info) + == STT_FUNC) + { + *jptr = grub_host_to_target64 (sym->st_value); + sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr; + jptr++; + *jptr = 0; + jptr++; + } + grub_util_info ("locating %s at 0x%" GRUB_HOST_PRIxLONG_LONG + " (0x%" GRUB_HOST_PRIxLONG_LONG ")", name, + (unsigned long long) sym->st_value, + (unsigned long long) smd->vaddrs[cur_index]); + + if (start_address == (Elf_Addr)-1) + if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0) + start_address = sym->st_value; + } + + return start_address; +} + +/* Return the address of a symbol at the index I in the section S. */ +static Elf_Addr +SUFFIX (get_symbol_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Sym *sym; + + sym = (Elf_Sym *) ((char *) e + + grub_target_to_host (s->sh_offset) + + i * grub_target_to_host (s->sh_entsize)); + return sym->st_value; +} + +/* Return the address of a modified value. */ +static Elf_Addr * +SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset, + const struct grub_install_image_target_desc *image_target) +{ + return (Elf_Addr *) ((char *) e + grub_target_to_host (s->sh_offset) + offset); +} + +#ifdef MKIMAGE_ELF64 +static Elf_Addr +SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Word symtab_size, sym_size, num_syms; + Elf_Off symtab_offset; + Elf_Sym *sym; + Elf_Word i; + int ret = 0; + + symtab_size = grub_target_to_host (symtab_section->sh_size); + sym_size = grub_target_to_host (symtab_section->sh_entsize); + symtab_offset = grub_target_to_host (symtab_section->sh_offset); + num_syms = symtab_size / sym_size; + + for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset); + i < num_syms; + i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) + if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) + ret++; + + return ret; +} +#endif + +#ifdef MKIMAGE_ELF32 +/* Deal with relocation information. This function relocates addresses + within the virtual address space starting from 0. So only relative + addresses can be fully resolved. Absolute addresses must be relocated + again by a PE32 relocator when loaded. */ +static grub_size_t +arm_get_trampoline_size (Elf_Ehdr *e, + Elf_Shdr *sections, + Elf_Half section_entsize, + Elf_Half num_sections, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Half i; + Elf_Shdr *s; + grub_size_t ret = 0; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((s->sh_type == grub_host_to_target32 (SHT_REL)) || + (s->sh_type == grub_host_to_target32 (SHT_RELA))) + { + Elf_Rela *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Shdr *symtab_section; + Elf_Word j; + + symtab_section = (Elf_Shdr *) ((char *) sections + + (grub_target_to_host32 (s->sh_link) + * section_entsize)); + + rtab_size = grub_target_to_host (s->sh_size); + r_size = grub_target_to_host (s->sh_entsize); + rtab_offset = grub_target_to_host (s->sh_offset); + num_rs = rtab_size / r_size; + + for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); + j < num_rs; + j++, r = (Elf_Rela *) ((char *) r + r_size)) + { + Elf_Addr info; + Elf_Addr sym_addr; + + info = grub_target_to_host (r->r_info); + sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, + ELF_R_SYM (info), image_target); + + sym_addr += (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? + grub_target_to_host (r->r_addend) : 0; + + switch (ELF_R_TYPE (info)) + { + case R_ARM_ABS32: + case R_ARM_V4BX: + break; + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + case R_ARM_THM_JUMP19: + if (!(sym_addr & 1)) + ret += 8; + break; + + case R_ARM_CALL: + case R_ARM_JUMP24: + if (sym_addr & 1) + ret += 16; + break; + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + } + } + return ret; +} +#endif + +static int +SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target); +static int +SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target, + struct section_metadata *smd); + +/* Deal with relocation information. This function relocates addresses + within the virtual address space starting from 0. So only relative + addresses can be fully resolved. Absolute addresses must be relocated + again by a PE32 relocator when loaded. */ +static void +SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, + char *pe_target, Elf_Addr tramp_off, Elf_Addr got_off, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Half i; + Elf_Shdr *s; +#ifdef MKIMAGE_ELF64 + struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off); + grub_uint64_t *gpptr = (void *) (pe_target + got_off); + unsigned unmatched_adr_got_page = 0; +#define MASK19 ((1 << 19) - 1) +#else + grub_uint32_t *tr = (void *) (pe_target + tramp_off); +#endif + + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + if ((s->sh_type == grub_host_to_target32 (SHT_REL)) || + (s->sh_type == grub_host_to_target32 (SHT_RELA))) + { + Elf_Rela *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Word target_section_index; + Elf_Addr target_section_addr; + Elf_Shdr *target_section; + Elf_Word j; + + if (!SUFFIX (is_kept_section) (s, image_target) && + !SUFFIX (is_kept_reloc_section) (s, image_target, smd)) + { + grub_util_info ("not translating relocations for omitted section %s", + smd->strtab + grub_le_to_cpu32 (s->sh_name)); + continue; + } + + target_section_index = grub_target_to_host32 (s->sh_info); + target_section_addr = smd->addrs[target_section_index]; + target_section = (Elf_Shdr *) ((char *) smd->sections + + (target_section_index + * smd->section_entsize)); + + grub_util_info ("dealing with the relocation section %s for %s", + smd->strtab + grub_target_to_host32 (s->sh_name), + smd->strtab + grub_target_to_host32 (target_section->sh_name)); + + rtab_size = grub_target_to_host (s->sh_size); + r_size = grub_target_to_host (s->sh_entsize); + rtab_offset = grub_target_to_host (s->sh_offset); + num_rs = rtab_size / r_size; + + for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); + j < num_rs; + j++, r = (Elf_Rela *) ((char *) r + r_size)) + { + Elf_Addr info; + Elf_Addr offset; + Elf_Addr sym_addr; + Elf_Addr *target; + Elf_Addr addend; + + offset = grub_target_to_host (r->r_offset); + target = SUFFIX (get_target_address) (e, target_section, + offset, image_target); + if (image_target->elf_target == EM_MIPS && image_target->voidp_sizeof == 8) + info = ((grub_uint64_t) r->r_info << 32) | + (grub_uint32_t) grub_be_to_cpu64 (r->r_info); + else + info = grub_target_to_host (r->r_info); + sym_addr = SUFFIX (get_symbol_address) (e, smd->symtab, + ELF_R_SYM (info), image_target); + + addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? + grub_target_to_host (r->r_addend) : 0; + + switch (image_target->elf_target) + { + case EM_386: + switch (ELF_R_TYPE (info)) + { + case R_386_NONE: + break; + + case R_386_32: + /* This is absolute. */ + *target = grub_host_to_target32 (grub_target_to_host32 (*target) + + addend + sym_addr); + grub_util_info ("relocating an R_386_32 entry to 0x%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) *target, + (unsigned long long) offset); + break; + + case R_386_PC32: + /* This is relative. */ + *target = grub_host_to_target32 (grub_target_to_host32 (*target) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_386_PC32 entry to 0x%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) *target, + (unsigned long long) offset); + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; +#ifdef MKIMAGE_ELF64 + case EM_X86_64: + switch (ELF_R_TYPE (info)) + { + + case R_X86_64_NONE: + break; + + case R_X86_64_64: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr); + grub_util_info ("relocating an R_X86_64_64 entry to 0x%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) *target, + (unsigned long long) offset); + break; + + case R_X86_64_PC32: + case R_X86_64_PLT32: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + *t32, (unsigned long long) offset); + break; + } + + case R_X86_64_PC64: + { + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_X86_64_PC64 entry to 0x%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) *target, + (unsigned long long) offset); + break; + } + + case R_X86_64_32: + case R_X86_64_32S: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + + addend + sym_addr); + grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + *t32, (unsigned long long) offset); + break; + } + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + case EM_IA_64: + switch (ELF_R_TYPE (info)) + { + case R_IA64_PCREL21B: + { + grub_uint64_t noff; + grub_ia64_make_trampoline (tr, addend + sym_addr); + noff = ((char *) tr - (char *) pe_target + - target_section_addr - (offset & ~3)) >> 4; + tr++; + if (noff & ~MASK19) + grub_util_error ("trampoline offset too big (%" + GRUB_HOST_PRIxLONG_LONG ")", + (unsigned long long) noff); + grub_ia64_add_value_to_slot_20b ((grub_addr_t) target, noff); + } + break; + + case R_IA64_LTOFF22X: + case R_IA64_LTOFF22: + { + Elf_Sym *sym; + + sym = (Elf_Sym *) ((char *) e + + grub_target_to_host (smd->symtab->sh_offset) + + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->sh_entsize)); + if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) + sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target + + sym->st_value + - image_target->vaddr_offset)); + } + /* FALLTHROUGH */ + case R_IA64_LTOFF_FPTR22: + *gpptr = grub_host_to_target64 (addend + sym_addr); + grub_ia64_add_value_to_slot_21 ((grub_addr_t) target, + (char *) gpptr - (char *) pe_target + + image_target->vaddr_offset); + gpptr++; + break; + + case R_IA64_GPREL22: + grub_ia64_add_value_to_slot_21 ((grub_addr_t) target, + addend + sym_addr); + break; + case R_IA64_GPREL64I: + grub_ia64_set_immu64 ((grub_addr_t) target, + addend + sym_addr); + break; + case R_IA64_PCREL64LSB: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + break; + + case R_IA64_SEGREL64LSB: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr - target_section_addr); + break; + case R_IA64_DIR64LSB: + case R_IA64_FPTR64LSB: + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + + addend + sym_addr); + grub_util_info ("relocating a direct entry to 0x%" + GRUB_HOST_PRIxLONG_LONG " at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) + grub_target_to_host64 (*target), + (unsigned long long) offset); + break; + + /* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */ + case R_IA64_LDXMOV: + break; + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + case EM_AARCH64: + { + sym_addr += addend; + switch (ELF_R_TYPE (info)) + { + case R_AARCH64_ABS64: + { + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr); + } + break; + case R_AARCH64_PREL32: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + + sym_addr + - target_section_addr - offset + - image_target->vaddr_offset); + grub_util_info ("relocating an R_AARCH64_PREL32 entry to 0x%x at the offset 0x%" + GRUB_HOST_PRIxLONG_LONG, + *t32, (unsigned long long) offset); + break; + } + case R_AARCH64_ADD_ABS_LO12_NC: + grub_arm64_set_abs_lo12 ((grub_uint32_t *) target, + sym_addr); + break; + case R_AARCH64_LDST64_ABS_LO12_NC: + grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) target, + sym_addr); + break; + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + { + sym_addr -= offset; + sym_addr -= target_section_addr + image_target->vaddr_offset; + if (!grub_arm_64_check_xxxx26_offset (sym_addr)) + grub_util_error ("%s", "CALL26 Relocation out of range"); + + grub_arm64_set_xxxx26_offset((grub_uint32_t *)target, + sym_addr); + } + break; + case R_AARCH64_ADR_GOT_PAGE: + { + Elf64_Rela *rel2; + grub_int64_t gpoffset = (((char *) gpptr - (char *) pe_target + image_target->vaddr_offset) & ~0xfffULL) + - ((offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL); + unsigned k; + *gpptr = grub_host_to_target64 (sym_addr); + unmatched_adr_got_page++; + if (!grub_arm64_check_hi21_signed (gpoffset)) + grub_util_error ("HI21 out of range"); + grub_arm64_set_hi21((grub_uint32_t *)target, + gpoffset); + for (k = 0, rel2 = (Elf_Rela *) ((char *) r + r_size); + k < num_rs; + k++, rel2 = (Elf_Rela *) ((char *) rel2 + r_size)) + if (ELF_R_SYM (rel2->r_info) + == ELF_R_SYM (r->r_info) + && r->r_addend == rel2->r_addend + && ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC) + { + grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) SUFFIX (get_target_address) (e, target_section, + grub_target_to_host (rel2->r_offset), image_target), + ((char *) gpptr - (char *) pe_target + image_target->vaddr_offset)); + break; + } + if (k >= num_rs) + grub_util_error ("ADR_GOT_PAGE without matching LD64_GOT_LO12_NC"); + gpptr++; + } + break; + case R_AARCH64_LD64_GOT_LO12_NC: + if (unmatched_adr_got_page == 0) + grub_util_error ("LD64_GOT_LO12_NC without matching ADR_GOT_PAGE"); + unmatched_adr_got_page--; + break; + case R_AARCH64_ADR_PREL_PG_HI21: + { + sym_addr &= ~0xfffULL; + sym_addr -= (offset + target_section_addr + image_target->vaddr_offset) & ~0xfffULL; + if (!grub_arm64_check_hi21_signed (sym_addr)) + grub_util_error ("%s", "CALL26 Relocation out of range"); + + grub_arm64_set_hi21((grub_uint32_t *)target, + sym_addr); + } + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + } + case EM_MIPS: + { + sym_addr += addend; + switch (ELF_R_TYPE (info)) + { + case R_MIPS_NONE: + break; + case R_MIPS_64: + { + *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr); + } + break; + case R_MIPS_32: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + sym_addr); + } + break; + case R_MIPS_26: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + grub_addr_t addr = grub_host_to_target64 (sym_addr); + *t32 = ((*t32) & 0xfc000000U) | ((addr >> 2) & 0x3ffffffUL); + } + break; + case R_MIPS_LO16: + { + grub_int16_t *t16 = (grub_int16_t *) target; + grub_addr_t addr = grub_host_to_target64 (sym_addr); + *t16 = (grub_int16_t) addr; + } + break; + case R_MIPS_HI16: + { + grub_int16_t *t16 = (grub_int16_t *) target; + grub_addr_t addr = grub_host_to_target64 (sym_addr); + *t16 = (grub_int16_t) ((addr + 0x8000UL) >> 16); + } + break; + case R_MIPS_HIGHER: + { + grub_int16_t *t16 = (grub_int16_t *) target; + grub_addr_t addr = grub_host_to_target64 (sym_addr); + *t16 = (grub_int16_t) ((addr + 0x80008000UL) >> 32); + } + break; + case R_MIPS_HIGHEST: + { + grub_uint16_t *t16 = (grub_uint16_t *) target; + grub_addr_t addr = grub_host_to_target64 (sym_addr); + *t16 = (grub_uint16_t) ((addr + 0x800080008000UL) >> 48); + } + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + } +#endif +#if defined(MKIMAGE_ELF32) + case EM_ARM: + { + sym_addr += addend; + sym_addr -= image_target->vaddr_offset; + switch (ELF_R_TYPE (info)) + { + case R_ARM_ABS32: + { + grub_util_info (" ABS32:\toffset=%d\t(0x%08x)", + (int) sym_addr, (int) sym_addr); + /* Data will be naturally aligned */ + if (image_target->id == IMAGE_EFI) + sym_addr += GRUB_PE32_SECTION_ALIGNMENT; + *target = grub_host_to_target32 (grub_target_to_host32 (*target) + sym_addr); + } + break; + /* Happens when compiled with -march=armv4. + Since currently we need at least armv5, keep bx as-is. + */ + case R_ARM_V4BX: + break; + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + case R_ARM_THM_JUMP19: + { + grub_err_t err; + Elf_Sym *sym; + grub_util_info (" THM_JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", + (unsigned long) ((char *) target + - (char *) e), + sym_addr); + sym = (Elf_Sym *) ((char *) e + + grub_target_to_host (smd->symtab->sh_offset) + + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->sh_entsize)); + if (ELF_ST_TYPE (sym->st_info) != STT_FUNC) + sym_addr |= 1; + if (!(sym_addr & 1)) + { + grub_uint32_t tr_addr; + grub_int32_t new_offset; + tr_addr = (char *) tr - (char *) pe_target + - target_section_addr; + new_offset = sym_addr - tr_addr - 12; + + if (!grub_arm_jump24_check_offset (new_offset)) + return grub_util_error ("jump24 relocation out of range"); + + tr[0] = grub_host_to_target32 (0x46c04778); /* bx pc; nop */ + tr[1] = grub_host_to_target32 (((new_offset >> 2) & 0xffffff) | 0xea000000); /* b new_offset */ + tr += 2; + sym_addr = tr_addr | 1; + } + sym_addr -= offset; + /* Thumb instructions can be 16-bit aligned */ + if (ELF_R_TYPE (info) == R_ARM_THM_JUMP19) + err = grub_arm_reloc_thm_jump19 ((grub_uint16_t *) target, sym_addr); + else + err = grub_arm_reloc_thm_call ((grub_uint16_t *) target, + sym_addr); + if (err) + grub_util_error ("%s", grub_errmsg); + } + break; + + case R_ARM_CALL: + case R_ARM_JUMP24: + { + grub_err_t err; + grub_util_info (" JUMP24:\ttarget=0x%08lx\toffset=(0x%08x)", (unsigned long) ((char *) target - (char *) e), sym_addr); + if (sym_addr & 1) + { + grub_uint32_t tr_addr; + grub_int32_t new_offset; + tr_addr = (char *) tr - (char *) pe_target + - target_section_addr; + new_offset = sym_addr - tr_addr - 12; + + /* There is no immediate version of bx, only register one... */ + tr[0] = grub_host_to_target32 (0xe59fc004); /* ldr ip, [pc, #4] */ + tr[1] = grub_host_to_target32 (0xe08cc00f); /* add ip, ip, pc */ + tr[2] = grub_host_to_target32 (0xe12fff1c); /* bx ip */ + tr[3] = grub_host_to_target32 (new_offset | 1); + tr += 4; + sym_addr = tr_addr; + } + sym_addr -= offset; + err = grub_arm_reloc_jump24 (target, + sym_addr); + if (err) + grub_util_error ("%s", grub_errmsg); + } + break; + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + } +#endif /* MKIMAGE_ELF32 */ + case EM_RISCV: + { + grub_uint64_t *t64 = (grub_uint64_t *) target; + grub_uint32_t *t32 = (grub_uint32_t *) target; + grub_uint16_t *t16 = (grub_uint16_t *) target; + grub_uint8_t *t8 = (grub_uint8_t *) target; + grub_int64_t off = (long)sym_addr - target_section_addr - offset + - image_target->vaddr_offset; + + /* + * Instructions and instruction encoding are documented in the RISC-V + * specification. This file is based on version 2.2: + * + * https://github.com/riscv/riscv-isa-manual/blob/master/release/riscv-spec-v2.2.pdf + */ + + sym_addr += addend; + + switch (ELF_R_TYPE (info)) + { + case R_RISCV_ADD8: + *t8 = *t8 + sym_addr; + break; + case R_RISCV_ADD16: + *t16 = grub_host_to_target16 (grub_target_to_host16 (*t16) + sym_addr); + break; + case R_RISCV_32: + case R_RISCV_ADD32: + *t32 = grub_host_to_target32 (grub_target_to_host32 (*t32) + sym_addr); + break; + case R_RISCV_64: + case R_RISCV_ADD64: + *t64 = grub_host_to_target64 (grub_target_to_host64 (*t64) + sym_addr); + break; + + case R_RISCV_SUB8: + *t8 = sym_addr - *t8; + break; + case R_RISCV_SUB16: + *t16 = grub_host_to_target16 (grub_target_to_host16 (*t16) - sym_addr); + break; + case R_RISCV_SUB32: + *t32 = grub_host_to_target32 (grub_target_to_host32 (*t32) - sym_addr); + break; + case R_RISCV_SUB64: + *t64 = grub_host_to_target64 (grub_target_to_host64 (*t64) - sym_addr); + break; + case R_RISCV_BRANCH: + { + grub_uint32_t imm12 = (off & 0x1000) << (31 - 12); + grub_uint32_t imm11 = (off & 0x800) >> (11 - 7); + grub_uint32_t imm10_5 = (off & 0x7e0) << (30 - 10); + grub_uint32_t imm4_1 = (off & 0x1e) << (11 - 4); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0x1fff07f) + | imm12 | imm11 | imm10_5 | imm4_1); + } + break; + case R_RISCV_JAL: + { + grub_uint32_t imm20 = (off & 0x100000) << (31 - 20); + grub_uint32_t imm19_12 = (off & 0xff000); + grub_uint32_t imm11 = (off & 0x800) << (20 - 11); + grub_uint32_t imm10_1 = (off & 0x7fe) << (30 - 10); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfff) + | imm20 | imm19_12 | imm11 | imm10_1); + } + break; + case R_RISCV_CALL: + { + grub_uint32_t hi20, lo12; + + if (off != (grub_int32_t)off) + grub_util_error ("target %lx not reachable from pc=%lx", (long)sym_addr, (long)((char *)target - (char *)e)); + + hi20 = (off + 0x800) & 0xfffff000; + lo12 = (off - hi20) & 0xfff; + t32[0] = grub_host_to_target32 ((grub_target_to_host32 (t32[0]) & 0xfff) | hi20); + t32[1] = grub_host_to_target32 ((grub_target_to_host32 (t32[1]) & 0xfffff) | (lo12 << 20)); + } + break; + case R_RISCV_RVC_BRANCH: + { + grub_uint16_t imm8 = (off & 0x100) << (12 - 8); + grub_uint16_t imm7_6 = (off & 0xc0) >> (6 - 5); + grub_uint16_t imm5 = (off & 0x20) >> (5 - 2); + grub_uint16_t imm4_3 = (off & 0x18) << (12 - 5); + grub_uint16_t imm2_1 = (off & 0x6) << (12 - 10); + *t16 = grub_host_to_target16 ((grub_target_to_host16 (*t16) & 0xe383) + | imm8 | imm7_6 | imm5 | imm4_3 | imm2_1); + } + break; + case R_RISCV_RVC_JUMP: + { + grub_uint16_t imm11 = (off & 0x800) << (12 - 11); + grub_uint16_t imm10 = (off & 0x400) >> (10 - 8); + grub_uint16_t imm9_8 = (off & 0x300) << (12 - 11); + grub_uint16_t imm7 = (off & 0x80) >> (7 - 6); + grub_uint16_t imm6 = (off & 0x40) << (12 - 11); + grub_uint16_t imm5 = (off & 0x20) >> (5 - 2); + grub_uint16_t imm4 = (off & 0x10) << (12 - 5); + grub_uint16_t imm3_1 = (off & 0xe) << (12 - 10); + *t16 = grub_host_to_target16 ((grub_target_to_host16 (*t16) & 0xe003) + | imm11 | imm10 | imm9_8 | imm7 | imm6 + | imm5 | imm4 | imm3_1); + } + break; + case R_RISCV_PCREL_HI20: + { + grub_int32_t hi20; + + if (off != (grub_int32_t)off) + grub_util_error ("target %lx not reachable from pc=%lx", (long)sym_addr, (long)((char *)target - (char *)e)); + + hi20 = (off + 0x800) & 0xfffff000; + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfff) | hi20); + } + break; + case R_RISCV_PCREL_LO12_I: + case R_RISCV_PCREL_LO12_S: + { + Elf_Rela *rel2; + Elf_Word k; + /* Search backwards for matching HI20 reloc. */ + for (k = j, rel2 = (Elf_Rela *) ((char *) r - r_size); + k > 0; + k--, rel2 = (Elf_Rela *) ((char *) rel2 - r_size)) + { + Elf_Addr rel2_info; + Elf_Addr rel2_offset; + Elf_Addr rel2_sym_addr; + Elf_Addr rel2_addend; + Elf_Addr rel2_loc; + grub_int64_t rel2_off; + + rel2_offset = grub_target_to_host (rel2->r_offset); + rel2_info = grub_target_to_host (rel2->r_info); + rel2_loc = target_section_addr + rel2_offset + image_target->vaddr_offset; + + if (ELF_R_TYPE (rel2_info) == R_RISCV_PCREL_HI20 + && rel2_loc == sym_addr) + { + rel2_sym_addr = SUFFIX (get_symbol_address) + (e, smd->symtab, ELF_R_SYM (rel2_info), + image_target); + rel2_addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? + grub_target_to_host (rel2->r_addend) : 0; + rel2_off = rel2_sym_addr + rel2_addend - rel2_loc; + off = rel2_off - ((rel2_off + 0x800) & 0xfffff000); + + if (ELF_R_TYPE (info) == R_RISCV_PCREL_LO12_I) + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfffff) | (off & 0xfff) << 20); + else + { + grub_uint32_t imm11_5 = (off & 0xfe0) << (31 - 11); + grub_uint32_t imm4_0 = (off & 0x1f) << (11 - 4); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0x1fff07f) | imm11_5 | imm4_0); + } + break; + } + } + if (k == 0) + grub_util_error ("cannot find matching HI20 relocation"); + } + break; + case R_RISCV_HI20: + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfff) | (((grub_int32_t) sym_addr + 0x800) & 0xfffff000)); + break; + case R_RISCV_LO12_I: + { + grub_int32_t lo12 = (grub_int32_t) sym_addr - (((grub_int32_t) sym_addr + 0x800) & 0xfffff000); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0xfffff) | ((lo12 & 0xfff) << 20)); + } + break; + case R_RISCV_LO12_S: + { + grub_int32_t lo12 = (grub_int32_t) sym_addr - (((grub_int32_t) sym_addr + 0x800) & 0xfffff000); + grub_uint32_t imm11_5 = (lo12 & 0xfe0) << (31 - 11); + grub_uint32_t imm4_0 = (lo12 & 0x1f) << (11 - 4); + *t32 = grub_host_to_target32 ((grub_target_to_host32 (*t32) & 0x1fff07f) | imm11_5 | imm4_0); + } + break; + case R_RISCV_RELAX: + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + } + default: + grub_util_error ("unknown architecture type %d", + image_target->elf_target); + } + } + } +} + +/* Add a PE32's fixup entry for a relocation. Return the resulting address + after having written to the file OUT. */ +static Elf_Addr +add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, + Elf_Addr addr, int flush, Elf_Addr current_address, + const struct grub_install_image_target_desc *image_target) +{ + struct grub_pe32_fixup_block *b; + + b = &((*cblock)->b); + + /* First, check if it is necessary to write out the current block. */ + if ((*cblock)->state) + { + if (flush || (type && (addr < b->page_rva || b->page_rva + 0x1000 <= addr))) + { + grub_uint32_t size; + + if (flush) + { + /* Add as much padding as necessary to align the address + with a section boundary. */ + Elf_Addr next_address; + unsigned padding_size; + size_t cur_index; + + next_address = current_address + b->block_size; + padding_size = ((ALIGN_UP (next_address, image_target->section_align) + - next_address) + >> 1); + cur_index = ((b->block_size - sizeof (*b)) >> 1); + grub_util_info ("adding %d padding fixup entries", padding_size); + while (padding_size--) + { + b->entries[cur_index++] = 0; + b->block_size += 2; + } + } + else while (b->block_size & (8 - 1)) + { + /* If not aligned with a 32-bit boundary, add + a padding entry. */ + size_t cur_index; + + grub_util_info ("adding a padding fixup entry"); + cur_index = ((b->block_size - sizeof (*b)) >> 1); + b->entries[cur_index] = 0; + b->block_size += 2; + } + + /* Flush it. */ + grub_util_info ("writing %d bytes of a fixup block starting at 0x%x", + b->block_size, b->page_rva); + size = b->block_size; + current_address += size; + b->page_rva = grub_host_to_target32 (b->page_rva); + b->block_size = grub_host_to_target32 (b->block_size); + (*cblock)->next = xmalloc (sizeof (**cblock) + 2 * 0x1000); + memset ((*cblock)->next, 0, sizeof (**cblock) + 2 * 0x1000); + *cblock = (*cblock)->next; + } + } + + b = &((*cblock)->b); + + if (! flush) + { + grub_uint16_t entry; + size_t cur_index; + + /* If not allocated yet, allocate a block with enough entries. */ + if (! (*cblock)->state) + { + (*cblock)->state = 1; + + /* The spec does not mention the requirement of a Page RVA. + Here, align the address with a 4K boundary for safety. */ + if (type) + b->page_rva = (addr & ~(0x1000 - 1)); + b->block_size = sizeof (*b); + } + + /* Sanity check. */ + if (b->block_size >= sizeof (*b) + 2 * 0x1000) + grub_util_error ("too many fixup entries"); + + /* Add a new entry. */ + cur_index = ((b->block_size - sizeof (*b)) >> 1); + entry = GRUB_PE32_FIXUP_ENTRY (type, type ? (addr - b->page_rva) : addr); + b->entries[cur_index] = grub_host_to_target16 (entry); + b->block_size += 2; + } + + return current_address; +} + +struct raw_reloc +{ + struct raw_reloc *next; + grub_uint32_t offset; + enum raw_reloc_type { + RAW_RELOC_NONE = -1, + RAW_RELOC_32 = 0, + RAW_RELOC_MAX = 1, + } type; +}; + +struct translate_context +{ + /* PE */ + struct fixup_block_list *lst, *lst0; + Elf_Addr current_address; + + /* Raw */ + struct raw_reloc *raw_relocs; +}; + +static void +translate_reloc_start (struct translate_context *ctx, + const struct grub_install_image_target_desc *image_target) +{ + grub_memset (ctx, 0, sizeof (*ctx)); + if (image_target->id == IMAGE_EFI) + { + ctx->lst = ctx->lst0 = xmalloc (sizeof (*ctx->lst) + 2 * 0x1000); + memset (ctx->lst, 0, sizeof (*ctx->lst) + 2 * 0x1000); + ctx->current_address = 0; + } +} + +static void +translate_relocation_pe (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, + Elf_Addr sym_addr, + Elf_Addr addend, + const struct grub_install_image_target_desc *image_target) +{ + /* Necessary to relocate only absolute addresses. */ + switch (image_target->elf_target) + { + case EM_386: + if (ELF_R_TYPE (info) == R_386_32) + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, ctx->current_address, + image_target); + } + break; + case EM_X86_64: + if ((ELF_R_TYPE (info) == R_X86_64_32) || + (ELF_R_TYPE (info) == R_X86_64_32S)) + { + grub_util_error ("can\'t add fixup entry for R_X86_64_32(S)"); + } + else if (ELF_R_TYPE (info) == R_X86_64_64) + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, ctx->current_address, + image_target); + } + break; + case EM_IA_64: + switch (ELF_R_TYPE (info)) + { + case R_IA64_PCREL64LSB: + case R_IA64_LDXMOV: + case R_IA64_PCREL21B: + case R_IA64_LTOFF_FPTR22: + case R_IA64_LTOFF22X: + case R_IA64_LTOFF22: + case R_IA64_GPREL22: + case R_IA64_GPREL64I: + case R_IA64_SEGREL64LSB: + break; + + case R_IA64_FPTR64LSB: + case R_IA64_DIR64LSB: +#if 1 + { + grub_util_info ("adding a relocation entry for 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) addr); + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, ctx->current_address, + image_target); + } +#endif + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + case EM_AARCH64: + switch (ELF_R_TYPE (info)) + { + case R_AARCH64_ABS64: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, 0, ctx->current_address, + image_target); + } + break; + /* Relative relocations do not require fixup entries. */ + case R_AARCH64_CALL26: + case R_AARCH64_JUMP26: + case R_AARCH64_PREL32: + break; + /* Page-relative relocations do not require fixup entries. */ + case R_AARCH64_ADR_PREL_PG_HI21: + /* We page-align the whole kernel, so no need + for fixup entries. + */ + case R_AARCH64_ADD_ABS_LO12_NC: + case R_AARCH64_LDST64_ABS_LO12_NC: + break; + + /* GOT is relocated separately. */ + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_LD64_GOT_LO12_NC: + break; + + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; +#if defined(MKIMAGE_ELF64) + case EM_MIPS: + switch (ELF_R_TYPE (info)) + { + case R_MIPS_64: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_MIPS_32: +#if 0 + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, ctx->current_address, + image_target); + } +#endif + break; + case R_MIPS_26: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_MIPS_JMPADDR, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_MIPS_LO16: + { + Elf_Addr target = sym_addr + addend; + + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_MIPS_LOW, + addr, 0, ctx->current_address, + image_target); + /* Hi */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_int16_t) ((target & 0x8000UL) >> 16), + 0, ctx->current_address, + image_target); + /* Higher */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_int16_t) ((target & 0x80008000UL) >> 32), + 0, ctx->current_address, + image_target); + /* Highest */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_uint16_t) ((target & 0x800080008000UL) >> 48), + 0, ctx->current_address, + image_target); + } + break; + case R_MIPS_HI16: + { + Elf_Addr target = sym_addr + addend; + + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_MIPS_HIGH, + addr, 0, ctx->current_address, + image_target); + /* Lo */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_int16_t) target, + 0, ctx->current_address, + image_target); + /* Higher */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_int16_t) ((target & 0x80008000UL) >> 32), + 0, ctx->current_address, + image_target); + /* Highest */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_uint16_t) ((target & 0x800080008000UL) >> 48), + 0, ctx->current_address, + image_target); + } + break; + case R_MIPS_HIGHER: + { + Elf_Addr target = sym_addr + addend; + + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_MIPS_HIGHER, + addr, 0, ctx->current_address, + image_target); + /* Lo */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_int16_t) target, + 0, ctx->current_address, + image_target); + /* Hi */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_int16_t) ((target & 0x8000UL) >> 16), + 0, ctx->current_address, + image_target); + /* Highest */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_uint16_t) ((target & 0x800080008000UL) >> 48), + 0, ctx->current_address, + image_target); + } + break; + case R_MIPS_HIGHEST: + { + Elf_Addr target = sym_addr + addend; + + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_MIPS_HIGHEST, + addr, 0, ctx->current_address, + image_target); + /* Lo */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_int16_t) target, + 0, ctx->current_address, + image_target); + /* Hi */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_int16_t) ((target & 0x8000UL) >> 16), + 0, ctx->current_address, + image_target); + /* Higher */ + ctx->current_address + = add_fixup_entry (&ctx->lst, 0, + (grub_int16_t) ((target & 0x80008000UL) >> 32), + 0, ctx->current_address, + image_target); + } + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; +#endif +#if defined(MKIMAGE_ELF32) + case EM_ARM: + switch (ELF_R_TYPE (info)) + { + case R_ARM_V4BX: + /* Relative relocations do not require fixup entries. */ + case R_ARM_JUMP24: + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_CALL: + { + grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address); + } + break; + /* Create fixup entry for PE/COFF loader */ + case R_ARM_ABS32: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, ctx->current_address, + image_target); + } + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; +#endif /* defined(MKIMAGE_ELF32) */ + case EM_RISCV: + switch (ELF_R_TYPE (info)) + { + case R_RISCV_32: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_RISCV_64: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + addr, 0, ctx->current_address, + image_target); + } + break; + /* Relative relocations do not require fixup entries. */ + case R_RISCV_BRANCH: + case R_RISCV_JAL: + case R_RISCV_CALL: + case R_RISCV_PCREL_HI20: + case R_RISCV_PCREL_LO12_I: + case R_RISCV_PCREL_LO12_S: + case R_RISCV_RVC_BRANCH: + case R_RISCV_RVC_JUMP: + case R_RISCV_ADD32: + case R_RISCV_SUB32: + grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x", __FUNCTION__, (unsigned int) addr, (unsigned int) ctx->current_address); + break; + case R_RISCV_HI20: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_RISCV_HI20, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_RISCV_LO12_I: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_RISCV_LOW12I, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_RISCV_LO12_S: + { + ctx->current_address + = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_RISCV_LOW12S, + addr, 0, ctx->current_address, + image_target); + } + break; + case R_RISCV_RELAX: + break; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + default: + grub_util_error ("unknown machine type 0x%x", image_target->elf_target); + } +} + +static enum raw_reloc_type +classify_raw_reloc (Elf_Addr info, + const struct grub_install_image_target_desc *image_target) +{ + /* Necessary to relocate only absolute addresses. */ + switch (image_target->elf_target) + { + case EM_ARM: + switch (ELF_R_TYPE (info)) + { + case R_ARM_V4BX: + case R_ARM_JUMP24: + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_CALL: + return RAW_RELOC_NONE; + case R_ARM_ABS32: + return RAW_RELOC_32; + default: + grub_util_error (_("relocation 0x%x is not implemented yet"), + (unsigned int) ELF_R_TYPE (info)); + break; + } + break; + default: + grub_util_error ("unknown machine type 0x%x", image_target->elf_target); + } +} + +static void +translate_relocation_raw (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, + const struct grub_install_image_target_desc *image_target) +{ + enum raw_reloc_type class = classify_raw_reloc (info, image_target); + struct raw_reloc *rel; + if (class == RAW_RELOC_NONE) + return; + rel = xmalloc (sizeof (*rel)); + rel->next = ctx->raw_relocs; + rel->type = class; + rel->offset = addr; + ctx->raw_relocs = rel; +} + +static void +translate_relocation (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, + Elf_Addr sym_addr, + Elf_Addr addend, + const struct grub_install_image_target_desc *image_target) +{ + if (image_target->id == IMAGE_EFI) + translate_relocation_pe (ctx, addr, info, sym_addr, addend, image_target); + else + translate_relocation_raw (ctx, addr, info, image_target); +} + +static void +finish_reloc_translation_pe (struct translate_context *ctx, struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + ctx->current_address = add_fixup_entry (&ctx->lst, 0, 0, 1, ctx->current_address, image_target); + + { + grub_uint8_t *ptr; + layout->reloc_section = ptr = xmalloc (ctx->current_address); + for (ctx->lst = ctx->lst0; ctx->lst; ctx->lst = ctx->lst->next) + if (ctx->lst->state) + { + memcpy (ptr, &ctx->lst->b, grub_target_to_host32 (ctx->lst->b.block_size)); + ptr += grub_target_to_host32 (ctx->lst->b.block_size); + } + assert ((ctx->current_address + (grub_uint8_t *) layout->reloc_section) == ptr); + } + + for (ctx->lst = ctx->lst0; ctx->lst; ) + { + struct fixup_block_list *next; + next = ctx->lst->next; + free (ctx->lst); + ctx->lst = next; + } + + layout->reloc_size = ctx->current_address; + if (image_target->elf_target == EM_ARM && layout->reloc_size > GRUB_KERNEL_ARM_STACK_SIZE) + grub_util_error ("Reloc section (%d) is bigger than stack size (%d). " + "This breaks assembly assumptions. Please increase stack size", + (int) layout->reloc_size, + (int) GRUB_KERNEL_ARM_STACK_SIZE); +} + +/* + Layout: + + + + + ... + + + each relocation starts with 32-bit offset. Rest depends on relocation. + mkimage stops when it sees first unknown type or end marker. + This allows images to be created with mismatched mkimage and + kernel as long as no relocations are present in kernel that mkimage + isn't aware of (in which case mkimage aborts). + This also allows simple assembly to do the relocs. +*/ + +#define RAW_SEPARATOR 0xfffffffe +#define RAW_END_MARKER 0xffffffff + +static void +finish_reloc_translation_raw (struct translate_context *ctx, struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + size_t count = 0, sz; + enum raw_reloc_type highest = RAW_RELOC_NONE; + enum raw_reloc_type curtype; + struct raw_reloc *cur; + grub_uint32_t *p; + if (!ctx->raw_relocs) + { + layout->reloc_section = p = xmalloc (sizeof (grub_uint32_t)); + p[0] = RAW_END_MARKER; + layout->reloc_size = sizeof (grub_uint32_t); + return; + } + for (cur = ctx->raw_relocs; cur; cur = cur->next) + { + count++; + if (cur->type > highest) + highest = cur->type; + } + /* highest separators, count relocations and one end marker. */ + sz = (highest + count + 1) * sizeof (grub_uint32_t); + layout->reloc_section = p = xmalloc (sz); + for (curtype = 0; curtype <= highest; curtype++) + { + /* Support for special cases would go here. */ + for (cur = ctx->raw_relocs; cur; cur = cur->next) + if (cur->type == curtype) + { + *p++ = cur->offset; + } + *p++ = RAW_SEPARATOR; + } + *--p = RAW_END_MARKER; + layout->reloc_size = sz; +} + +static void +finish_reloc_translation (struct translate_context *ctx, struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + if (image_target->id == IMAGE_EFI) + finish_reloc_translation_pe (ctx, layout, image_target); + else + finish_reloc_translation_raw (ctx, layout, image_target); +} + + +static void +create_u64_fixups (struct translate_context *ctx, + Elf_Addr jumpers, grub_size_t njumpers, + const struct grub_install_image_target_desc *image_target) +{ + unsigned i; + assert (image_target->id == IMAGE_EFI); + for (i = 0; i < njumpers; i++) + ctx->current_address = add_fixup_entry (&ctx->lst, + GRUB_PE32_REL_BASED_DIR64, + jumpers + 8 * i, + 0, ctx->current_address, + image_target); +} + +/* Make a .reloc section. */ +static void +make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, + struct section_metadata *smd, + const struct grub_install_image_target_desc *image_target) +{ + unsigned i; + Elf_Shdr *s; + struct translate_context ctx; + + translate_reloc_start (&ctx, image_target); + + for (i = 0, s = smd->sections; i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + if ((grub_target_to_host32 (s->sh_type) == SHT_REL) || + (grub_target_to_host32 (s->sh_type) == SHT_RELA)) + { + Elf_Rela *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Shdr *symtab_section; + Elf_Addr section_address; + Elf_Word j; + + if (!SUFFIX (is_kept_reloc_section) (s, image_target, smd)) + { + grub_util_info ("not translating the skipped relocation section %s", + smd->strtab + grub_le_to_cpu32 (s->sh_name)); + continue; + } + + symtab_section = (Elf_Shdr *) ((char *) smd->sections + + (grub_target_to_host32 (s->sh_link) + * smd->section_entsize)); + + grub_util_info ("translating the relocation section %s", + smd->strtab + grub_le_to_cpu32 (s->sh_name)); + + rtab_size = grub_target_to_host (s->sh_size); + r_size = grub_target_to_host (s->sh_entsize); + rtab_offset = grub_target_to_host (s->sh_offset); + num_rs = rtab_size / r_size; + + section_address = smd->vaddrs[grub_le_to_cpu32 (s->sh_info)]; + + for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); + j < num_rs; + j++, r = (Elf_Rela *) ((char *) r + r_size)) + { + Elf_Addr info; + Elf_Addr offset; + Elf_Addr addr; + Elf_Addr sym_addr; + Elf_Addr addend; + + offset = grub_target_to_host (r->r_offset); + if (image_target->elf_target == EM_MIPS && image_target->voidp_sizeof == 8) + info = ((grub_uint64_t) r->r_info << 32) | + (grub_uint32_t) grub_be_to_cpu64 (r->r_info); + else + info = grub_target_to_host (r->r_info); + + sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, + ELF_R_SYM (info), image_target); + addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? + grub_target_to_host (r->r_addend) : 0; + addr = section_address + offset; + + translate_relocation (&ctx, addr, info, sym_addr, addend, image_target); + } + } + + if (image_target->elf_target == EM_IA_64) + create_u64_fixups (&ctx, + layout->ia64jmp_off + + image_target->vaddr_offset, + 2 * layout->ia64jmpnum, + image_target); + if (image_target->elf_target == EM_IA_64 || image_target->elf_target == EM_AARCH64) + create_u64_fixups (&ctx, + layout->got_off + + image_target->vaddr_offset, + (layout->got_size / 8), + image_target); + + finish_reloc_translation (&ctx, layout, image_target); +} + +/* Determine if this section is a text section. Return false if this + section is not allocated. */ +static int +SUFFIX (is_text_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) +{ + if (!is_relocatable (image_target) + && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) + return 0; + return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) + == (SHF_EXECINSTR | SHF_ALLOC)); +} + +/* Determine if this section is a data section. */ +static int +SUFFIX (is_data_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) +{ + if (!is_relocatable (image_target) + && grub_target_to_host32 (s->sh_type) != SHT_PROGBITS) + return 0; + return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) + == SHF_ALLOC) && !(grub_target_to_host32 (s->sh_type) == SHT_NOBITS); +} + +static int +SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) +{ + if (!is_relocatable (image_target)) + return 0; + return ((grub_target_to_host (s->sh_flags) & (SHF_EXECINSTR | SHF_ALLOC)) + == SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS); +} + +/* Determine if a section is going to be in the final output */ +static int +SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target) +{ + /* We keep .text and .data */ + if (SUFFIX (is_text_section) (s, image_target) + || SUFFIX (is_data_section) (s, image_target)) + return 1; + + /* + * And we keep .bss if we're producing PE binaries or the target doesn't + * have a relocating loader. Platforms other than EFI and U-boot shouldn't + * have .bss in their binaries as we build with -Wl,-Ttext. + */ + if (SUFFIX (is_bss_section) (s, image_target) + && (image_target->id == IMAGE_EFI || !is_relocatable (image_target))) + return 1; + + /* Otherwise this is not a section we're keeping in the final output. */ + return 0; +} + +static int +SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target, + struct section_metadata *smd) +{ + int i; + int r = 0; + const char *name = smd->strtab + grub_host_to_target32 (s->sh_name); + + if (!strncmp (name, ".rela.", 6)) + name += 5; + else if (!strncmp (name, ".rel.", 5)) + name += 4; + else + return 1; + + for (i = 0, s = smd->sections; i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + { + const char *sname = smd->strtab + grub_host_to_target32 (s->sh_name); + if (strcmp (sname, name)) + continue; + + return SUFFIX (is_kept_section) (s, image_target); + } + + return r; +} + +/* Return if the ELF header is valid. */ +static int +SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_image_target_desc *image_target) +{ + if (size < sizeof (*e) + || e->e_ident[EI_MAG0] != ELFMAG0 + || e->e_ident[EI_MAG1] != ELFMAG1 + || e->e_ident[EI_MAG2] != ELFMAG2 + || e->e_ident[EI_MAG3] != ELFMAG3 + || e->e_ident[EI_VERSION] != EV_CURRENT + || e->e_ident[EI_CLASS] != ELFCLASSXX + || e->e_version != grub_host_to_target32 (EV_CURRENT)) + return 0; + + return 1; +} + +static Elf_Addr +SUFFIX (put_section) (Elf_Shdr *s, int i, + Elf_Addr current_address, + struct section_metadata *smd, + const struct grub_install_image_target_desc *image_target) +{ + Elf_Word align = grub_host_to_target_addr (s->sh_addralign); + const char *name = smd->strtab + grub_host_to_target32 (s->sh_name); + + if (align) + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + align) + - image_target->vaddr_offset; + + grub_util_info ("locating the section %s at 0x%" + GRUB_HOST_PRIxLONG_LONG, + name, (unsigned long long) current_address); + if (!is_relocatable (image_target)) + current_address = grub_host_to_target_addr (s->sh_addr) + - image_target->link_addr; + smd->addrs[i] = current_address; + current_address += grub_host_to_target_addr (s->sh_size); + return current_address; +} + +/* + * Locate section addresses by merging code sections and data sections + * into .text and .data, respectively. + */ +static void +SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path, + struct section_metadata *smd, + struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + int i; + Elf_Shdr *s; + + layout->align = 1; + /* Page-aligning simplifies relocation handling. */ + if (image_target->elf_target == EM_AARCH64) + layout->align = 4096; + + layout->kernel_size = 0; + + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) + && grub_host_to_target32 (s->sh_addralign) > layout->align) + layout->align = grub_host_to_target32 (s->sh_addralign); + + /* .text */ + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + if (SUFFIX (is_text_section) (s, image_target)) + { + layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size, + smd, image_target); + if (!is_relocatable (image_target) && + grub_host_to_target_addr (s->sh_addr) != image_target->link_addr) + { + char *msg + = grub_xasprintf (_("`%s' is miscompiled: its start address is 0x%llx" + " instead of 0x%llx: ld.gold bug?"), + kernel_path, + (unsigned long long) grub_host_to_target_addr (s->sh_addr), + (unsigned long long) image_target->link_addr); + grub_util_error ("%s", msg); + } + } + +#ifdef MKIMAGE_ELF32 + if (image_target->elf_target == EM_ARM) + { + grub_size_t tramp; + + layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); + + tramp = arm_get_trampoline_size (e, smd->sections, smd->section_entsize, + smd->num_sections, image_target); + + layout->tramp_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (tramp, 16); + } +#endif + + layout->kernel_size = ALIGN_UP (layout->kernel_size + image_target->vaddr_offset, + image_target->section_align) + - image_target->vaddr_offset; + layout->exec_size = layout->kernel_size; + + /* .data */ + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + if (SUFFIX (is_data_section) (s, image_target)) + layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size, smd, + image_target); + + layout->bss_start = layout->kernel_size; + layout->end = layout->kernel_size; + + /* .bss */ + for (i = 0, s = smd->sections; + i < smd->num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize)) + { + if (SUFFIX (is_bss_section) (s, image_target)) + layout->end = SUFFIX (put_section) (s, i, layout->end, smd, image_target); + + /* + * This must to be in the last time this function passes through the loop. + */ + smd->vaddrs[i] = smd->addrs[i] + image_target->vaddr_offset; + } + + layout->end = ALIGN_UP (layout->end + image_target->vaddr_offset, + image_target->section_align) - image_target->vaddr_offset; + /* Explicitly initialize BSS + when producing PE32 to avoid a bug in EFI implementations. + Platforms other than EFI and U-boot shouldn't have .bss in + their binaries as we build with -Wl,-Ttext. + */ + if (image_target->id == IMAGE_EFI || !is_relocatable (image_target)) + layout->kernel_size = layout->end; +} + +char * +SUFFIX (grub_mkimage_load_image) (const char *kernel_path, + size_t total_module_size, + struct grub_mkimage_layout *layout, + const struct grub_install_image_target_desc *image_target) +{ + char *kernel_img, *out_img; + struct section_metadata smd = { 0, 0, 0, 0, 0, 0, 0 }; + Elf_Ehdr *e; + int i; + Elf_Shdr *s; + Elf_Off section_offset; + grub_size_t kernel_size; + + grub_memset (layout, 0, sizeof (*layout)); + + layout->start_address = 0; + + kernel_size = grub_util_get_image_size (kernel_path); + kernel_img = xmalloc (kernel_size); + grub_util_load_image (kernel_path, kernel_img); + + e = (Elf_Ehdr *) kernel_img; + if (! SUFFIX (check_elf_header) (e, kernel_size, image_target)) + grub_util_error ("invalid ELF header"); + + section_offset = grub_target_to_host (e->e_shoff); + smd.section_entsize = grub_target_to_host16 (e->e_shentsize); + smd.num_sections = grub_target_to_host16 (e->e_shnum); + + if (kernel_size < section_offset + + (grub_uint32_t) smd.section_entsize * smd.num_sections) + grub_util_error (_("premature end of file %s"), kernel_path); + + smd.sections = (Elf_Shdr *) (kernel_img + section_offset); + + /* Relocate sections then symbols in the virtual address space. */ + s = (Elf_Shdr *) ((char *) smd.sections + + grub_host_to_target16 (e->e_shstrndx) * smd.section_entsize); + smd.strtab = (char *) e + grub_host_to_target_addr (s->sh_offset); + + smd.addrs = xmalloc (sizeof (*smd.addrs) * smd.num_sections); + memset (smd.addrs, 0, sizeof (*smd.addrs) * smd.num_sections); + smd.vaddrs = xmalloc (sizeof (*smd.vaddrs) * smd.num_sections); + memset (smd.vaddrs, 0, sizeof (*smd.vaddrs) * smd.num_sections); + + SUFFIX (locate_sections) (e, kernel_path, &smd, layout, image_target); + + if (!is_relocatable (image_target)) + { + Elf_Addr current_address = layout->kernel_size; + + for (i = 0, s = smd.sections; + i < smd.num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize)) + if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) + { + Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign); + const char *name = smd.strtab + grub_host_to_target32 (s->sh_name); + + if (sec_align) + current_address = ALIGN_UP (current_address + + image_target->vaddr_offset, + sec_align) + - image_target->vaddr_offset; + + grub_util_info ("locating the section %s at 0x%" + GRUB_HOST_PRIxLONG_LONG, + name, (unsigned long long) current_address); + if (!is_relocatable (image_target)) + current_address = grub_host_to_target_addr (s->sh_addr) + - image_target->link_addr; + + smd.vaddrs[i] = current_address + + image_target->vaddr_offset; + current_address += grub_host_to_target_addr (s->sh_size); + } + current_address = ALIGN_UP (current_address + image_target->vaddr_offset, + image_target->section_align) + - image_target->vaddr_offset; + layout->bss_size = current_address - layout->kernel_size; + } + else + layout->bss_size = 0; + + if (image_target->id == IMAGE_SPARC64_AOUT + || image_target->id == IMAGE_SPARC64_RAW + || image_target->id == IMAGE_UBOOT + || image_target->id == IMAGE_COREBOOT + || image_target->id == IMAGE_SPARC64_CDCORE) + layout->kernel_size = ALIGN_UP (layout->kernel_size, image_target->mod_align); + + if (is_relocatable (image_target)) + { + smd.symtab = NULL; + for (i = 0, s = smd.sections; + i < smd.num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize)) + if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB)) + { + smd.symtab = s; + break; + } + if (! smd.symtab) + grub_util_error ("%s", _("no symbol table")); +#ifdef MKIMAGE_ELF64 + if (image_target->elf_target == EM_IA_64) + { + grub_size_t tramp; + + layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); + + grub_ia64_dl_get_tramp_got_size (e, &tramp, &layout->got_size); + + layout->tramp_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (tramp, 16); + + layout->ia64jmp_off = layout->kernel_size; + layout->ia64jmpnum = SUFFIX (count_funcs) (e, smd.symtab, + image_target); + layout->kernel_size += 16 * layout->ia64jmpnum; + + layout->got_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (layout->got_size, 16); + } + if (image_target->elf_target == EM_AARCH64) + { + grub_size_t tramp; + + layout->kernel_size = ALIGN_UP (layout->kernel_size, 16); + + grub_arm64_dl_get_tramp_got_size (e, &tramp, &layout->got_size); + + layout->got_off = layout->kernel_size; + layout->kernel_size += ALIGN_UP (layout->got_size, 16); + } +#endif + } + else + { + layout->reloc_size = 0; + layout->reloc_section = NULL; + } + + out_img = xmalloc (layout->kernel_size + total_module_size); + memset (out_img, 0, layout->kernel_size + total_module_size); + + if (is_relocatable (image_target)) + { + layout->start_address = SUFFIX (relocate_symbols) (e, &smd, + (char *) out_img + layout->ia64jmp_off, + layout->ia64jmp_off + image_target->vaddr_offset, + layout->bss_start, layout->end, image_target); + + if (layout->start_address == (Elf_Addr) -1) + grub_util_error ("start symbol is not defined"); + + /* Resolve addrs in the virtual address space. */ + SUFFIX (relocate_addrs) (e, &smd, out_img, layout->tramp_off, + layout->got_off, image_target); + + make_reloc_section (e, layout, &smd, image_target); + if (image_target->id != IMAGE_EFI) + { + out_img = xrealloc (out_img, layout->kernel_size + total_module_size + + ALIGN_UP (layout->reloc_size, image_target->mod_align)); + memcpy (out_img + layout->kernel_size, layout->reloc_section, layout->reloc_size); + memset (out_img + layout->kernel_size + layout->reloc_size, 0, + total_module_size + ALIGN_UP (layout->reloc_size, image_target->mod_align) - layout->reloc_size); + layout->kernel_size += ALIGN_UP (layout->reloc_size, image_target->mod_align); + } + } + + for (i = 0, s = smd.sections; + i < smd.num_sections; + i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize)) + if (SUFFIX (is_kept_section) (s, image_target)) + { + if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) + memset (out_img + smd.addrs[i], 0, + grub_host_to_target_addr (s->sh_size)); + else + memcpy (out_img + smd.addrs[i], + kernel_img + grub_host_to_target_addr (s->sh_offset), + grub_host_to_target_addr (s->sh_size)); + } + free (kernel_img); + + free (smd.vaddrs); + smd.vaddrs = NULL; + free (smd.addrs); + smd.addrs = NULL; + + return out_img; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mknetdir.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mknetdir.c new file mode 100644 index 0000000..815e807 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mknetdir.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2013 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . +*/ + +#include + +#include +#include +#include + +#include +#include + +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +static char *rootdir = NULL, *subdir = NULL; +static char *debug_image = NULL; + +enum + { + OPTION_NET_DIRECTORY = 0x301, + OPTION_SUBDIR, + OPTION_DEBUG, + OPTION_DEBUG_IMAGE + }; + +static struct argp_option options[] = { + GRUB_INSTALL_OPTIONS, + {"net-directory", OPTION_NET_DIRECTORY, N_("DIR"), + 0, N_("root directory of TFTP server"), 2}, + {"subdir", OPTION_SUBDIR, N_("DIR"), + 0, N_("relative subdirectory on network server"), 2}, + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, + {0, 0, 0, 0, 0, 0} +}; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + if (grub_install_parse (key, arg)) + return 0; + switch (key) + { + case OPTION_NET_DIRECTORY: + free (rootdir); + rootdir = xstrdup (arg); + return 0; + case OPTION_SUBDIR: + free (subdir); + subdir = xstrdup (arg); + return 0; + /* This is an undocumented feature... */ + case OPTION_DEBUG: + verbosity++; + return 0; + case OPTION_DEBUG_IMAGE: + free (debug_image); + debug_image = xstrdup (arg); + return 0; + + case ARGP_KEY_ARG: + default: + return ARGP_ERR_UNKNOWN; + } +} + + +struct argp argp = { + options, argp_parser, NULL, + "\v"N_("Prepares GRUB network boot images at net_directory/subdir " + "assuming net_directory being TFTP root."), + NULL, grub_install_help_filter, NULL +}; + +static char *base; + +static const struct +{ + const char *mkimage_target; + const char *netmodule; + const char *ext; +} targets[GRUB_INSTALL_PLATFORM_MAX] = + { + [GRUB_INSTALL_PLATFORM_I386_PC] = { "i386-pc-pxe", "pxe", ".0" }, + [GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] = { "sparc64-ieee1275-aout", "ofnet", ".img" }, + [GRUB_INSTALL_PLATFORM_I386_IEEE1275] = { "i386-ieee1275", "ofnet", ".elf" }, + [GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] = { "powerpc-ieee1275", "ofnet", ".elf" }, + [GRUB_INSTALL_PLATFORM_I386_EFI] = { "i386-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_MIPS64EL_EFI] = { "mips64el-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_RISCV32_EFI] = { "riscv32-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_RISCV64_EFI] = { "riscv64-efi", "efinet", ".efi" }, + }; + +static void +process_input_dir (const char *input_dir, enum grub_install_plat platform) +{ + char *platsub = grub_install_get_platform_name (platform); + char *grubdir = grub_util_path_concat (3, rootdir, subdir, platsub); + char *load_cfg = grub_util_path_concat (2, grubdir, "load.cfg"); + char *prefix; + char *output; + char *grub_cfg; + FILE *cfg; + + grub_install_copy_files (input_dir, base, platform); + grub_util_unlink (load_cfg); + + if (debug_image) + { + FILE *f = grub_util_fopen (load_cfg, "wb"); + if (!f) + grub_util_error (_("cannot open `%s': %s"), load_cfg, + strerror (errno)); + fprintf (f, "set debug='%s'\n", debug_image); + fclose (f); + } + else + { + free (load_cfg); + load_cfg = 0; + } + + prefix = xasprintf ("/%s", subdir); + if (!targets[platform].mkimage_target) + grub_util_error (_("unsupported platform %s"), platsub); + + grub_cfg = grub_util_path_concat (2, grubdir, "grub.cfg"); + cfg = grub_util_fopen (grub_cfg, "wb"); + if (!cfg) + grub_util_error (_("cannot open `%s': %s"), grub_cfg, + strerror (errno)); + fprintf (cfg, "source %s/grub.cfg", subdir); + fclose (cfg); + + grub_install_push_module (targets[platform].netmodule); + + output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext); + grub_install_make_image_wrap (input_dir, prefix, output, + 0, load_cfg, + targets[platform].mkimage_target, 0); + grub_install_pop_module (); + + /* TRANSLATORS: First %s is replaced by platform name. Second one by filename. */ + printf (_("Netboot directory for %s created. Configure your DHCP server to point to %s\n"), + platsub, output); + + free (platsub); + free (output); + free (prefix); + free (grub_cfg); + free (grubdir); +} + + +int +main (int argc, char *argv[]) +{ + const char *pkglibdir; + + grub_util_host_init (&argc, &argv); + grub_util_disable_fd_syncs (); + rootdir = xstrdup ("/srv/tftp"); + pkglibdir = grub_util_get_pkglibdir (); + + subdir = grub_util_path_concat (2, GRUB_BOOT_DIR_NAME, GRUB_DIR_NAME); + + argp_parse (&argp, argc, argv, 0, 0, 0); + + base = grub_util_path_concat (2, rootdir, subdir); + /* Create the GRUB directory if it is not present. */ + + grub_install_mkdir_p (base); + + grub_install_push_module ("tftp"); + + if (!grub_install_source_directory) + { + enum grub_install_plat plat; + + for (plat = 0; plat < GRUB_INSTALL_PLATFORM_MAX; plat++) + if (targets[plat].mkimage_target) + { + char *platdir = grub_util_path_concat (2, pkglibdir, + grub_install_get_platform_name (plat)); + + grub_util_info ("Looking for `%s'", platdir); + + if (!grub_util_is_directory (platdir)) + { + free (platdir); + continue; + } + process_input_dir (platdir, plat); + } + } + else + { + enum grub_install_plat plat; + plat = grub_install_get_target (grub_install_source_directory); + process_input_dir (grub_install_source_directory, plat); + } + return 0; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mkrescue.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mkrescue.c new file mode 100644 index 0000000..aace527 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-mkrescue.c @@ -0,0 +1,1003 @@ +/* + * Make GRUB rescue image + * + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#include +#pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wmissing-declarations" + +#include +#include + +#include +#include + +static char *source_dirs[GRUB_INSTALL_PLATFORM_MAX]; +static char *rom_directory; +static char *label_font; +static char *label_color; +static char *label_bgcolor; +static char *product_name; +static char *product_version; +static char *output_image; +static char *xorriso; +static char *boot_grub; +static int xorriso_argc; +static int xorriso_arg_alloc; +static char **xorriso_argv; +static char *iso_uuid; +static char *iso9660_dir; + +static void +xorriso_push (const char *val) +{ + if (xorriso_arg_alloc <= xorriso_argc + 1) + { + xorriso_arg_alloc = 2 * (4 + xorriso_argc); + xorriso_argv = xrealloc (xorriso_argv, + sizeof (xorriso_argv[0]) + * xorriso_arg_alloc); + } + xorriso_argv[xorriso_argc++] = xstrdup (val); +} + +static void +xorriso_link (const char *from, const char *to) +{ + char *tof = grub_util_path_concat (2, iso9660_dir, to); + char *val = xasprintf ("%s=%s", from, tof); + xorriso_push (val); + free (val); + free (tof); +} + +enum + { + OPTION_OUTPUT = 'o', + OPTION_ROM_DIRECTORY = 0x301, + OPTION_XORRISO, + OPTION_GLUE_EFI, + OPTION_RENDER_LABEL, + OPTION_LABEL_FONT, + OPTION_LABEL_COLOR, + OPTION_LABEL_BGCOLOR, + OPTION_PRODUCT_NAME, + OPTION_PRODUCT_VERSION, + OPTION_SPARC_BOOT, + OPTION_ARCS_BOOT + }; + +static struct argp_option options[] = { + GRUB_INSTALL_OPTIONS, + {"output", 'o', N_("FILE"), + 0, N_("save output in FILE [required]"), 2}, + {"rom-directory", OPTION_ROM_DIRECTORY, N_("DIR"), + 0, N_("save ROM images in DIR [optional]"), 2}, + {"xorriso", OPTION_XORRISO, N_("FILE"), + /* TRANSLATORS: xorriso is a program for creating ISOs and burning CDs. */ + 0, N_("use FILE as xorriso [optional]"), 2}, + {"grub-glue-efi", OPTION_GLUE_EFI, N_("FILE"), OPTION_HIDDEN, 0, 2}, + {"grub-render-label", OPTION_RENDER_LABEL, N_("FILE"), OPTION_HIDDEN, 0, 2}, + {"label-font", OPTION_LABEL_FONT, N_("FILE"), 0, N_("use FILE as font for label"), 2}, + {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2}, + {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2}, + {"product-name", OPTION_PRODUCT_NAME, N_("STRING"), 0, N_("use STRING as product name"), 2}, + {"product-version", OPTION_PRODUCT_VERSION, N_("STRING"), 0, N_("use STRING as product version"), 2}, + {"sparc-boot", OPTION_SPARC_BOOT, 0, 0, N_("enable sparc boot. Disables HFS+, APM, ARCS and boot as disk image for i386-pc"), 2}, + {"arcs-boot", OPTION_ARCS_BOOT, 0, 0, N_("enable ARCS (big-endian mips machines, mostly SGI) boot. Disables HFS+, APM, sparc64 and boot as disk image for i386-pc"), 2}, + {0, 0, 0, 0, 0, 0} +}; + +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + +static char * +help_filter (int key, const char *text, void *input __attribute__ ((unused))) +{ + switch (key) + { + case ARGP_KEY_HELP_PRE_DOC: + /* TRANSLATORS: it generates one single image which is bootable through any method. */ + return strdup (_("Make GRUB CD-ROM, disk, pendrive and floppy bootable image.")); + case ARGP_KEY_HELP_POST_DOC: + { + char *p1, *out; + + p1 = xasprintf (_("Generates a bootable CD/USB/floppy image. Arguments other than options to this program" + " are passed to xorriso, and indicate source files, source directories, or any of the " + "mkisofs options listed by the output of `%s'."), "xorriso -as mkisofs -help"); + out = xasprintf ("%s\n\n%s\n\n%s", p1, + _("Option -- switches to native xorriso command mode."), + _("Mail xorriso support requests to .")); + free (p1); + return out; + } + default: + return grub_install_help_filter (key, text, input); + } +} + +#pragma GCC diagnostic error "-Wformat-nonliteral" + +enum { + SYS_AREA_AUTO, + SYS_AREA_COMMON, + SYS_AREA_SPARC, + SYS_AREA_ARCS +} system_area = SYS_AREA_AUTO; + +static error_t +argp_parser (int key, char *arg, struct argp_state *state) +{ + if (grub_install_parse (key, arg)) + return 0; + switch (key) + { + case OPTION_OUTPUT: + free (output_image); + output_image = xstrdup (arg); + return 0; + case OPTION_ROM_DIRECTORY: + free (rom_directory); + rom_directory = xstrdup (arg); + return 0; + + /* + FIXME: + # Intentionally undocumented + --grub-mkimage-extra) + mkimage_extra_arg="$mkimage_extra_arg `argument $option "$@"`"; shift ;; + --grub-mkimage-extra=*) + mkimage_extra_arg="$mkimage_extra_arg `echo "$option" | sed 's/--grub-mkimage-extra=//'`" ;; + */ + case OPTION_SPARC_BOOT: + system_area = SYS_AREA_SPARC; + return 0; + case OPTION_ARCS_BOOT: + system_area = SYS_AREA_ARCS; + return 0; + case OPTION_PRODUCT_NAME: + free (product_name); + product_name = xstrdup (arg); + return 0; + case OPTION_PRODUCT_VERSION: + free (product_version); + product_version = xstrdup (arg); + return 0; + /* Accept and ignore for compatibility. */ + case OPTION_GLUE_EFI: + case OPTION_RENDER_LABEL: + return 0; + case OPTION_LABEL_FONT: + free (label_font); + label_font = xstrdup (arg); + return 0; + + case OPTION_LABEL_COLOR: + free (label_color); + label_color = xstrdup (arg); + return 0; + + case OPTION_LABEL_BGCOLOR: + free (label_bgcolor); + label_bgcolor = xstrdup (arg); + return 0; + + case OPTION_XORRISO: + free (xorriso); + xorriso = xstrdup (arg); + return 0; + + default: + return ARGP_ERR_UNKNOWN; + } +} + +struct argp argp = { + options, argp_parser, N_("[OPTION] SOURCE..."), + NULL, NULL, help_filter, NULL +}; + +static void +write_part (FILE *f, const char *srcdir) +{ + FILE *in; + char *inname = grub_util_path_concat (2, srcdir, "partmap.lst"); + char buf[260]; + in = grub_util_fopen (inname, "rb"); + if (!in) + return; + while (fgets (buf, 256, in)) + { + char *ptr; + for (ptr = buf + strlen (buf) - 1; + ptr >= buf && (*ptr == '\n' || *ptr == '\r'); + ptr--); + ptr[1] = '\0'; + fprintf (f, "insmod %s\n", buf); + } + fclose (in); +} + +static void +make_image_abs (enum grub_install_plat plat, + const char *mkimage_target, + const char *output) +{ + char *load_cfg; + FILE *load_cfg_f; + + if (!source_dirs[plat]) + return; + + grub_util_info (N_("enabling %s support ..."), + mkimage_target); + + load_cfg = grub_util_make_temporary_file (); + + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + fprintf (load_cfg_f, "search --fs-uuid --set=root %s\n", iso_uuid); + fprintf (load_cfg_f, "set prefix=(${root})/boot/grub\n"); + + write_part (load_cfg_f, source_dirs[plat]); + fclose (load_cfg_f); + + grub_install_push_module ("search"); + grub_install_push_module ("iso9660"); + grub_install_make_image_wrap (source_dirs[plat], "/boot/grub", output, + 0, load_cfg, + mkimage_target, 0); + grub_install_pop_module (); + grub_install_pop_module (); + grub_util_unlink (load_cfg); +} + +static void +make_image (enum grub_install_plat plat, + const char *mkimage_target, + const char *output_sub) +{ + char *out = grub_util_path_concat (2, boot_grub, output_sub); + make_image_abs (plat, mkimage_target, out); + free (out); +} + +static void +make_image_fwdisk_abs (enum grub_install_plat plat, + const char *mkimage_target, + const char *output) +{ + char *load_cfg; + FILE *load_cfg_f; + + if (!source_dirs[plat]) + return; + + grub_util_info (N_("enabling %s support ..."), + mkimage_target); + + load_cfg = grub_util_make_temporary_file (); + + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + write_part (load_cfg_f, source_dirs[plat]); + fclose (load_cfg_f); + + grub_install_push_module ("iso9660"); + grub_install_make_image_wrap (source_dirs[plat], "()/boot/grub", output, + 0, load_cfg, mkimage_target, 0); + grub_install_pop_module (); + grub_util_unlink (load_cfg); +} + +static int +check_xorriso (const char *val) +{ + const char *argv[5]; + int fd; + pid_t pid; + FILE *mdadm; + char *buf = NULL; + size_t len = 0; + int ret = 0; + int wstatus = 0; + + argv[0] = xorriso; + argv[1] = "-as"; + argv[2] = "mkisofs"; + argv[3] = "-help"; + argv[4] = NULL; + + pid = grub_util_exec_pipe_stderr (argv, &fd); + + if (!pid) + return 0; + + /* Parent. Read mdadm's output. */ + mdadm = fdopen (fd, "r"); + if (! mdadm) + return 0; + + while (getline (&buf, &len, mdadm) > 0) + { + if (grub_strstr (buf, val)) + ret = 1; + } + + close (fd); + waitpid (pid, &wstatus, 0); + free (buf); + if (!WIFEXITED (wstatus) || WEXITSTATUS(wstatus) != 0) + return 0; + return ret; +} + +static void +make_image_fwdisk (enum grub_install_plat plat, + const char *mkimage_target, + const char *output_sub) +{ + char *out = grub_util_path_concat (2, boot_grub, output_sub); + make_image_fwdisk_abs (plat, mkimage_target, out); + free (out); +} + +static int +option_is_end (const struct argp_option *opt) +{ + return !opt->key && !opt->name && !opt->doc && !opt->group; +} + + +static int +args_to_eat (const char *arg) +{ + int j; + + if (arg[0] != '-') + return 0; + + if (arg[1] == '-') + { + for (j = 0; !option_is_end(&options[j]); j++) + { + size_t len = strlen (options[j].name); + if (strncmp (arg + 2, options[j].name, len) == 0) + { + if (arg[2 + len] == '=') + return 1; + if (arg[2 + len] == '\0' && options[j].arg) + return 2; + if (arg[2 + len] == '\0') + return 1; + } + } + if (strcmp (arg, "--help") == 0) + return 1; + if (strcmp (arg, "--usage") == 0) + return 1; + if (strcmp (arg, "--version") == 0) + return 1; + return 0; + } + if (arg[2] && arg[3]) + return 0; + for (j = 0; !option_is_end(&options[j]); j++) + { + if (options[j].key > 0 && options[j].key < 128 && arg[1] == options[j].key) + { + if (options[j].arg) + return 2; + return 1; + } + if (arg[1] == '?') + return 1; + } + return 0; +} + +int +main (int argc, char *argv[]) +{ + char *romdir; + char *sysarea_img = NULL; + const char *pkgdatadir; + int argp_argc; + char **argp_argv; + int xorriso_tail_argc; + char **xorriso_tail_argv; + int rv; + + grub_util_host_init (&argc, &argv); + grub_util_disable_fd_syncs (); + + pkgdatadir = grub_util_get_pkgdatadir (); + + product_name = xstrdup (PACKAGE_NAME); + product_version = xstrdup (PACKAGE_VERSION); + xorriso = xstrdup ("xorriso"); + label_font = grub_util_path_concat (2, pkgdatadir, "unicode.pf2"); + + argp_argv = xmalloc (sizeof (argp_argv[0]) * argc); + xorriso_tail_argv = xmalloc (sizeof (argp_argv[0]) * argc); + + xorriso_tail_argc = 0; + /* Program name */ + argp_argv[0] = argv[0]; + argp_argc = 1; + + /* argp doesn't allow us to catch unknwon arguments, + so catch them before passing to argp + */ + { + int i; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-output") == 0) { + argp_argv[argp_argc++] = (char *) "--output"; + i++; + argp_argv[argp_argc++] = argv[i]; + continue; + } + switch (args_to_eat (argv[i])) + { + case 2: + argp_argv[argp_argc++] = argv[i++]; + /* Fallthrough */ + case 1: + argp_argv[argp_argc++] = argv[i]; + break; + case 0: + xorriso_tail_argv[xorriso_tail_argc++] = argv[i]; + break; + } + } + } + + argp_parse (&argp, argp_argc, argp_argv, 0, 0, 0); + + if (!output_image) + grub_util_error ("%s", _("output file must be specified")); + + if (!check_xorriso ("graft-points")) { + grub_util_error ("%s", _("xorriso not found")); + } + + grub_init_all (); + grub_hostfs_init (); + grub_host_init (); + + xorriso_push (xorriso); + xorriso_push ("-as"); + xorriso_push ("mkisofs"); + xorriso_push ("-graft-points"); + + iso9660_dir = grub_util_make_temporary_dir (); + grub_util_info ("temporary iso9660 dir is `%s'", iso9660_dir); + boot_grub = grub_util_path_concat (3, iso9660_dir, "boot", "grub"); + grub_install_mkdir_p (boot_grub); + romdir = grub_util_path_concat (2, boot_grub, "roms"); + grub_util_mkdir (romdir); + + if (!grub_install_source_directory) + { + const char *pkglibdir = grub_util_get_pkglibdir (); + enum grub_install_plat plat; + + for (plat = 0; plat < GRUB_INSTALL_PLATFORM_MAX; plat++) + { + char *platdir = grub_util_path_concat (2, pkglibdir, + grub_install_get_platform_name (plat)); + + if (!grub_util_is_directory (platdir)) + { + free (platdir); + continue; + } + source_dirs[plat] = platdir; + grub_install_copy_files (platdir, + boot_grub, plat); + } + } + else + { + enum grub_install_plat plat; + plat = grub_install_get_target (grub_install_source_directory); + grub_install_copy_files (grub_install_source_directory, + boot_grub, plat); + source_dirs[plat] = xstrdup (grub_install_source_directory); + } + if (system_area == SYS_AREA_AUTO || grub_install_source_directory) + { + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC] + || source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] + || source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_IA64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_ARM_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_ARM64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_MIPS64EL_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_RISCV32_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_RISCV64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + system_area = SYS_AREA_COMMON; + else if (source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275]) + system_area = SYS_AREA_SPARC; + else if (source_dirs[GRUB_INSTALL_PLATFORM_MIPS_ARC]) + system_area = SYS_AREA_ARCS; + } + + /* obtain date-based UUID. */ + { + time_t tim; + struct tm *tmm; + tim = time (NULL); + tmm = gmtime (&tim); + iso_uuid = xmalloc (55); + grub_snprintf (iso_uuid, 50, + "%04d-%02d-%02d-%02d-%02d-%02d-00", + tmm->tm_year + 1900, + tmm->tm_mon + 1, + tmm->tm_mday, + tmm->tm_hour, + tmm->tm_min, + tmm->tm_sec); + } + { + char *uuid_out = xmalloc (strlen (iso_uuid) + 1 + 40); + char *optr; + const char *iptr; + optr = grub_stpcpy (uuid_out, "--modification-date="); + for (iptr = iso_uuid; *iptr; iptr++) + if (*iptr != '-') + *optr++ = *iptr; + *optr = '\0'; + xorriso_push (uuid_out); + free (uuid_out); + } + + /* build BIOS core.img. */ + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC]) + { + char *load_cfg; + FILE *load_cfg_f; + char *output = grub_util_path_concat (3, boot_grub, "i386-pc", "eltorito.img"); + load_cfg = grub_util_make_temporary_file (); + + grub_util_info (N_("enabling %s support ..."), "BIOS"); + load_cfg_f = grub_util_fopen (load_cfg, "wb"); + write_part (load_cfg_f, source_dirs[GRUB_INSTALL_PLATFORM_I386_PC]); + fclose (load_cfg_f); + + grub_install_push_module ("biosdisk"); + grub_install_push_module ("iso9660"); + grub_install_make_image_wrap (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC], + "/boot/grub", output, + 0, load_cfg, + "i386-pc-eltorito", 0); + + xorriso_push ("-b"); + xorriso_push ("boot/grub/i386-pc/eltorito.img"); + xorriso_push ("-no-emul-boot"); + xorriso_push ("-boot-load-size"); + xorriso_push ("4"); + xorriso_push ("-boot-info-table"); + if (system_area == SYS_AREA_COMMON) + { + if (check_xorriso ("grub2-boot-info")) + { + char *boot_hybrid = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_I386_PC], + "boot_hybrid.img"); + xorriso_push ("--grub2-boot-info"); + xorriso_push ("--grub2-mbr"); + xorriso_push (boot_hybrid); + } + else + { + FILE *sa, *bi; + size_t sz; + char buf[512]; + char *bin = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_I386_PC], + "boot.img"); + grub_util_warn ("%s", _("Your xorriso doesn't support `--grub2-boot-info'. Some features are disabled. Please use xorriso 1.2.9 or later.")); + sysarea_img = grub_util_make_temporary_file (); + sa = grub_util_fopen (sysarea_img, "wb"); + if (!sa) + grub_util_error (_("cannot open `%s': %s"), sysarea_img, + strerror (errno)); + bi = grub_util_fopen (bin, "rb"); + if (!bi) + grub_util_error (_("cannot open `%s': %s"), bin, + strerror (errno)); + if (fread (buf, 1, 512, bi) != 512) + grub_util_error (_("cannot read `%s': %s"), bin, + strerror (errno)); + fclose (bi); + fwrite (buf, 1, 512, sa); + + grub_install_make_image_wrap_file (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC], + "/boot/grub", sa, sysarea_img, + 0, load_cfg, + "i386-pc", 0); + sz = ftello (sa); + fflush (sa); + grub_util_fd_sync (fileno (sa)); + fclose (sa); + + if (sz > 32768) + { + grub_util_warn ("%s", _("Your xorriso doesn't support `--grub2-boot-info'. Your core image is too big. Boot as disk is disabled. Please use xorriso 1.2.9 or later.")); + } + else + { + xorriso_push ("-G"); + xorriso_push (sysarea_img); + } + } + } + grub_install_pop_module (); + grub_install_pop_module (); + grub_util_unlink (load_cfg); + } + + /** build multiboot core.img */ + grub_install_push_module ("pata"); + grub_install_push_module ("ahci"); + grub_install_push_module ("at_keyboard"); + make_image (GRUB_INSTALL_PLATFORM_I386_MULTIBOOT, "i386-multiboot", "i386-multiboot/core.elf"); + grub_install_pop_module (); + grub_install_pop_module (); + grub_install_pop_module (); + + make_image_fwdisk (GRUB_INSTALL_PLATFORM_I386_IEEE1275, "i386-ieee1275", "ofwx86.elf"); + + char *core_services = NULL; + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275]) + { + char *mach_ker, *sv, *label, *label_text; + FILE *f; + core_services = grub_util_path_concat (4, iso9660_dir, "System", "Library", "CoreServices"); + grub_install_mkdir_p (core_services); + + mach_ker = grub_util_path_concat (2, iso9660_dir, "mach_kernel"); + f = grub_util_fopen (mach_ker, "wb"); + fclose (f); + free (mach_ker); + + sv = grub_util_path_concat (2, core_services, "SystemVersion.plist"); + f = grub_util_fopen (sv, "wb"); + fprintf (f, "\n" + "\n" + " ProductBuildVersion\n" + " \n" + " ProductName\n" + " %s\n" + " ProductVersion\n" + " %s\n" + "\n" + "\n", product_name, product_version); + fclose (f); + free (sv); + label = grub_util_path_concat (2, core_services, ".disk_label"); + char *label_string = xasprintf ("%s %s", product_name, product_version); + grub_util_render_label (label_font, label_bgcolor ? : "white", + label_color ? : "black", label_string, label); + free (label); + label_text = grub_util_path_concat (2, core_services, ".disk_label.contentDetails"); + f = grub_util_fopen (label_text, "wb"); + fprintf (f, "%s\n", label_string); + fclose (f); + free (label_string); + free (label_text); + if (system_area == SYS_AREA_COMMON) + { + xorriso_push ("-hfsplus"); + xorriso_push ("-apm-block-size"); + xorriso_push ("2048"); + xorriso_push ("-hfsplus-file-creator-type"); + xorriso_push ("chrp"); + xorriso_push ("tbxj"); + xorriso_push ("/System/Library/CoreServices/.disk_label"); + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + { + xorriso_push ("-hfs-bless-by"); + xorriso_push ("i"); + xorriso_push ("/System/Library/CoreServices/boot.efi"); + } + } + } + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_IA64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_ARM_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_ARM64_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_MIPS64EL_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_RISCV32_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_RISCV64_EFI]) + { + char *efidir = grub_util_make_temporary_dir (); + char *efidir_efi = grub_util_path_concat (2, efidir, "efi"); + char *efidir_efi_boot = grub_util_path_concat (3, efidir, "efi", "boot"); + char *imgname, *img32, *img64, *img_mac = NULL; + char *efiimgfat; + grub_install_mkdir_p (efidir_efi_boot); + + grub_install_push_module ("part_gpt"); + grub_install_push_module ("part_msdos"); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootia64.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_IA64_EFI, "ia64-efi", imgname); + free (imgname); + + grub_install_push_module ("part_apple"); + img64 = grub_util_path_concat (2, efidir_efi_boot, "bootx64.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_X86_64_EFI, "x86_64-efi", img64); + grub_install_pop_module (); + + grub_install_push_module ("part_apple"); + img32 = grub_util_path_concat (2, efidir_efi_boot, "bootia32.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_I386_EFI, "i386-efi", img32); + grub_install_pop_module (); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootarm.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_ARM_EFI, "arm-efi", imgname); + free (imgname); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootaa64.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_ARM64_EFI, "arm64-efi", + imgname); + free (imgname); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootmips64el.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_MIPS64EL_EFI, "mips64el-efi", + imgname); + free (imgname); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootriscv32.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_RISCV32_EFI, "riscv32-efi", + imgname); + free (imgname); + + imgname = grub_util_path_concat (2, efidir_efi_boot, "bootriscv64.efi"); + make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_RISCV64_EFI, "riscv64-efi", + imgname); + free (imgname); + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]) + { + imgname = grub_util_path_concat (2, efidir_efi_boot, "boot.efi"); + /* For old macs. Suggested by Peter Jones. */ + grub_install_copy_file (img32, imgname, 1); + } + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + img_mac = grub_util_path_concat (2, core_services, "boot.efi"); + + if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI] + && source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + grub_util_glue_efi (img32, img64, img_mac); + else if (source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]) + grub_install_copy_file (img64, img_mac, 1); + else if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]) + grub_install_copy_file (img32, img_mac, 1); + + free (img_mac); + free (img32); + free (img64); + free (efidir_efi_boot); + + efiimgfat = grub_util_path_concat (2, iso9660_dir, "efi.img"); + rv = grub_util_exec ((const char * []) { "mformat", "-C", "-f", "2880", "-L", "16", "-i", + efiimgfat, "::", NULL }); + if (rv != 0) + grub_util_error ("`%s` invocation failed\n", "mformat"); + rv = grub_util_exec ((const char * []) { "mcopy", "-s", "-i", efiimgfat, efidir_efi, "::/", NULL }); + if (rv != 0) + grub_util_error ("`%s` invocation failed\n", "mcopy"); + xorriso_push ("--efi-boot"); + xorriso_push ("efi.img"); + xorriso_push ("-efi-boot-part"); + xorriso_push ("--efi-boot-image"); + + grub_util_unlink_recursive (efidir); + free (efiimgfat); + free (efidir_efi); + free (efidir); + grub_install_pop_module (); + grub_install_pop_module (); + } + + grub_install_push_module ("part_apple"); + make_image_fwdisk (GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275, "powerpc-ieee1275", "powerpc-ieee1275/core.elf"); + grub_install_pop_module (); + + if (source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275]) + { + char *grub_chrp = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275], + "grub.chrp"); + char *bisrc = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275], + "bootinfo.txt"); + char *bootx = grub_util_path_concat (2, core_services, "BootX"); + char *ppc_chrp = grub_util_path_concat (3, iso9660_dir, "ppc", "chrp"); + char *bitgt = grub_util_path_concat (3, iso9660_dir, "ppc", "bootinfo.txt"); + grub_install_copy_file (grub_chrp, bootx, 1); + grub_install_mkdir_p (ppc_chrp); + grub_install_copy_file (bisrc, bitgt, 1); + xorriso_link ("/System/Library/CoreServices/grub.elf", "/boot/grub/powerpc-ieee1275/core.elf"); + xorriso_link ("/boot/grub/powerpc.elf", "/boot/grub/powerpc-ieee1275/core.elf"); + /* FIXME: add PreP */ + if (system_area == SYS_AREA_COMMON) + { + xorriso_push ("-hfsplus-file-creator-type"); + xorriso_push ("chrp"); + xorriso_push ("tbxi"); + xorriso_push ("/System/Library/CoreServices/BootX"); + xorriso_push ("-hfs-bless-by"); + xorriso_push ("p"); + xorriso_push ("/System/Library/CoreServices"); + } + xorriso_push ("-sysid"); + xorriso_push ("PPC"); + } + + make_image_fwdisk (GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275, + "sparc64-ieee1275-cdcore", "sparc64-ieee1275/core.img"); + + if (source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] + && system_area == SYS_AREA_SPARC) + { + char *cdboot; + FILE *in, *out; + char buf[512]; + sysarea_img = grub_util_make_temporary_file (); + cdboot = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275], + "cdboot.img"); + in = grub_util_fopen (cdboot, "rb"); + if (!in) + grub_util_error (_("cannot open `%s': %s"), cdboot, + strerror (errno)); + out = grub_util_fopen (sysarea_img, "wb"); + if (!out) + grub_util_error (_("cannot open `%s': %s"), sysarea_img, + strerror (errno)); + memset (buf, 0, 512); + fwrite (buf, 1, 512, out); + if (fread (buf, 1, 512, in) != 512) + grub_util_error (_("cannot read `%s': %s"), cdboot, + strerror (errno)); + fwrite (buf, 1, 512, out); + fclose (in); + fclose (out); + xorriso_push ("-G"); + xorriso_push (sysarea_img); + xorriso_push ("-B"); + xorriso_push (","); + xorriso_push ("--grub2-sparc-core"); + xorriso_push ("/boot/grub/sparc64-ieee1275/core.img"); + } + + make_image_fwdisk (GRUB_INSTALL_PLATFORM_MIPS_ARC, "mips-arc", "mips-arc/core.img"); + + if (source_dirs[GRUB_INSTALL_PLATFORM_MIPS_ARC]) + { + xorriso_link ("/boot/grub/mips-arc/grub", "/boot/grub/mips-arc/core.img"); + xorriso_link ("/boot/grub/mips-arc/sashARCS", "/boot/grub/mips-arc/core.img"); + xorriso_link ("/boot/grub/mips-arc/sash", "/boot/grub/mips-arc/core.img"); + } + if (source_dirs[GRUB_INSTALL_PLATFORM_MIPS_ARC] && system_area == SYS_AREA_ARCS) + { + xorriso_push ("-mips-boot"); + xorriso_push ("/boot/grub/mips-arc/sashARCS"); + xorriso_push ("-mips-boot"); + xorriso_push ("/boot/grub/mips-arc/sash"); + xorriso_push ("-mips-boot"); + xorriso_push ("/boot/grub/mips-arc/grub"); + } + + make_image_fwdisk (GRUB_INSTALL_PLATFORM_MIPSEL_ARC, "mipsel-arc", "arc.exe"); + + grub_install_push_module ("pata"); + make_image (GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS, "mipsel-qemu_mips-elf", "roms/mipsel-qemu_mips.elf"); + + make_image (GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "mipsel-loongson-elf", "loongson.elf"); + + make_image (GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "mipsel-yeeloong-flash", "mipsel-yeeloong.bin"); + make_image (GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "mipsel-fuloong2f-flash", "mipsel-fuloong2f.bin"); + + make_image (GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS, "mips-qemu_mips-elf", "roms/mips-qemu_mips.elf"); + + grub_install_push_module ("at_keyboard"); + + make_image (GRUB_INSTALL_PLATFORM_I386_QEMU, "i386-qemu", "roms/qemu.img"); + + grub_install_push_module ("ahci"); + + make_image (GRUB_INSTALL_PLATFORM_I386_COREBOOT, "i386-coreboot", "roms/coreboot.elf"); + grub_install_pop_module (); + grub_install_pop_module (); + grub_install_pop_module (); + + if (rom_directory) + { + const struct + { + enum grub_install_plat plat; + const char *from, *to; + } roms[] = + { + {GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS, "roms/mipsel-qemu_mips.elf", "mipsel-qemu_mips.elf"}, + {GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "loongson.elf", "mipsel-loongson.elf"}, + {GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "roms/mipsel-yeeloong.bin", "mipsel-yeeloong.bin"}, + {GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "roms/mipsel-fulong.bin", "mipsel-fulong.bin"}, + {GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS, "roms/mips-qemu_mips.elf", "mips-qemu_mips.elf"}, + {GRUB_INSTALL_PLATFORM_I386_QEMU, "roms/qemu.img", "qemu.img"}, + {GRUB_INSTALL_PLATFORM_I386_COREBOOT, "roms/coreboot.elf", "coreboot.elf"}, + }; + grub_size_t i; + for (i = 0; i < ARRAY_SIZE (roms); i++) + { + char *from = grub_util_path_concat (2, boot_grub, roms[i].from); + char *to = grub_util_path_concat (2, rom_directory, roms[i].to); + grub_install_copy_file (from, to, 0); + } + } + + xorriso_push ("--protective-msdos-label"); + xorriso_push ("-o"); + xorriso_push (output_image); + xorriso_push ("-r"); + xorriso_push (iso9660_dir); + xorriso_push ("--sort-weight"); + xorriso_push ("0"); + xorriso_push ("/"); + xorriso_push ("--sort-weight"); + xorriso_push ("1"); + xorriso_push ("/boot"); + int i; + for (i = 0; i < xorriso_tail_argc; i++) + xorriso_push (xorriso_tail_argv[i]); + + xorriso_argv[xorriso_argc] = NULL; + + rv = grub_util_exec ((const char *const *)xorriso_argv); + if (rv != 0) + grub_util_error ("`%s` invocation failed\n", "xorriso"); + + grub_util_unlink_recursive (iso9660_dir); + + if (sysarea_img) + grub_util_unlink (sysarea_img); + + free (core_services); + free (romdir); + return 0; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-module-verifier.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-module-verifier.c new file mode 100644 index 0000000..0075a1f --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-module-verifier.c @@ -0,0 +1,247 @@ +#include +#include + +#include +#include +#include +#include + +struct grub_module_verifier_arch archs[] = { + { "i386", 4, 0, EM_386, GRUB_MODULE_VERIFY_SUPPORTS_REL, (int[]){ + R_386_32, + R_386_PC32, + -1 + } }, + { "x86_64", 8, 0, EM_X86_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_X86_64_64, + R_X86_64_PC64, + /* R_X86_64_32, R_X86_64_32S are supported but shouldn't be used because of their limited range. */ + -1 + }, (int[]){ + R_X86_64_PC32, + R_X86_64_PLT32, + -1 + } + }, + { "powerpc", 4, 1, EM_PPC, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + GRUB_ELF_R_PPC_ADDR16_LO, + GRUB_ELF_R_PPC_REL24, /* It has limited range but GRUB adds trampolines when necessarry. */ + GRUB_ELF_R_PPC_ADDR16_HA, + GRUB_ELF_R_PPC_ADDR32, + GRUB_ELF_R_PPC_REL32, + GRUB_ELF_R_PPC_PLTREL24, + -1 + } }, + { "sparc64", 8, 1, EM_SPARCV9, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_SPARC_WDISP30, /* It has limited range but GRUB adds trampolines when necessarry. */ + R_SPARC_HH22, + R_SPARC_HM10, + R_SPARC_LM22, + R_SPARC_LO10, + R_SPARC_64, + R_SPARC_OLO10, + /* Following 2 relocations have limited range but unfortunately + clang generates them, as it doesn't implement mcmodel=large properly. + At least our heap and core are under 4G, so it's not a problem + usually. */ + R_SPARC_HI22, + R_SPARC_32, + -1 + } }, + { "ia64", 8, 0, EM_IA_64, GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_IA64_PCREL21B, /* We should verify that it's pointing either + to a function or to a section in the same module. + Checking that external symbol is a function is + non-trivial and I have never seen this relocation used + for anything else, so assume that it always points to a + function. + */ + R_IA64_SEGREL64LSB, + R_IA64_FPTR64LSB, + R_IA64_DIR64LSB, + R_IA64_PCREL64LSB, + R_IA64_LTOFF22X, + R_IA64_LTOFF22, + R_IA64_GPREL64I, + R_IA64_LTOFF_FPTR22, + R_IA64_LDXMOV, + -1 + }, (int[]){ + R_IA64_GPREL22, + -1 + } }, + { "mipsel", 4, 0, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_MIPS_HI16, + R_MIPS_LO16, + R_MIPS_32, + R_MIPS_GPREL32, + R_MIPS_26, + R_MIPS_GOT16, + R_MIPS_CALL16, + R_MIPS_JALR, + -1 + } }, + { "mips", 4, 1, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_MIPS_HI16, + R_MIPS_LO16, + R_MIPS_32, + R_MIPS_GPREL32, + R_MIPS_26, + R_MIPS_GOT16, + R_MIPS_CALL16, + R_MIPS_JALR, + -1 + } }, + { "arm", 4, 0, EM_ARM, GRUB_MODULE_VERIFY_SUPPORTS_REL, (int[]){ + /* Some relocations are range-limited but trampolines are added when necessarry. */ + R_ARM_ABS32, + R_ARM_CALL, + R_ARM_JUMP24, + R_ARM_THM_CALL, + R_ARM_THM_JUMP24, + R_ARM_V4BX, + R_ARM_THM_MOVW_ABS_NC, + R_ARM_THM_MOVT_ABS, + R_ARM_THM_JUMP19, + -1 + } }, + { "arm64", 8, 0, EM_AARCH64, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_AARCH64_ABS64, + R_AARCH64_CALL26, + R_AARCH64_JUMP26, + R_AARCH64_ADR_GOT_PAGE, + R_AARCH64_LD64_GOT_LO12_NC, + -1 + }, (int[]){ + R_AARCH64_ADR_PREL_PG_HI21, + R_AARCH64_ADD_ABS_LO12_NC, + R_AARCH64_LDST64_ABS_LO12_NC, + R_AARCH64_PREL32, + -1 + } }, + { "mips64el", 8, 0, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_MIPS_64, + R_MIPS_32, + R_MIPS_26, + R_MIPS_LO16, + R_MIPS_HI16, + R_MIPS_HIGHER, + R_MIPS_HIGHEST, + -1 + }, (int[]){ + -1 + } + }, + { "riscv32", 4, 0, EM_RISCV, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_RISCV_32, + R_RISCV_64, + R_RISCV_ADD8, + R_RISCV_ADD16, + R_RISCV_ADD32, + R_RISCV_ADD64, + R_RISCV_SUB8, + R_RISCV_SUB16, + R_RISCV_SUB32, + R_RISCV_SUB64, + R_RISCV_ALIGN, + R_RISCV_BRANCH, + R_RISCV_CALL, + R_RISCV_CALL_PLT, + R_RISCV_GOT_HI20, + R_RISCV_HI20, + R_RISCV_JAL, + R_RISCV_LO12_I, + R_RISCV_LO12_S, + R_RISCV_PCREL_HI20, + R_RISCV_PCREL_LO12_I, + R_RISCV_PCREL_LO12_S, + R_RISCV_RELAX, + R_RISCV_RVC_BRANCH, + R_RISCV_RVC_JUMP, + -1 + } }, + { "riscv64", 8, 0, EM_RISCV, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ + R_RISCV_32, + R_RISCV_64, + R_RISCV_ADD8, + R_RISCV_ADD16, + R_RISCV_ADD32, + R_RISCV_ADD64, + R_RISCV_SUB8, + R_RISCV_SUB16, + R_RISCV_SUB32, + R_RISCV_SUB64, + R_RISCV_ALIGN, + R_RISCV_BRANCH, + R_RISCV_CALL, + R_RISCV_CALL_PLT, + R_RISCV_GOT_HI20, + R_RISCV_HI20, + R_RISCV_JAL, + R_RISCV_LO12_I, + R_RISCV_LO12_S, + R_RISCV_PCREL_HI20, + R_RISCV_PCREL_LO12_I, + R_RISCV_PCREL_LO12_S, + R_RISCV_RELAX, + R_RISCV_RVC_BRANCH, + R_RISCV_RVC_JUMP, + -1 + } + }, +}; + +struct platform_whitelist { + const char *arch; + const char *platform; + const char **whitelist_empty; +}; + +static struct platform_whitelist whitelists[] = { + {"i386", "xen", (const char *[]) {"all_video", 0}}, + {"i386", "xen_pvh", (const char *[]) {"all_video", 0}}, + {"x86_64", "xen", (const char *[]) {"all_video", 0}}, + {"sparc64", "ieee1275", (const char *[]) {"all_video", 0}}, + + /* video is compiled-in on MIPS. */ + {"mipsel", "loongson", (const char *[]) {"all_video", 0}}, + {"mipsel", "qemu_mips", (const char *[]) {"all_video", 0}}, + {"mipsel", "arc", (const char *[]) {"all_video", 0}}, + {"mips", "qemu_mips", (const char *[]) {"all_video", 0}}, + {"mips", "arc", (const char *[]) {"all_video", 0}}, +}; + + +int +main (int argc, char **argv) +{ + size_t module_size; + unsigned arch, whitelist; + const char **whitelist_empty = 0; + char *module_img; + if (argc != 4) { + fprintf (stderr, "usage: %s FILE ARCH PLATFORM\n", argv[0]); + return 1; + } + + for (arch = 0; arch < ARRAY_SIZE(archs); arch++) + if (strcmp(archs[arch].name, argv[2]) == 0) + break; + if (arch == ARRAY_SIZE(archs)) + grub_util_error("%s: unknown arch: %s", argv[1], argv[2]); + + for (whitelist = 0; whitelist < ARRAY_SIZE(whitelists); whitelist++) + if (strcmp(whitelists[whitelist].arch, argv[2]) == 0 + && strcmp(whitelists[whitelist].platform, argv[3]) == 0) + break; + if (whitelist != ARRAY_SIZE(whitelists)) + whitelist_empty = whitelists[whitelist].whitelist_empty; + + module_size = grub_util_get_image_size (argv[1]); + module_img = grub_util_read_image (argv[1]); + if (archs[arch].voidp_sizeof == 8) + grub_module_verify64(argv[1], module_img, module_size, &archs[arch], whitelist_empty); + else + grub_module_verify32(argv[1], module_img, module_size, &archs[arch], whitelist_empty); + return 0; +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-module-verifierXX.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-module-verifierXX.c new file mode 100644 index 0000000..9259ebb --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/grub-module-verifierXX.c @@ -0,0 +1,446 @@ +#include + +#include +#include +#include + +#if defined(MODULEVERIFIER_ELF32) +# define SUFFIX(x) x ## 32 +# define ELFCLASSXX ELFCLASS32 +# define Elf_Ehdr Elf32_Ehdr +# define Elf_Phdr Elf32_Phdr +# define Elf_Nhdr Elf32_Nhdr +# define Elf_Addr Elf32_Addr +# define Elf_Sym Elf32_Sym +# define Elf_Off Elf32_Off +# define Elf_Shdr Elf32_Shdr +# define Elf_Rela Elf32_Rela +# define Elf_Rel Elf32_Rel +# define Elf_Word Elf32_Word +# define Elf_Half Elf32_Half +# define Elf_Section Elf32_Section +# define ELF_R_SYM(val) ELF32_R_SYM(val) +# define ELF_R_TYPE(val) ELF32_R_TYPE(val) +# define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) +#elif defined(MODULEVERIFIER_ELF64) +# define SUFFIX(x) x ## 64 +# define ELFCLASSXX ELFCLASS64 +# define Elf_Ehdr Elf64_Ehdr +# define Elf_Phdr Elf64_Phdr +# define Elf_Nhdr Elf64_Nhdr +# define Elf_Addr Elf64_Addr +# define Elf_Sym Elf64_Sym +# define Elf_Off Elf64_Off +# define Elf_Shdr Elf64_Shdr +# define Elf_Rela Elf64_Rela +# define Elf_Rel Elf64_Rel +# define Elf_Word Elf64_Word +# define Elf_Half Elf64_Half +# define Elf_Section Elf64_Section +# define ELF_R_SYM(val) ELF64_R_SYM(val) +# define ELF_R_TYPE(val) ELF64_R_TYPE(val) +# define ELF_ST_TYPE(val) ELF64_ST_TYPE(val) +#else +#error "I'm confused" +#endif + +#define grub_target_to_host32(x) (grub_target_to_host32_real (arch, (x))) +#define grub_host_to_target32(x) (grub_host_to_target32_real (arch, (x))) +#define grub_target_to_host64(x) (grub_target_to_host64_real (arch, (x))) +#define grub_host_to_target64(x) (grub_host_to_target64_real (arch, (x))) +#define grub_host_to_target_addr(x) (grub_host_to_target_addr_real (arch, (x))) +#define grub_target_to_host16(x) (grub_target_to_host16_real (arch, (x))) +#define grub_host_to_target16(x) (grub_host_to_target16_real (arch, (x))) +#define grub_target_to_host(val) grub_target_to_host_real(arch, (val)) + +static inline grub_uint32_t +grub_target_to_host32_real (const struct grub_module_verifier_arch *arch, + grub_uint32_t in) +{ + if (arch->bigendian) + return grub_be_to_cpu32 (in); + else + return grub_le_to_cpu32 (in); +} + +static inline grub_uint64_t +grub_target_to_host64_real (const struct grub_module_verifier_arch *arch, + grub_uint64_t in) +{ + if (arch->bigendian) + return grub_be_to_cpu64 (in); + else + return grub_le_to_cpu64 (in); +} + +static inline grub_uint64_t +grub_host_to_target64_real (const struct grub_module_verifier_arch *arch, + grub_uint64_t in) +{ + if (arch->bigendian) + return grub_cpu_to_be64 (in); + else + return grub_cpu_to_le64 (in); +} + +static inline grub_uint32_t +grub_host_to_target32_real (const struct grub_module_verifier_arch *arch, + grub_uint32_t in) +{ + if (arch->bigendian) + return grub_cpu_to_be32 (in); + else + return grub_cpu_to_le32 (in); +} + +static inline grub_uint16_t +grub_target_to_host16_real (const struct grub_module_verifier_arch *arch, + grub_uint16_t in) +{ + if (arch->bigendian) + return grub_be_to_cpu16 (in); + else + return grub_le_to_cpu16 (in); +} + +static inline grub_uint16_t +grub_host_to_target16_real (const struct grub_module_verifier_arch *arch, + grub_uint16_t in) +{ + if (arch->bigendian) + return grub_cpu_to_be16 (in); + else + return grub_cpu_to_le16 (in); +} + +static inline grub_uint64_t +grub_host_to_target_addr_real (const struct grub_module_verifier_arch *arch, grub_uint64_t in) +{ + if (arch->voidp_sizeof == 8) + return grub_host_to_target64_real (arch, in); + else + return grub_host_to_target32_real (arch, in); +} + +static inline grub_uint64_t +grub_target_to_host_real (const struct grub_module_verifier_arch *arch, grub_uint64_t in) +{ + if (arch->voidp_sizeof == 8) + return grub_target_to_host64_real (arch, in); + else + return grub_target_to_host32_real (arch, in); +} + + +static Elf_Shdr * +find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const char *name) +{ + Elf_Shdr *s; + const char *str; + unsigned i; + + s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + grub_target_to_host16 (e->e_shstrndx) * grub_target_to_host16 (e->e_shentsize)); + str = (char *) e + grub_target_to_host (s->sh_offset); + + for (i = 0, s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff)); + i < grub_target_to_host16 (e->e_shnum); + i++, s = (Elf_Shdr *) ((char *) s + grub_target_to_host16 (e->e_shentsize))) + if (strcmp (str + grub_target_to_host32 (s->sh_name), name) == 0) + return s; + return NULL; +} + +static void +check_license (const char * const filename, + const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) +{ + Elf_Shdr *s = find_section (arch, e, ".module_license"); + if (s && (strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3") == 0 + || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3+") == 0 + || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv2+") == 0)) + return; + grub_util_error ("%s: incompatible license", filename); +} + +static Elf_Sym * +get_symtab (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, Elf_Word *size, Elf_Word *entsize) +{ + unsigned i; + Elf_Shdr *s, *sections; + Elf_Sym *sym; + + sections = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff)); + for (i = 0, s = sections; + i < grub_target_to_host16 (e->e_shnum); + i++, s = (Elf_Shdr *) ((char *) s + grub_target_to_host16 (e->e_shentsize))) + if (grub_target_to_host32 (s->sh_type) == SHT_SYMTAB) + break; + + if (i == grub_target_to_host16 (e->e_shnum)) + return NULL; + + sym = (Elf_Sym *) ((char *) e + grub_target_to_host (s->sh_offset)); + *size = grub_target_to_host (s->sh_size); + *entsize = grub_target_to_host (s->sh_entsize); + return sym; +} + +static int +is_whitelisted (const char *modname, const char **whitelist) +{ + const char **ptr; + if (!whitelist) + return 0; + if (!modname) + return 0; + for (ptr = whitelist; *ptr; ptr++) + if (strcmp (modname, *ptr) == 0) + return 1; + return 0; +} + +static void +check_symbols (const struct grub_module_verifier_arch *arch, + Elf_Ehdr *e, const char *modname, + const char **whitelist_empty) +{ + Elf_Sym *sym; + Elf_Word size, entsize; + unsigned i; + + /* Module without symbol table and without .moddeps section is useless + at boot time, so catch it early to prevent build errors */ + sym = get_symtab (arch, e, &size, &entsize); + if (!sym) + { + Elf_Shdr *s; + + /* However some modules are dependencies-only, + e.g. insmod all_video pulls in all video drivers. + Some platforms e.g. xen have no video drivers, so + the module does nothing. */ + if (is_whitelisted (modname, whitelist_empty)) + return; + + s = find_section (arch, e, ".moddeps"); + + if (!s) + grub_util_error ("%s: no symbol table and no .moddeps section", modname); + + if (!s->sh_size) + grub_util_error ("%s: no symbol table and empty .moddeps section", modname); + + return; + } + + for (i = 0; + i < size / entsize; + i++, sym = (Elf_Sym *) ((char *) sym + entsize)) + { + unsigned char type = ELF_ST_TYPE (sym->st_info); + + switch (type) + { + case STT_NOTYPE: + case STT_OBJECT: + case STT_FUNC: + case STT_SECTION: + case STT_FILE: + break; + + default: + return grub_util_error ("%s: unknown symbol type `%d'", modname, (int) type); + } + } +} + +static int +is_symbol_local(Elf_Sym *sym) +{ + switch (ELF_ST_TYPE (sym->st_info)) + { + case STT_NOTYPE: + case STT_OBJECT: + if (sym->st_name != 0 && sym->st_shndx == 0) + return 0; + return 1; + + case STT_FUNC: + case STT_SECTION: + return 1; + + default: + return 0; + } +} + +static void +section_check_relocations (const char * const modname, + const struct grub_module_verifier_arch *arch, void *ehdr, + Elf_Shdr *s, size_t target_seg_size) +{ + Elf_Rel *rel, *max; + Elf_Sym *symtab; + Elf_Word symtabsize, symtabentsize; + + symtab = get_symtab (arch, ehdr, &symtabsize, &symtabentsize); + if (!symtab) + grub_util_error ("%s: relocation without symbol table", modname); + + for (rel = (Elf_Rel *) ((char *) ehdr + grub_target_to_host (s->sh_offset)), + max = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_size)); + rel < max; + rel = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_entsize))) + { + Elf_Sym *sym; + unsigned i; + + if (target_seg_size < grub_target_to_host (rel->r_offset)) + grub_util_error ("%s: reloc offset is out of the segment", modname); + + grub_size_t r_info; + if (arch->machine == EM_MIPS && arch->voidp_sizeof == 8) + r_info = ((grub_uint64_t) rel->r_info << 32) | + (grub_uint32_t) grub_be_to_cpu64 (rel->r_info); + else + r_info = grub_target_to_host (rel->r_info); + + grub_uint32_t type = ELF_R_TYPE (r_info); + + if (arch->machine == EM_SPARCV9) + type &= 0xff; + + for (i = 0; arch->supported_relocations[i] != -1; i++) + if (type == arch->supported_relocations[i]) + break; + if (arch->supported_relocations[i] != -1) + continue; + if (!arch->short_relocations) + grub_util_error ("%s: unsupported relocation 0x%x", modname, type); + for (i = 0; arch->short_relocations[i] != -1; i++) + if (type == arch->short_relocations[i]) + break; + if (arch->short_relocations[i] == -1) + grub_util_error ("%s: unsupported relocation 0x%x", modname, type); + sym = (Elf_Sym *) ((char *) symtab + symtabentsize * ELF_R_SYM (r_info)); + + if (is_symbol_local (sym)) + continue; + grub_util_error ("%s: relocation 0x%x is not module-local", modname, type); + } +#if defined(MODULEVERIFIER_ELF64) + if (arch->machine == EM_AARCH64) + { + unsigned unmatched_adr_got_page = 0; + Elf_Rela *rel2; + for (rel = (Elf_Rel *) ((char *) ehdr + grub_target_to_host (s->sh_offset)), + max = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_size)); + rel < max; + rel = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_entsize))) + { + switch (ELF_R_TYPE (grub_target_to_host (rel->r_info))) + { + case R_AARCH64_ADR_GOT_PAGE: + unmatched_adr_got_page++; + for (rel2 = (Elf_Rela *) ((char *) rel + grub_target_to_host (s->sh_entsize)); + rel2 < (Elf_Rela *) max; + rel2 = (Elf_Rela *) ((char *) rel2 + grub_target_to_host (s->sh_entsize))) + if (ELF_R_SYM (rel2->r_info) + == ELF_R_SYM (rel->r_info) + && ((Elf_Rela *) rel)->r_addend == rel2->r_addend + && ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC) + break; + if (rel2 >= (Elf_Rela *) max) + grub_util_error ("%s: ADR_GOT_PAGE without matching LD64_GOT_LO12_NC", modname); + break; + case R_AARCH64_LD64_GOT_LO12_NC: + if (unmatched_adr_got_page == 0) + grub_util_error ("%s: LD64_GOT_LO12_NC without matching ADR_GOT_PAGE", modname); + unmatched_adr_got_page--; + break; + } + } + } +#endif +} + +static void +check_relocations (const char * const modname, + const struct grub_module_verifier_arch *arch, Elf_Ehdr *e) +{ + Elf_Shdr *s; + unsigned i; + + for (i = 0, s = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff)); + i < grub_target_to_host16 (e->e_shnum); + i++, s = (Elf_Shdr *) ((char *) s + grub_target_to_host16 (e->e_shentsize))) + if (grub_target_to_host32 (s->sh_type) == SHT_REL || grub_target_to_host32 (s->sh_type) == SHT_RELA) + { + Elf_Shdr *ts; + + if (grub_target_to_host32 (s->sh_type) == SHT_REL && !(arch->flags & GRUB_MODULE_VERIFY_SUPPORTS_REL)) + grub_util_error ("%s: unsupported SHT_REL", modname); + if (grub_target_to_host32 (s->sh_type) == SHT_RELA && !(arch->flags & GRUB_MODULE_VERIFY_SUPPORTS_RELA)) + grub_util_error ("%s: unsupported SHT_RELA", modname); + + /* Find the target segment. */ + if (grub_target_to_host32 (s->sh_info) >= grub_target_to_host16 (e->e_shnum)) + grub_util_error ("%s: orphaned reloc section", modname); + ts = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + grub_target_to_host32 (s->sh_info) * grub_target_to_host16 (e->e_shentsize)); + + section_check_relocations (modname, arch, e, s, grub_target_to_host (ts->sh_size)); + } +} + +void +SUFFIX(grub_module_verify) (const char * const filename, + void *module_img, size_t size, + const struct grub_module_verifier_arch *arch, + const char **whitelist_empty) +{ + Elf_Ehdr *e = module_img; + + /* Check the header size. */ + if (size < sizeof (Elf_Ehdr)) + grub_util_error ("%s: ELF header smaller than expected", filename); + + /* Check the magic numbers. */ + if (e->e_ident[EI_MAG0] != ELFMAG0 + || e->e_ident[EI_MAG1] != ELFMAG1 + || e->e_ident[EI_MAG2] != ELFMAG2 + || e->e_ident[EI_MAG3] != ELFMAG3 + || e->e_ident[EI_VERSION] != EV_CURRENT + || grub_target_to_host32 (e->e_version) != EV_CURRENT) + grub_util_error ("%s: invalid arch-independent ELF magic", filename); + + if (e->e_ident[EI_CLASS] != ELFCLASSXX + || e->e_ident[EI_DATA] != (arch->bigendian ? ELFDATA2MSB : ELFDATA2LSB) + || grub_target_to_host16 (e->e_machine) != arch->machine) + grub_util_error ("%s: invalid arch-dependent ELF magic", filename); + + if (grub_target_to_host16 (e->e_type) != ET_REL) + { + grub_util_error ("%s: this ELF file is not of the right type", filename); + } + + /* Make sure that every section is within the core. */ + if (size < grub_target_to_host (e->e_shoff) + + (grub_uint32_t) grub_target_to_host16 (e->e_shentsize) * grub_target_to_host16(e->e_shnum)) + { + grub_util_error ("%s: ELF sections outside core", filename); + } + + check_license (filename, arch, e); + + Elf_Shdr *s; + const char *modname; + + s = find_section (arch, e, ".modname"); + if (!s) + grub_util_error ("%s: no module name found", filename); + + modname = (const char *) e + grub_target_to_host (s->sh_offset); + + check_symbols(arch, e, modname, whitelist_empty); + check_relocations(modname, arch, e); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/mkimage.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/mkimage.c new file mode 100644 index 0000000..25b0d8e --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/mkimage.c @@ -0,0 +1,1776 @@ +/* grub-mkimage.c - make a bootable image */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof)) + +#ifdef USE_LIBLZMA +#include +#endif + +#pragma GCC diagnostic ignored "-Wcast-align" + +#define TARGET_NO_FIELD 0xffffffff + +/* use 2015-01-01T00:00:00+0000 as a stock timestamp */ +#define STABLE_EMBEDDING_TIMESTAMP 1420070400 + +#define EFI32_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE \ + + GRUB_PE32_SIGNATURE_SIZE \ + + sizeof (struct grub_pe32_coff_header) \ + + sizeof (struct grub_pe32_optional_header) \ + + 4 * sizeof (struct grub_pe32_section_table), \ + GRUB_PE32_FILE_ALIGNMENT) + +#define EFI64_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE \ + + GRUB_PE32_SIGNATURE_SIZE \ + + sizeof (struct grub_pe32_coff_header) \ + + sizeof (struct grub_pe64_optional_header) \ + + 4 * sizeof (struct grub_pe32_section_table), \ + GRUB_PE32_FILE_ALIGNMENT) + +static const struct grub_install_image_target_desc image_targets[] = + { + { + .dirname = "i386-coreboot", + .names = { "i386-coreboot", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .reloc_table_offset = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, + .elf_target = EM_386, + .link_align = 4, + .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN + }, + { + .dirname = "i386-multiboot", + .names = { "i386-multiboot", NULL}, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_COREBOOT_LINK_ADDR, + .elf_target = EM_386, + .link_align = 4, + .mod_gap = GRUB_KERNEL_I386_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN + }, + { + .dirname = "i386-pc", + .names = { "i386-pc", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR, + .default_compression = GRUB_COMPRESSION_LZMA + }, + { + .dirname = "i386-xen_pvh", + .names = { "i386-xen_pvh", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_XEN_PVH, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .elf_target = EM_386, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_XEN_PVH_LINK_ADDR, + .mod_align = GRUB_KERNEL_I386_XEN_PVH_MOD_ALIGN, + .link_align = 4 + }, + { + .dirname = "i386-pc", + .names = { "i386-pc-pxe", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC_PXE, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR, + .default_compression = GRUB_COMPRESSION_LZMA + }, + { + .dirname = "i386-pc", + .names = { "i386-pc-eltorito", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC_ELTORITO, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_I386_PC_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_I386_PC_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR, + .default_compression = GRUB_COMPRESSION_LZMA + }, + { + .dirname = "i386-efi", + .names = { "i386-efi", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI32_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_I386, + .elf_target = EM_386, + }, + { + .dirname = "i386-ieee1275", + .names = { "i386-ieee1275", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_IEEE1275, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_IEEE1275_LINK_ADDR, + .elf_target = EM_386, + .mod_gap = GRUB_KERNEL_I386_IEEE1275_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN, + .link_align = 4, + }, + { + .dirname = "i386-qemu", + .names = { "i386-qemu", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_QEMU, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_I386_QEMU_LINK_ADDR + }, + { + .dirname = "x86_64-efi", + .names = { "x86_64-efi", NULL }, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_X86_64, + .elf_target = EM_X86_64, + }, + { + .dirname = "i386-xen", + .names = { "i386-xen", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_XEN, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = 0, + .elf_target = EM_386, + .mod_gap = GRUB_KERNEL_I386_XEN_MOD_GAP, + .mod_align = GRUB_KERNEL_I386_XEN_MOD_ALIGN, + .link_align = 4 + }, + { + .dirname = "x86_64-xen", + .names = { "x86_64-xen", NULL }, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_XEN, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = 0, + .elf_target = EM_X86_64, + .mod_gap = GRUB_KERNEL_X86_64_XEN_MOD_GAP, + .mod_align = GRUB_KERNEL_X86_64_XEN_MOD_ALIGN, + .link_align = 8 + }, + { + .dirname = "mipsel-loongson", + .names = { "mipsel-yeeloong-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_YEELOONG_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-loongson", + .names = { "mipsel-fuloong2f-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_FULOONG2F_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-loongson", + .names = { "mipsel-loongson-elf", "mipsel-yeeloong-elf", + "mipsel-fuloong2f-elf", "mipsel-fuloong2e-elf", + "mipsel-fuloong-elf", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_LOONGSON_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_LOONGSON_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_LOONGSON_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "powerpc-ieee1275", + .names = { "powerpc-ieee1275", NULL }, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_PPC, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR, + .elf_target = EM_PPC, + .mod_gap = GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP, + .mod_align = GRUB_KERNEL_POWERPC_IEEE1275_MOD_ALIGN, + .link_align = 4 + }, + { + .dirname = "sparc64-ieee1275", + .names = { "sparc64-ieee1275-raw", NULL }, + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_RAW, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR, + .mod_align = GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN, + }, + { + .dirname = "sparc64-ieee1275", + .names = { "sparc64-ieee1275-cdcore", NULL }, + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_CDCORE, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR, + .mod_align = GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN, + }, + { + .dirname = "sparc64-ieee1275", + .names = { "sparc64-ieee1275-aout", NULL }, + .voidp_sizeof = 8, + .bigendian = 1, + .id = IMAGE_SPARC64_AOUT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR, + .mod_align = GRUB_KERNEL_SPARC64_IEEE1275_MOD_ALIGN, + }, + { + .dirname = "ia64-efi", + .names = {"ia64-efi", NULL}, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_IA64, + .elf_target = EM_IA_64, + }, + { + .dirname = "mips-arc", + .names = {"mips-arc", NULL}, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_MIPS_ARC, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_ARC_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-arc", + .names = {"mipsel-arc", NULL}, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_MIPS_ARC, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPSEL_ARC_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_ARC_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-qemu_mips", + .names = { "mipsel-qemu_mips-elf", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_LOONGSON_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mips-qemu_mips", + .names = { "mips-qemu_mips-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_QEMU_MIPS_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mipsel-qemu_mips", + .names = { "mipsel-qemu_mips-flash", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_QEMU_MIPS_FLASH, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "mips-qemu_mips", + .names = { "mips-qemu_mips-elf", NULL }, + .voidp_sizeof = 4, + .bigendian = 1, + .id = IMAGE_LOONGSON_ELF, + .flags = PLATFORM_FLAGS_DECOMPRESSORS, + .total_module_size = GRUB_KERNEL_MIPS_QEMU_MIPS_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_COMPRESSED_SIZE, + .decompressor_uncompressed_size = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_SIZE, + .decompressor_uncompressed_addr = GRUB_DECOMPRESSOR_MIPS_LOONGSON_UNCOMPRESSED_ADDR, + .section_align = 1, + .vaddr_offset = 0, + .link_addr = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ADDR, + .elf_target = EM_MIPS, + .link_align = GRUB_KERNEL_MIPS_QEMU_MIPS_LINK_ALIGN, + .default_compression = GRUB_COMPRESSION_NONE + }, + { + .dirname = "arm-uboot", + .names = { "arm-uboot", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_UBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN, + .vaddr_offset = 0, + .elf_target = EM_ARM, + .mod_gap = GRUB_KERNEL_ARM_UBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN, + .link_align = 4 + }, + /* For coreboot versions that don't support self-relocating images. */ + { + .dirname = "arm-coreboot-vexpress", + .names = { "arm-coreboot-vexpress", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_ARM_COREBOOT_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN, + .vaddr_offset = 0, + .elf_target = EM_ARM, + .mod_gap = GRUB_KERNEL_ARM_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN, + .link_align = 4, + .link_addr = 0x62000000, + }, + { + .dirname = "arm-coreboot-veyron", + .names = { "arm-coreboot-veyron", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_COREBOOT, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = GRUB_KERNEL_ARM_COREBOOT_TOTAL_MODULE_SIZE, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN, + .vaddr_offset = 0, + .elf_target = EM_ARM, + .mod_gap = GRUB_KERNEL_ARM_COREBOOT_MOD_GAP, + .mod_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN, + .link_align = 4, + .link_addr = 0x43000000, + }, + { + .dirname = "arm-efi", + .names = { "arm-efi", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI32_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_ARMTHUMB_MIXED, + .elf_target = EM_ARM, + }, + { + .dirname = "arm64-efi", + .names = { "arm64-efi", NULL }, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_ARM64, + .elf_target = EM_AARCH64, + }, + { + .dirname = "mips64el-efi", + .names = { "mips64el-efi", NULL }, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_MIPS, + .elf_target = EM_MIPS, + }, + { + .dirname = "riscv32-efi", + .names = { "riscv32-efi", NULL }, + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI32_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_RISCV32, + .elf_target = EM_RISCV, + }, + { + .dirname = "riscv64-efi", + .names = { "riscv64-efi", NULL }, + .voidp_sizeof = 8, + .bigendian = 0, + .id = IMAGE_EFI, + .flags = PLATFORM_FLAGS_NONE, + .total_module_size = TARGET_NO_FIELD, + .decompressor_compressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_size = TARGET_NO_FIELD, + .decompressor_uncompressed_addr = TARGET_NO_FIELD, + .section_align = GRUB_PE32_SECTION_ALIGNMENT, + .vaddr_offset = EFI64_HEADER_SIZE, + .pe_target = GRUB_PE32_MACHINE_RISCV64, + .elf_target = EM_RISCV, + }, + }; + +#include + +static void *SzAlloc(void *p __attribute__ ((unused)), size_t size) { return xmalloc(size); } +static void SzFree(void *p __attribute__ ((unused)), void *address) { free(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +static void +compress_kernel_lzma (char *kernel_img, size_t kernel_size, + char **core_img, size_t *core_size) +{ + CLzmaEncProps props; + unsigned char out_props[5]; + size_t out_props_size = 5; + + LzmaEncProps_Init(&props); + props.dictSize = 1 << 16; + props.lc = 3; + props.lp = 0; + props.pb = 2; + props.numThreads = 1; + + *core_img = xmalloc (kernel_size); + + *core_size = kernel_size; + if (LzmaEncode ((unsigned char *) *core_img, core_size, + (unsigned char *) kernel_img, + kernel_size, + &props, out_props, &out_props_size, + 0, NULL, &g_Alloc, &g_Alloc) != SZ_OK) + grub_util_error ("%s", _("cannot compress the kernel image")); +} + +#ifdef USE_LIBLZMA +static void +compress_kernel_xz (char *kernel_img, size_t kernel_size, + char **core_img, size_t *core_size) +{ + lzma_stream strm = LZMA_STREAM_INIT; + lzma_ret xzret; + lzma_options_lzma lzopts = { + .dict_size = 1 << 16, + .preset_dict = NULL, + .preset_dict_size = 0, + .lc = 3, + .lp = 0, + .pb = 2, + .mode = LZMA_MODE_NORMAL, + .nice_len = 64, + .mf = LZMA_MF_BT4, + .depth = 0, + }; + lzma_filter fltrs[] = { + { .id = LZMA_FILTER_LZMA2, .options = &lzopts}, + { .id = LZMA_VLI_UNKNOWN, .options = NULL} + }; + + xzret = lzma_stream_encoder (&strm, fltrs, LZMA_CHECK_NONE); + if (xzret != LZMA_OK) + grub_util_error ("%s", _("cannot compress the kernel image")); + + *core_img = xmalloc (kernel_size); + + *core_size = kernel_size; + strm.next_in = (unsigned char *) kernel_img; + strm.avail_in = kernel_size; + strm.next_out = (unsigned char *) *core_img; + strm.avail_out = *core_size; + + while (1) + { + xzret = lzma_code (&strm, LZMA_FINISH); + if (xzret == LZMA_OK) + continue; + if (xzret == LZMA_STREAM_END) + break; + grub_util_error ("%s", _("cannot compress the kernel image")); + } + + *core_size -= strm.avail_out; +} +#endif + +static void +compress_kernel (const struct grub_install_image_target_desc *image_target, char *kernel_img, + size_t kernel_size, char **core_img, size_t *core_size, + grub_compression_t comp) +{ + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS + && (comp == GRUB_COMPRESSION_LZMA)) + { + compress_kernel_lzma (kernel_img, kernel_size, core_img, + core_size); + return; + } + +#ifdef USE_LIBLZMA + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS + && (comp == GRUB_COMPRESSION_XZ)) + { + compress_kernel_xz (kernel_img, kernel_size, core_img, + core_size); + return; + } +#endif + + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS + && (comp != GRUB_COMPRESSION_NONE)) + grub_util_error (_("unknown compression %d"), comp); + + *core_img = xmalloc (kernel_size); + memcpy (*core_img, kernel_img, kernel_size); + *core_size = kernel_size; +} + +const struct grub_install_image_target_desc * +grub_install_get_image_target (const char *arg) +{ + unsigned i, j; + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + for (j = 0; j < ARRAY_SIZE (image_targets[i].names) && + image_targets[i].names[j]; j++) + if (strcmp (arg, image_targets[i].names[j]) == 0) + return &image_targets[i]; + return NULL; +} + +const char * +grub_util_get_target_dirname (const struct grub_install_image_target_desc *t) +{ + return t->dirname; +} + +const char * +grub_util_get_target_name (const struct grub_install_image_target_desc *t) +{ + return t->names[0]; +} + +char * +grub_install_get_image_targets_string (void) +{ + int format_len = 0; + char *formats; + char *ptr; + unsigned i; + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + format_len += strlen (image_targets[i].names[0]) + 2; + ptr = formats = xmalloc (format_len); + for (i = 0; i < ARRAY_SIZE (image_targets); i++) + { + strcpy (ptr, image_targets[i].names[0]); + ptr += strlen (image_targets[i].names[0]); + *ptr++ = ','; + *ptr++ = ' '; + } + ptr[-2] = 0; + + return formats; +} + +void +grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, const char *outname, char *mods[], + char *memdisk_path, char **pubkey_paths, + size_t npubkeys, char *config_path, + const struct grub_install_image_target_desc *image_target, + int note, grub_compression_t comp, const char *dtb_path) +{ + char *kernel_img, *core_img; + size_t total_module_size, core_size; + size_t memdisk_size = 0, config_size = 0; + size_t prefix_size = 0, dtb_size = 0; + char *kernel_path; + size_t offset; + struct grub_util_path_list *path_list, *p; + size_t decompress_size = 0; + struct grub_mkimage_layout layout; + + if (comp == GRUB_COMPRESSION_AUTO) + comp = image_target->default_compression; + + if (image_target->id == IMAGE_I386_PC + || image_target->id == IMAGE_I386_PC_PXE + || image_target->id == IMAGE_I386_PC_ELTORITO) + comp = GRUB_COMPRESSION_LZMA; + + path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); + + kernel_path = grub_util_get_path (dir, "kernel.img"); + + if (image_target->voidp_sizeof == 8) + total_module_size = sizeof (struct grub_module_info64); + else + total_module_size = sizeof (struct grub_module_info32); + + { + size_t i; + for (i = 0; i < npubkeys; i++) + { + size_t curs; + curs = ALIGN_ADDR (grub_util_get_image_size (pubkey_paths[i])); + grub_util_info ("the size of public key %u is 0x%" + GRUB_HOST_PRIxLONG_LONG, + (unsigned) i, (unsigned long long) curs); + total_module_size += curs + sizeof (struct grub_module_header); + } + } + + if (memdisk_path) + { + memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); + grub_util_info ("the size of memory disk is 0x%" GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) memdisk_size); + total_module_size += memdisk_size + sizeof (struct grub_module_header); + } + + if (dtb_path) + { + dtb_size = ALIGN_ADDR(grub_util_get_image_size (dtb_path)); + total_module_size += dtb_size + sizeof (struct grub_module_header); + } + + if (config_path) + { + config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1); + grub_util_info ("the size of config file is 0x%" GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) config_size); + total_module_size += config_size + sizeof (struct grub_module_header); + } + + if (prefix) + { + prefix_size = ALIGN_ADDR (strlen (prefix) + 1); + total_module_size += prefix_size + sizeof (struct grub_module_header); + } + + for (p = path_list; p; p = p->next) + total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name)) + + sizeof (struct grub_module_header)); + + grub_util_info ("the total module size is 0x%" GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) total_module_size); + + if (image_target->voidp_sizeof == 4) + kernel_img = grub_mkimage_load_image32 (kernel_path, total_module_size, + &layout, image_target); + else + kernel_img = grub_mkimage_load_image64 (kernel_path, total_module_size, + &layout, image_target); + if ((image_target->id == IMAGE_XEN || image_target->id == IMAGE_XEN_PVH) && + layout.align < 4096) + layout.align = 4096; + + if ((image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) + && (image_target->total_module_size != TARGET_NO_FIELD)) + *((grub_uint32_t *) (kernel_img + image_target->total_module_size)) + = grub_host_to_target32 (total_module_size); + + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + { + memmove (kernel_img + total_module_size, kernel_img, layout.kernel_size); + memset (kernel_img, 0, total_module_size); + } + + if (image_target->voidp_sizeof == 8) + { + /* Fill in the grub_module_info structure. */ + struct grub_module_info64 *modinfo; + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + modinfo = (struct grub_module_info64 *) kernel_img; + else + modinfo = (struct grub_module_info64 *) (kernel_img + layout.kernel_size); + modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); + modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info64)); + modinfo->size = grub_host_to_target_addr (total_module_size); + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + offset = sizeof (struct grub_module_info64); + else + offset = layout.kernel_size + sizeof (struct grub_module_info64); + } + else + { + /* Fill in the grub_module_info structure. */ + struct grub_module_info32 *modinfo; + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + modinfo = (struct grub_module_info32 *) kernel_img; + else + modinfo = (struct grub_module_info32 *) (kernel_img + layout.kernel_size); + modinfo->magic = grub_host_to_target32 (GRUB_MODULE_MAGIC); + modinfo->offset = grub_host_to_target_addr (sizeof (struct grub_module_info32)); + modinfo->size = grub_host_to_target_addr (total_module_size); + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + offset = sizeof (struct grub_module_info32); + else + offset = layout.kernel_size + sizeof (struct grub_module_info32); + } + + for (p = path_list; p; p = p->next) + { + struct grub_module_header *header; + size_t mod_size; + + mod_size = ALIGN_ADDR (grub_util_get_image_size (p->name)); + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_ELF); + header->size = grub_host_to_target32 (mod_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (p->name, kernel_img + offset); + offset += mod_size; + } + + { + size_t i; + for (i = 0; i < npubkeys; i++) + { + size_t curs; + struct grub_module_header *header; + + curs = grub_util_get_image_size (pubkey_paths[i]); + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY); + header->size = grub_host_to_target32 (curs + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (pubkey_paths[i], kernel_img + offset); + offset += ALIGN_ADDR (curs); + } + } + + if (memdisk_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_MEMDISK); + header->size = grub_host_to_target32 (memdisk_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (memdisk_path, kernel_img + offset); + offset += memdisk_size; + } + + if (dtb_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_DTB); + header->size = grub_host_to_target32 (dtb_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (dtb_path, kernel_img + offset); + offset += dtb_size; + } + + if (config_path) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_CONFIG); + header->size = grub_host_to_target32 (config_size + sizeof (*header)); + offset += sizeof (*header); + + grub_util_load_image (config_path, kernel_img + offset); + offset += config_size; + } + + if (prefix) + { + struct grub_module_header *header; + + header = (struct grub_module_header *) (kernel_img + offset); + header->type = grub_host_to_target32 (OBJ_TYPE_PREFIX); + header->size = grub_host_to_target32 (prefix_size + sizeof (*header)); + offset += sizeof (*header); + + grub_strcpy (kernel_img + offset, prefix); + offset += prefix_size; + } + + grub_util_info ("kernel_img=%p, kernel_size=0x%" GRUB_HOST_PRIxLONG_LONG, + kernel_img, + (unsigned long long) layout.kernel_size); + compress_kernel (image_target, kernel_img, layout.kernel_size + total_module_size, + &core_img, &core_size, comp); + free (kernel_img); + + grub_util_info ("the core size is 0x%" GRUB_HOST_PRIxLONG_LONG, + (unsigned long long) core_size); + + if (!(image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) + && image_target->total_module_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (core_img + image_target->total_module_size)) + = grub_host_to_target32 (total_module_size); + + if (image_target->flags & PLATFORM_FLAGS_DECOMPRESSORS) + { + char *full_img; + size_t full_size; + char *decompress_path, *decompress_img; + const char *name; + + switch (comp) + { + case GRUB_COMPRESSION_XZ: + name = "xz_decompress.img"; + break; + case GRUB_COMPRESSION_LZMA: + name = "lzma_decompress.img"; + break; + case GRUB_COMPRESSION_NONE: + name = "none_decompress.img"; + break; + default: + grub_util_error (_("unknown compression %d"), comp); + } + + decompress_path = grub_util_get_path (dir, name); + decompress_size = grub_util_get_image_size (decompress_path); + decompress_img = grub_util_read_image (decompress_path); + + if ((image_target->id == IMAGE_I386_PC + || image_target->id == IMAGE_I386_PC_PXE + || image_target->id == IMAGE_I386_PC_ELTORITO) + && decompress_size > GRUB_KERNEL_I386_PC_LINK_ADDR - 0x8200) + grub_util_error ("%s", _("Decompressor is too big")); + + if (image_target->decompressor_compressed_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (decompress_img + + image_target->decompressor_compressed_size)) + = grub_host_to_target32 (core_size); + + if (image_target->decompressor_uncompressed_size != TARGET_NO_FIELD) + *((grub_uint32_t *) (decompress_img + + image_target->decompressor_uncompressed_size)) + = grub_host_to_target32 (layout.kernel_size + total_module_size); + + if (image_target->decompressor_uncompressed_addr != TARGET_NO_FIELD) + { + if (image_target->flags & PLATFORM_FLAGS_MODULES_BEFORE_KERNEL) + *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr)) + = grub_host_to_target_addr (image_target->link_addr - total_module_size); + else + *((grub_uint32_t *) (decompress_img + image_target->decompressor_uncompressed_addr)) + = grub_host_to_target_addr (image_target->link_addr); + } + full_size = core_size + decompress_size; + + full_img = xmalloc (full_size); + + memcpy (full_img, decompress_img, decompress_size); + + memcpy (full_img + decompress_size, core_img, core_size); + + free (core_img); + core_img = full_img; + core_size = full_size; + free (decompress_img); + free (decompress_path); + } + + switch (image_target->id) + { + case IMAGE_I386_PC: + case IMAGE_I386_PC_PXE: + case IMAGE_I386_PC_ELTORITO: + if (GRUB_KERNEL_I386_PC_LINK_ADDR + core_size > 0x78000 + || (core_size > (0xffff << GRUB_DISK_SECTOR_BITS)) + || (layout.kernel_size + layout.bss_size + + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)) + grub_util_error (_("core image is too big (0x%x > 0x%x)"), + GRUB_KERNEL_I386_PC_LINK_ADDR + (unsigned) core_size, + 0x78000); + /* fallthrough */ + case IMAGE_COREBOOT: + case IMAGE_QEMU: + if (image_target->elf_target != EM_ARM && layout.kernel_size + layout.bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000) + grub_util_error (_("kernel image is too big (0x%x > 0x%x)"), + (unsigned) layout.kernel_size + (unsigned) layout.bss_size + + GRUB_KERNEL_I386_PC_LINK_ADDR, + 0x68000); + break; + case IMAGE_LOONGSON_ELF: + case IMAGE_YEELOONG_FLASH: + case IMAGE_FULOONG2F_FLASH: + case IMAGE_EFI: + case IMAGE_MIPS_ARC: + case IMAGE_QEMU_MIPS_FLASH: + case IMAGE_XEN: + case IMAGE_XEN_PVH: + break; + case IMAGE_SPARC64_AOUT: + case IMAGE_SPARC64_RAW: + case IMAGE_SPARC64_CDCORE: + case IMAGE_I386_IEEE1275: + case IMAGE_PPC: + case IMAGE_UBOOT: + break; + } + + switch (image_target->id) + { + case IMAGE_I386_PC: + case IMAGE_I386_PC_PXE: + case IMAGE_I386_PC_ELTORITO: + { + unsigned num; + char *boot_path, *boot_img; + size_t boot_size; + + num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); + if (image_target->id == IMAGE_I386_PC_PXE) + { + char *pxeboot_path, *pxeboot_img; + size_t pxeboot_size; + grub_uint32_t *ptr; + + pxeboot_path = grub_util_get_path (dir, "pxeboot.img"); + pxeboot_size = grub_util_get_image_size (pxeboot_path); + pxeboot_img = grub_util_read_image (pxeboot_path); + + grub_util_write_image (pxeboot_img, pxeboot_size, out, + outname); + free (pxeboot_img); + free (pxeboot_path); + + /* Remove Multiboot header to avoid confusing ipxe. */ + for (ptr = (grub_uint32_t *) core_img; + ptr < (grub_uint32_t *) (core_img + MULTIBOOT_SEARCH); ptr++) + if (*ptr == grub_host_to_target32 (MULTIBOOT_HEADER_MAGIC) + && grub_target_to_host32 (ptr[0]) + + grub_target_to_host32 (ptr[1]) + + grub_target_to_host32 (ptr[2]) == 0) + { + *ptr = 0; + break; + } + } + + if (image_target->id == IMAGE_I386_PC_ELTORITO) + { + char *eltorito_path, *eltorito_img; + size_t eltorito_size; + + eltorito_path = grub_util_get_path (dir, "cdboot.img"); + eltorito_size = grub_util_get_image_size (eltorito_path); + eltorito_img = grub_util_read_image (eltorito_path); + + grub_util_write_image (eltorito_img, eltorito_size, out, + outname); + free (eltorito_img); + free (eltorito_path); + } + + boot_path = grub_util_get_path (dir, "diskboot.img"); + boot_size = grub_util_get_image_size (boot_path); + if (boot_size != GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("diskboot.img size must be %u bytes"), + GRUB_DISK_SECTOR_SIZE); + + boot_img = grub_util_read_image (boot_path); + + { + struct grub_pc_bios_boot_blocklist *block; + block = (struct grub_pc_bios_boot_blocklist *) (boot_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*block)); + block->len = grub_host_to_target16 (num); + + /* This is filled elsewhere. Verify it just in case. */ + assert (block->segment + == grub_host_to_target16 (GRUB_BOOT_I386_PC_KERNEL_SEG + + (GRUB_DISK_SECTOR_SIZE >> 4))); + } + + grub_util_write_image (boot_img, boot_size, out, outname); + free (boot_img); + free (boot_path); + } + break; + case IMAGE_EFI: + { + void *pe_img; + grub_uint8_t *header; + void *sections; + size_t pe_size; + struct grub_pe32_coff_header *c; + struct grub_pe32_section_table *text_section, *data_section; + struct grub_pe32_section_table *mods_section, *reloc_section; + static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; + int header_size; + int reloc_addr; + + if (image_target->voidp_sizeof == 4) + header_size = EFI32_HEADER_SIZE; + else + header_size = EFI64_HEADER_SIZE; + + reloc_addr = ALIGN_UP (header_size + core_size, + GRUB_PE32_FILE_ALIGNMENT); + + pe_size = ALIGN_UP (reloc_addr + layout.reloc_size, + GRUB_PE32_FILE_ALIGNMENT); + pe_img = xmalloc (reloc_addr + layout.reloc_size); + memset (pe_img, 0, header_size); + memcpy ((char *) pe_img + header_size, core_img, core_size); + memset ((char *) pe_img + header_size + core_size, 0, reloc_addr - (header_size + core_size)); + memcpy ((char *) pe_img + reloc_addr, layout.reloc_section, layout.reloc_size); + header = pe_img; + + /* The magic. */ + memcpy (header, stub, GRUB_PE32_MSDOS_STUB_SIZE); + memcpy (header + GRUB_PE32_MSDOS_STUB_SIZE, "PE\0\0", + GRUB_PE32_SIGNATURE_SIZE); + + /* The COFF file header. */ + c = (struct grub_pe32_coff_header *) (header + GRUB_PE32_MSDOS_STUB_SIZE + + GRUB_PE32_SIGNATURE_SIZE); + c->machine = grub_host_to_target16 (image_target->pe_target); + + c->num_sections = grub_host_to_target16 (4); + c->time = grub_host_to_target32 (STABLE_EMBEDDING_TIMESTAMP); + c->characteristics = grub_host_to_target16 (GRUB_PE32_EXECUTABLE_IMAGE + | GRUB_PE32_LINE_NUMS_STRIPPED + | ((image_target->voidp_sizeof == 4) + ? GRUB_PE32_32BIT_MACHINE + : 0) + | GRUB_PE32_LOCAL_SYMS_STRIPPED + | GRUB_PE32_DEBUG_STRIPPED); + + /* The PE Optional header. */ + if (image_target->voidp_sizeof == 4) + { + struct grub_pe32_optional_header *o; + + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe32_optional_header)); + + o = (struct grub_pe32_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE32_MAGIC); + o->code_size = grub_host_to_target32 (layout.exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size + - header_size); + o->bss_size = grub_cpu_to_le32 (layout.bss_size); + o->entry_addr = grub_cpu_to_le32 (layout.start_address); + o->code_base = grub_cpu_to_le32 (header_size); + + o->data_base = grub_host_to_target32 (header_size + layout.exec_size); + + o->image_base = 0; + o->section_alignment = grub_host_to_target32 (image_target->section_align); + o->file_alignment = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); + o->image_size = grub_host_to_target32 (pe_size); + o->header_size = grub_host_to_target32 (header_size); + o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ + o->stack_reserve_size = grub_host_to_target32 (0x10000); + o->stack_commit_size = grub_host_to_target32 (0x10000); + o->heap_reserve_size = grub_host_to_target32 (0x10000); + o->heap_commit_size = grub_host_to_target32 (0x10000); + + o->num_data_directories = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); + + o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); + o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); + sections = o + 1; + } + else + { + struct grub_pe64_optional_header *o; + + c->optional_header_size = grub_host_to_target16 (sizeof (struct grub_pe64_optional_header)); + + o = (struct grub_pe64_optional_header *) + (header + GRUB_PE32_MSDOS_STUB_SIZE + GRUB_PE32_SIGNATURE_SIZE + + sizeof (struct grub_pe32_coff_header)); + o->magic = grub_host_to_target16 (GRUB_PE32_PE64_MAGIC); + o->code_size = grub_host_to_target32 (layout.exec_size); + o->data_size = grub_cpu_to_le32 (reloc_addr - layout.exec_size + - header_size); + o->bss_size = grub_cpu_to_le32 (layout.bss_size); + o->entry_addr = grub_cpu_to_le32 (layout.start_address); + o->code_base = grub_cpu_to_le32 (header_size); + o->image_base = 0; + o->section_alignment = grub_host_to_target32 (image_target->section_align); + o->file_alignment = grub_host_to_target32 (GRUB_PE32_FILE_ALIGNMENT); + o->image_size = grub_host_to_target32 (pe_size); + o->header_size = grub_host_to_target32 (header_size); + o->subsystem = grub_host_to_target16 (GRUB_PE32_SUBSYSTEM_EFI_APPLICATION); + + /* Do these really matter? */ + o->stack_reserve_size = grub_host_to_target64 (0x10000); + o->stack_commit_size = grub_host_to_target64 (0x10000); + o->heap_reserve_size = grub_host_to_target64 (0x10000); + o->heap_commit_size = grub_host_to_target64 (0x10000); + + o->num_data_directories + = grub_host_to_target32 (GRUB_PE32_NUM_DATA_DIRECTORIES); + + o->base_relocation_table.rva = grub_host_to_target32 (reloc_addr); + o->base_relocation_table.size = grub_host_to_target32 (layout.reloc_size); + sections = o + 1; + } + /* The sections. */ + text_section = sections; + strcpy (text_section->name, ".text"); + text_section->virtual_size = grub_cpu_to_le32 (layout.exec_size); + text_section->virtual_address = grub_cpu_to_le32 (header_size); + text_section->raw_data_size = grub_cpu_to_le32 (layout.exec_size); + text_section->raw_data_offset = grub_cpu_to_le32 (header_size); + text_section->characteristics = grub_cpu_to_le32_compile_time ( + GRUB_PE32_SCN_CNT_CODE + | GRUB_PE32_SCN_MEM_EXECUTE + | GRUB_PE32_SCN_MEM_READ); + + data_section = text_section + 1; + strcpy (data_section->name, ".data"); + data_section->virtual_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); + data_section->virtual_address = grub_cpu_to_le32 (header_size + layout.exec_size); + data_section->raw_data_size = grub_cpu_to_le32 (layout.kernel_size - layout.exec_size); + data_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.exec_size); + data_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); + +#if 0 + bss_section = data_section + 1; + strcpy (bss_section->name, ".bss"); + bss_section->virtual_size = grub_cpu_to_le32 (layout.bss_size); + bss_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size); + bss_section->raw_data_size = 0; + bss_section->raw_data_offset = 0; + bss_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE + | GRUB_PE32_SCN_ALIGN_64BYTES + | GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | 0x80); +#endif + + mods_section = data_section + 1; + strcpy (mods_section->name, "mods"); + mods_section->virtual_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); + mods_section->virtual_address = grub_cpu_to_le32 (header_size + layout.kernel_size + layout.bss_size); + mods_section->raw_data_size = grub_cpu_to_le32 (reloc_addr - layout.kernel_size - header_size); + mods_section->raw_data_offset = grub_cpu_to_le32 (header_size + layout.kernel_size); + mods_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_READ + | GRUB_PE32_SCN_MEM_WRITE); + + reloc_section = mods_section + 1; + strcpy (reloc_section->name, ".reloc"); + reloc_section->virtual_size = grub_cpu_to_le32 (layout.reloc_size); + reloc_section->virtual_address = grub_cpu_to_le32 (reloc_addr + layout.bss_size); + reloc_section->raw_data_size = grub_cpu_to_le32 (layout.reloc_size); + reloc_section->raw_data_offset = grub_cpu_to_le32 (reloc_addr); + reloc_section->characteristics + = grub_cpu_to_le32_compile_time (GRUB_PE32_SCN_CNT_INITIALIZED_DATA + | GRUB_PE32_SCN_MEM_DISCARDABLE + | GRUB_PE32_SCN_MEM_READ); + free (core_img); + core_img = pe_img; + core_size = pe_size; + } + break; + case IMAGE_QEMU: + { + char *rom_img; + size_t rom_size; + char *boot_path, *boot_img; + size_t boot_size; + + boot_path = grub_util_get_path (dir, "boot.img"); + boot_size = grub_util_get_image_size (boot_path); + boot_img = grub_util_read_image (boot_path); + + /* Rom sizes must be 64k-aligned. */ + rom_size = ALIGN_UP (core_size + boot_size, 64 * 1024); + + rom_img = xmalloc (rom_size); + memset (rom_img, 0, rom_size); + + *((grub_int32_t *) (core_img + GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR)) + = grub_host_to_target32 ((grub_uint32_t) -rom_size); + + memcpy (rom_img, core_img, core_size); + + *((grub_int32_t *) (boot_img + GRUB_BOOT_I386_QEMU_CORE_ENTRY_ADDR)) + = grub_host_to_target32 ((grub_uint32_t) -rom_size); + + memcpy (rom_img + rom_size - boot_size, boot_img, boot_size); + + free (core_img); + core_img = rom_img; + core_size = rom_size; + + free (boot_img); + free (boot_path); + } + break; + case IMAGE_SPARC64_AOUT: + { + void *aout_img; + size_t aout_size; + struct grub_aout32_header *aout_head; + + aout_size = core_size + sizeof (*aout_head); + aout_img = xmalloc (aout_size); + aout_head = aout_img; + grub_memset (aout_head, 0, sizeof (*aout_head)); + aout_head->a_midmag = grub_host_to_target32 ((AOUT_MID_SUN << 16) + | AOUT32_OMAGIC); + aout_head->a_text = grub_host_to_target32 (core_size); + aout_head->a_entry + = grub_host_to_target32 (GRUB_BOOT_SPARC64_IEEE1275_IMAGE_ADDRESS); + memcpy ((char *) aout_img + sizeof (*aout_head), core_img, core_size); + + free (core_img); + core_img = aout_img; + core_size = aout_size; + } + break; + case IMAGE_SPARC64_RAW: + { + unsigned int num; + char *boot_path, *boot_img; + size_t boot_size; + + num = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); + num <<= GRUB_DISK_SECTOR_BITS; + + boot_path = grub_util_get_path (dir, "diskboot.img"); + boot_size = grub_util_get_image_size (boot_path); + if (boot_size != GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("diskboot.img size must be %u bytes"), + GRUB_DISK_SECTOR_SIZE); + + boot_img = grub_util_read_image (boot_path); + + *((grub_uint32_t *) (boot_img + GRUB_DISK_SECTOR_SIZE + - GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE + 8)) + = grub_host_to_target32 (num); + + grub_util_write_image (boot_img, boot_size, out, outname); + free (boot_img); + free (boot_path); + } + break; + case IMAGE_SPARC64_CDCORE: + break; + case IMAGE_YEELOONG_FLASH: + case IMAGE_FULOONG2F_FLASH: + { + char *rom_img; + size_t rom_size; + char *boot_path, *boot_img; + size_t boot_size; + /* fwstart.img is the only part which can't be tested by using *-elf + target. Check it against the checksum. */ + const grub_uint8_t yeeloong_fwstart_good_hash[512 / 8] = + { + 0x5f, 0x67, 0x46, 0x57, 0x31, 0x30, 0xc5, 0x0a, + 0xe9, 0x98, 0x18, 0xc9, 0xf3, 0xca, 0x45, 0xa5, + 0x75, 0x64, 0x6b, 0xbb, 0x24, 0xcd, 0xb4, 0xbc, + 0xf2, 0x3e, 0x23, 0xf9, 0xc2, 0x6a, 0x8c, 0xde, + 0x3b, 0x94, 0x9c, 0xcc, 0xa5, 0xa7, 0x58, 0xb1, + 0xbe, 0x8b, 0x3d, 0x73, 0x98, 0x18, 0x7e, 0x68, + 0x5e, 0x5f, 0x23, 0x7d, 0x7a, 0xe8, 0x51, 0xf7, + 0x1a, 0xaf, 0x2f, 0x54, 0x11, 0x2e, 0x5c, 0x25 + }; + const grub_uint8_t fuloong2f_fwstart_good_hash[512 / 8] = + { + 0x76, 0x9b, 0xad, 0x6e, 0xa2, 0x39, 0x47, 0x62, + 0x1f, 0xc9, 0x3a, 0x6d, 0x05, 0x5c, 0x43, 0x5c, + 0x29, 0x4a, 0x7e, 0x08, 0x2a, 0x31, 0x8f, 0x5d, + 0x02, 0x84, 0xa0, 0x85, 0xf2, 0xd1, 0xb9, 0x53, + 0xa2, 0xbc, 0xf2, 0xe1, 0x39, 0x1e, 0x51, 0xb5, + 0xaf, 0xec, 0x9e, 0xf2, 0xf1, 0xf3, 0x0a, 0x2f, + 0xe6, 0xf1, 0x08, 0x89, 0xbe, 0xbc, 0x73, 0xab, + 0x46, 0x50, 0xd6, 0x21, 0xce, 0x8e, 0x24, 0xa7 + }; + const grub_uint8_t *fwstart_good_hash; + grub_uint8_t fwstart_hash[512 / 8]; + + if (image_target->id == IMAGE_FULOONG2F_FLASH) + { + fwstart_good_hash = fuloong2f_fwstart_good_hash; + boot_path = grub_util_get_path (dir, "fwstart_fuloong2f.img"); + } + else + { + fwstart_good_hash = yeeloong_fwstart_good_hash; + boot_path = grub_util_get_path (dir, "fwstart.img"); + } + + boot_size = grub_util_get_image_size (boot_path); + boot_img = grub_util_read_image (boot_path); + + grub_crypto_hash (GRUB_MD_SHA512, fwstart_hash, boot_img, boot_size); + + if (grub_memcmp (fwstart_hash, fwstart_good_hash, + GRUB_MD_SHA512->mdlen) != 0) + /* TRANSLATORS: fwstart.img may still be good, just it wasn't checked. */ + grub_util_warn ("%s", + _("fwstart.img doesn't match the known good version. " + "proceed at your own risk")); + + if (core_size + boot_size > 512 * 1024) + grub_util_error ("%s", _("firmware image is too big")); + rom_size = 512 * 1024; + + rom_img = xmalloc (rom_size); + memset (rom_img, 0, rom_size); + + memcpy (rom_img, boot_img, boot_size); + + memcpy (rom_img + boot_size, core_img, core_size); + + memset (rom_img + boot_size + core_size, 0, + rom_size - (boot_size + core_size)); + + free (core_img); + core_img = rom_img; + core_size = rom_size; + free (boot_img); + free (boot_path); + } + break; + case IMAGE_QEMU_MIPS_FLASH: + { + char *rom_img; + size_t rom_size; + + if (core_size > 512 * 1024) + grub_util_error ("%s", _("firmware image is too big")); + rom_size = 512 * 1024; + + rom_img = xmalloc (rom_size); + memset (rom_img, 0, rom_size); + + memcpy (rom_img, core_img, core_size); + + memset (rom_img + core_size, 0, + rom_size - core_size); + + free (core_img); + core_img = rom_img; + core_size = rom_size; + } + break; + + case IMAGE_UBOOT: + { + struct grub_uboot_image_header *hdr; + + hdr = xmalloc (core_size + sizeof (struct grub_uboot_image_header)); + memcpy (hdr + 1, core_img, core_size); + + memset (hdr, 0, sizeof (*hdr)); + hdr->ih_magic = grub_cpu_to_be32_compile_time (GRUB_UBOOT_IH_MAGIC); + hdr->ih_time = grub_cpu_to_be32 (STABLE_EMBEDDING_TIMESTAMP); + hdr->ih_size = grub_cpu_to_be32 (core_size); + hdr->ih_load = 0; + hdr->ih_ep = 0; + hdr->ih_type = GRUB_UBOOT_IH_TYPE_KERNEL_NOLOAD; + hdr->ih_os = GRUB_UBOOT_IH_OS_LINUX; + hdr->ih_arch = GRUB_UBOOT_IH_ARCH_ARM; + hdr->ih_comp = GRUB_UBOOT_IH_COMP_NONE; + + grub_crypto_hash (GRUB_MD_CRC32, &hdr->ih_dcrc, hdr + 1, core_size); + grub_crypto_hash (GRUB_MD_CRC32, &hdr->ih_hcrc, hdr, sizeof (*hdr)); + + free (core_img); + core_img = (char *) hdr; + core_size += sizeof (struct grub_uboot_image_header); + } + break; + + case IMAGE_MIPS_ARC: + { + char *ecoff_img; + struct ecoff_header { + grub_uint16_t magic; + grub_uint16_t nsec; + grub_uint32_t time; + grub_uint32_t syms; + grub_uint32_t nsyms; + grub_uint16_t opt; + grub_uint16_t flags; + grub_uint16_t magic2; + grub_uint16_t version; + grub_uint32_t textsize; + grub_uint32_t datasize; + grub_uint32_t bsssize; + grub_uint32_t entry; + grub_uint32_t text_start; + grub_uint32_t data_start; + grub_uint32_t bss_start; + grub_uint32_t gprmask; + grub_uint32_t cprmask[4]; + grub_uint32_t gp_value; + }; + struct ecoff_section + { + char name[8]; + grub_uint32_t paddr; + grub_uint32_t vaddr; + grub_uint32_t size; + grub_uint32_t file_offset; + grub_uint32_t reloc; + grub_uint32_t gp; + grub_uint16_t nreloc; + grub_uint16_t ngp; + grub_uint32_t flags; + }; + struct ecoff_header *head; + struct ecoff_section *section; + grub_uint32_t target_addr; + size_t program_size; + + program_size = ALIGN_ADDR (core_size); + if (comp == GRUB_COMPRESSION_NONE) + target_addr = (image_target->link_addr - decompress_size); + else + target_addr = ALIGN_UP (image_target->link_addr + + layout.kernel_size + total_module_size, 32); + + ecoff_img = xmalloc (program_size + sizeof (*head) + sizeof (*section)); + grub_memset (ecoff_img, 0, program_size + sizeof (*head) + sizeof (*section)); + head = (void *) ecoff_img; + section = (void *) (head + 1); + head->magic = image_target->bigendian ? grub_host_to_target16 (0x160) + : grub_host_to_target16 (0x166); + head->nsec = grub_host_to_target16 (1); + head->time = grub_host_to_target32 (0); + head->opt = grub_host_to_target16 (0x38); + head->flags = image_target->bigendian + ? grub_host_to_target16 (0x207) + : grub_host_to_target16 (0x103); + head->magic2 = grub_host_to_target16 (0x107); + head->textsize = grub_host_to_target32 (program_size); + head->entry = grub_host_to_target32 (target_addr); + head->text_start = grub_host_to_target32 (target_addr); + head->data_start = grub_host_to_target32 (target_addr + program_size); + grub_memcpy (section->name, ".text", sizeof (".text") - 1); + section->vaddr = grub_host_to_target32 (target_addr); + section->size = grub_host_to_target32 (program_size); + section->file_offset = grub_host_to_target32 (sizeof (*head) + sizeof (*section)); + if (!image_target->bigendian) + { + section->paddr = grub_host_to_target32 (0xaa60); + section->flags = grub_host_to_target32 (0x20); + } + memcpy (section + 1, core_img, core_size); + free (core_img); + core_img = ecoff_img; + core_size = program_size + sizeof (*head) + sizeof (*section); + } + break; + case IMAGE_LOONGSON_ELF: + case IMAGE_PPC: + case IMAGE_XEN: + case IMAGE_XEN_PVH: + case IMAGE_COREBOOT: + case IMAGE_I386_IEEE1275: + { + grub_uint64_t target_addr; + if (image_target->id == IMAGE_LOONGSON_ELF) + { + if (comp == GRUB_COMPRESSION_NONE) + target_addr = (image_target->link_addr - decompress_size); + else + target_addr = ALIGN_UP (image_target->link_addr + + layout.kernel_size + total_module_size, 32); + } + else + target_addr = image_target->link_addr; + if (image_target->voidp_sizeof == 4) + grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, + target_addr, &layout); + else + grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, + target_addr, &layout); + } + break; + } + + grub_util_write_image (core_img, core_size, out, outname); + free (core_img); + free (kernel_path); + free (layout.reloc_section); + + grub_util_free_path_list (path_list); +} diff --git a/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/setup.c b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/setup.c new file mode 100644 index 0000000..b5c8885 --- /dev/null +++ b/Ventoy-src/GRUB2/MOD_SRC/grub-2.04/util/setup.c @@ -0,0 +1,878 @@ +/* grub-setup.c - make GRUB usable */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef GRUB_SETUP_SPARC64 +#include +#include +#include +#else +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "progname.h" +#include +#include +#include +#include +#include + +#include + +/* On SPARC this program fills in various fields inside of the 'boot' and 'core' + * image files. + * + * The 'boot' image needs to know the OBP path name of the root + * device. It also needs to know the initial block number of + * 'core' (which is 'diskboot' concatenated with 'kernel' and + * all the modules, this is created by grub-mkimage). This resulting + * 'boot' image is 512 bytes in size and is placed in the second block + * of a partition. + * + * The initial 'diskboot' block acts as a loader for the actual GRUB + * kernel. It contains the loading code and then a block list. + * + * The block list of 'core' starts at the end of the 'diskboot' image + * and works it's way backwards towards the end of the code of 'diskboot'. + * + * We patch up the images with the necessary values and write out the + * result. + */ + +#ifdef GRUB_SETUP_SPARC64 +#define grub_target_to_host16(x) grub_be_to_cpu16(x) +#define grub_target_to_host32(x) grub_be_to_cpu32(x) +#define grub_target_to_host64(x) grub_be_to_cpu64(x) +#define grub_host_to_target16(x) grub_cpu_to_be16(x) +#define grub_host_to_target32(x) grub_cpu_to_be32(x) +#define grub_host_to_target64(x) grub_cpu_to_be64(x) +#elif defined (GRUB_SETUP_BIOS) +#define grub_target_to_host16(x) grub_le_to_cpu16(x) +#define grub_target_to_host32(x) grub_le_to_cpu32(x) +#define grub_target_to_host64(x) grub_le_to_cpu64(x) +#define grub_host_to_target16(x) grub_cpu_to_le16(x) +#define grub_host_to_target32(x) grub_cpu_to_le32(x) +#define grub_host_to_target64(x) grub_cpu_to_le64(x) +#else +#error Complete this +#endif + +static void +write_rootdev (grub_device_t root_dev, + char *boot_img, grub_uint64_t first_sector) +{ +#ifdef GRUB_SETUP_BIOS + { + grub_uint8_t *boot_drive; + void *kernel_sector; + boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE); + kernel_sector = (boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR); + + /* FIXME: can this be skipped? */ + *boot_drive = 0xFF; + + grub_set_unaligned64 (kernel_sector, grub_cpu_to_le64 (first_sector)); + } +#endif +#ifdef GRUB_SETUP_SPARC64 + { + void *kernel_byte; + kernel_byte = (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE + + GRUB_BOOT_MACHINE_KERNEL_BYTE); + grub_set_unaligned64 (kernel_byte, + grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS)); + } +#endif +} + +#ifdef GRUB_SETUP_SPARC64 +#define BOOT_SECTOR 1 +#else +#define BOOT_SECTOR 0 +#endif + +/* Helper for setup. */ + +struct blocklists +{ + struct grub_boot_blocklist *first_block, *block; +#ifdef GRUB_SETUP_BIOS + grub_uint16_t current_segment; +#endif +#ifdef GRUB_SETUP_SPARC64 + grub_uint64_t gpt_offset; +#endif + grub_uint16_t last_length; + grub_disk_addr_t first_sector; +}; + +/* Helper for setup. */ +static void +save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length, + void *data) +{ + struct blocklists *bl = data; + struct grub_boot_blocklist *prev = bl->block + 1; + grub_uint64_t seclen; + +#ifdef GRUB_SETUP_SPARC64 + sector -= bl->gpt_offset; +#endif + + grub_util_info ("saving <%" GRUB_HOST_PRIuLONG_LONG ",%u,%u>", + (unsigned long long) sector, offset, length); + + if (bl->first_sector == (grub_disk_addr_t) -1) + { + if (offset != 0 || length < GRUB_DISK_SECTOR_SIZE) + grub_util_error ("%s", _("the first sector of the core file is not sector-aligned")); + + bl->first_sector = sector; + sector++; + length -= GRUB_DISK_SECTOR_SIZE; + if (!length) + return; + } + + if (offset != 0 || bl->last_length != 0) + grub_util_error ("%s", _("non-sector-aligned data is found in the core file")); + + seclen = (length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS; + + if (bl->block != bl->first_block + && (grub_target_to_host64 (prev->start) + + grub_target_to_host16 (prev->len)) == sector) + { + grub_uint16_t t = grub_target_to_host16 (prev->len); + t += seclen; + prev->len = grub_host_to_target16 (t); + } + else + { + bl->block->start = grub_host_to_target64 (sector); + bl->block->len = grub_host_to_target16 (seclen); +#ifdef GRUB_SETUP_BIOS + bl->block->segment = grub_host_to_target16 (bl->current_segment); +#endif + + bl->block--; + if (bl->block->len) + grub_util_error ("%s", _("the sectors of the core file are too fragmented")); + } + + bl->last_length = length & (GRUB_DISK_SECTOR_SIZE - 1); +#ifdef GRUB_SETUP_BIOS + bl->current_segment += seclen << (GRUB_DISK_SECTOR_BITS - 4); +#endif +} + +/* Context for setup/identify_partmap. */ +struct identify_partmap_ctx +{ + grub_partition_map_t dest_partmap; + grub_partition_t container; + int multiple_partmaps; +}; + +/* Helper for setup. + Unlike root_dev, with dest_dev we're interested in the partition map even + if dest_dev itself is a whole disk. */ +static int +identify_partmap (grub_disk_t disk __attribute__ ((unused)), + const grub_partition_t p, void *data) +{ + struct identify_partmap_ctx *ctx = data; + + if (p->parent != ctx->container) + return 0; + /* NetBSD and OpenBSD subpartitions have metadata inside a partition, + so they are safe to ignore. + */ + if (grub_strcmp (p->partmap->name, "netbsd") == 0 + || grub_strcmp (p->partmap->name, "openbsd") == 0) + return 0; + if (ctx->dest_partmap == NULL) + { + ctx->dest_partmap = p->partmap; + return 0; + } + if (ctx->dest_partmap == p->partmap) + return 0; + ctx->multiple_partmaps = 1; + return 1; +} + +#ifdef GRUB_SETUP_BIOS +#define SETUP grub_util_bios_setup +#elif GRUB_SETUP_SPARC64 +#define SETUP grub_util_sparc_setup +#else +#error "Shouldn't happen" +#endif + +void +SETUP (const char *dir, + const char *boot_file, const char *core_file, + const char *dest, int force, + int fs_probe, int allow_floppy, + int add_rs_codes __attribute__ ((unused))) /* unused on sparc64 */ +{ + char *core_path; + char *boot_img, *core_img, *boot_path; + char *root = 0; + size_t boot_size, core_size; + grub_uint16_t core_sectors; + grub_device_t root_dev = 0, dest_dev, core_dev; + grub_util_fd_t fp; + struct blocklists bl; + + bl.first_sector = (grub_disk_addr_t) -1; + +#ifdef GRUB_SETUP_BIOS + bl.current_segment = + GRUB_BOOT_I386_PC_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4); +#endif + bl.last_length = 0; + + /* Read the boot image by the OS service. */ + boot_path = grub_util_get_path (dir, boot_file); + boot_size = grub_util_get_image_size (boot_path); + if (boot_size != GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("the size of `%s' is not %u"), + boot_path, GRUB_DISK_SECTOR_SIZE); + boot_img = grub_util_read_image (boot_path); + free (boot_path); + + core_path = grub_util_get_path (dir, core_file); + core_size = grub_util_get_image_size (core_path); + core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) + >> GRUB_DISK_SECTOR_BITS); + if (core_size < GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("the size of `%s' is too small"), core_path); +#ifdef GRUB_SETUP_BIOS + if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE) + grub_util_error (_("the size of `%s' is too large"), core_path); +#endif + + core_img = grub_util_read_image (core_path); + + /* Have FIRST_BLOCK to point to the first blocklist. */ + bl.first_block = (struct grub_boot_blocklist *) (core_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*bl.block)); + + grub_util_info ("Opening dest `%s'", dest); + dest_dev = grub_device_open (dest); + if (! dest_dev) + grub_util_error ("%s", grub_errmsg); + + core_dev = dest_dev; + + { + char **root_devices = grub_guess_root_devices (dir); + char **cur; + int found = 0; + + if (!root_devices) + grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), dir); + + for (cur = root_devices; *cur; cur++) + { + char *drive; + grub_device_t try_dev; + + drive = grub_util_get_grub_dev (*cur); + if (!drive) + continue; + try_dev = grub_device_open (drive); + if (! try_dev) + { + free (drive); + continue; + } + if (!found && try_dev->disk->id == dest_dev->disk->id + && try_dev->disk->dev->id == dest_dev->disk->dev->id) + { + if (root_dev) + grub_device_close (root_dev); + free (root); + root_dev = try_dev; + root = drive; + found = 1; + continue; + } + if (!root_dev) + { + root_dev = try_dev; + root = drive; + continue; + } + grub_device_close (try_dev); + free (drive); + } + if (!root_dev) + { + root = grub_util_get_grub_dev ("/dev/sda"); + root_dev = grub_device_open (root); + if (root_dev) + grub_util_info ("guessing the root device failed, because of `%s'", grub_errmsg); + else + grub_util_error ("guessing the root device failed, because of `%s'", grub_errmsg); + } + grub_util_info ("guessed root_dev `%s' from " + "dir `%s'", root_dev->disk->name, dir); + + for (cur = root_devices; *cur; cur++) + free (*cur); + free (root_devices); + } + + grub_util_info ("setting the root device to `%s'", root); + if (grub_env_set ("root", root) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); + + { +#ifdef GRUB_SETUP_BIOS + char *tmp_img; + grub_uint8_t *boot_drive_check; + + /* Read the original sector from the disk. */ + tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE); + if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img)) + grub_util_error ("%s", grub_errmsg); + + boot_drive_check = (grub_uint8_t *) (boot_img + + GRUB_BOOT_MACHINE_DRIVE_CHECK); + /* Copy the possible DOS BPB. */ + memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START, + tmp_img + GRUB_BOOT_MACHINE_BPB_START, + GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START); + + /* If DEST_DRIVE is a hard disk, enable the workaround, which is + for buggy BIOSes which don't pass boot drive correctly. Instead, + they pass 0x00 or 0x01 even when booted from 0x80. */ + if (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)) + { + /* Replace the jmp (2 bytes) with double nop's. */ + boot_drive_check[0] = 0x90; + boot_drive_check[1] = 0x90; + } +#endif + + struct identify_partmap_ctx ctx = { + .dest_partmap = NULL, + .container = dest_dev->disk->partition, + .multiple_partmaps = 0 + }; + int is_ldm; + grub_err_t err; + grub_disk_addr_t *sectors; + int i; + grub_fs_t fs; + unsigned int nsec, maxsec; + + grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx); + +#ifdef GRUB_SETUP_BIOS + /* Copy the partition table. */ + if (ctx.dest_partmap || + (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))) + memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, + tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, + GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC); + + free (tmp_img); +#endif + + if (ctx.container + && grub_strcmp (ctx.container->partmap->name, "msdos") == 0 + && ctx.dest_partmap + && (ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD + || ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD)) + { + grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet.")); + goto unable_to_embed; + } + + fs = grub_fs_probe (dest_dev); + if (!fs) + grub_errno = GRUB_ERR_NONE; + + is_ldm = grub_util_is_ldm (dest_dev->disk); + + if (fs_probe) + { + if (!fs && !ctx.dest_partmap) + grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"), + dest_dev->disk->name); + if (fs && !fs->reserved_first_sector) + /* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it. */ + grub_util_error (_("%s appears to contain a %s filesystem which isn't known to " + "reserve space for DOS-style boot. Installing GRUB there could " + "result in FILESYSTEM DESTRUCTION if valuable data is overwritten " + "by grub-setup (--skip-fs-probe disables this " + "check, use at your own risk)"), dest_dev->disk->name, fs->name); + + if (ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0 + && strcmp (ctx.dest_partmap->name, "gpt") != 0 + && strcmp (ctx.dest_partmap->name, "bsd") != 0 + && strcmp (ctx.dest_partmap->name, "netbsd") != 0 + && strcmp (ctx.dest_partmap->name, "openbsd") != 0 + && strcmp (ctx.dest_partmap->name, "sunpc") != 0) + /* TRANSLATORS: Partition map may reserve the space just GRUB isn't sure about it. */ + grub_util_error (_("%s appears to contain a %s partition map which isn't known to " + "reserve space for DOS-style boot. Installing GRUB there could " + "result in FILESYSTEM DESTRUCTION if valuable data is overwritten " + "by grub-setup (--skip-fs-probe disables this " + "check, use at your own risk)"), dest_dev->disk->name, ctx.dest_partmap->name); + if (is_ldm && ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0 + && strcmp (ctx.dest_partmap->name, "gpt") != 0) + grub_util_error (_("%s appears to contain a %s partition map and " + "LDM which isn't known to be a safe combination." + " Installing GRUB there could " + "result in FILESYSTEM DESTRUCTION if valuable data" + " is overwritten " + "by grub-setup (--skip-fs-probe disables this " + "check, use at your own risk)"), + dest_dev->disk->name, ctx.dest_partmap->name); + + } + + if (! ctx.dest_partmap && ! fs && !is_ldm) + { + grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea.")); + goto unable_to_embed; + } + if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs)) + { + grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet.")); + goto unable_to_embed; + } + + if (ctx.dest_partmap && !ctx.dest_partmap->embed) + { + grub_util_warn (_("Partition style `%s' doesn't support embedding"), + ctx.dest_partmap->name); + goto unable_to_embed; + } + + if (fs && !fs->fs_embed) + { + grub_util_warn (_("File system `%s' doesn't support embedding"), + fs->name); + goto unable_to_embed; + } + + nsec = core_sectors; + + if (add_rs_codes) + maxsec = 2 * core_sectors; + else + maxsec = core_sectors; + +#ifdef GRUB_SETUP_BIOS + if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) + >> GRUB_DISK_SECTOR_BITS)) + maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR) + >> GRUB_DISK_SECTOR_BITS); +#endif + +#ifdef GRUB_SETUP_SPARC64 + /* + * On SPARC we need two extra. One is because we are combining the + * core.img with the boot.img. The other is because the boot sector + * starts at 1. + */ + nsec += 2; + maxsec += 2; +#endif + + if (is_ldm) + err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec, + GRUB_EMBED_PCBIOS, §ors); + else if (ctx.dest_partmap) + err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec, + GRUB_EMBED_PCBIOS, §ors); + else + err = fs->fs_embed (dest_dev, &nsec, maxsec, + GRUB_EMBED_PCBIOS, §ors); + if (!err && nsec < core_sectors) + { + err = grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("Your embedding area is unusually small. " + "core.img won't fit in it.")); + } + + if (err) + { + grub_util_warn ("%s", grub_errmsg); + grub_errno = GRUB_ERR_NONE; + goto unable_to_embed; + } + + assert (nsec <= maxsec); + + /* Clean out the blocklists. */ + bl.block = bl.first_block; + while (bl.block->len) + { + grub_memset (bl.block, 0, sizeof (*bl.block)); + + bl.block--; + + if ((char *) bl.block <= core_img) + grub_util_error ("%s", _("no terminator in the core image")); + } + + bl.block = bl.first_block; + for (i = 0; i < nsec; i++) + save_blocklists (sectors[i] + grub_partition_get_start (ctx.container), + 0, GRUB_DISK_SECTOR_SIZE, &bl); + + /* Make sure that the last blocklist is a terminator. */ + if (bl.block == bl.first_block) + bl.block--; + bl.block->start = 0; + bl.block->len = 0; +#ifdef GRUB_SETUP_BIOS + bl.block->segment = 0; +#endif + +#ifdef GRUB_SETUP_SPARC64 + { + /* + * On SPARC, the block-list entries need to be based off the beginning + * of the parition, not the beginning of the disk. + */ + struct grub_boot_blocklist *block; + block = bl.first_block; + + while (block->len) + { + block->start -= bl.first_sector; + block--; + } + } + + /* + * Reserve space for the boot block since it can not be in the + * Parition table on SPARC. + */ + assert (bl.first_block->len > 2); + bl.first_block->start += 2; + bl.first_block->len -= 2; + write_rootdev (root_dev, boot_img, sectors[BOOT_SECTOR + 1] - bl.first_sector); +#endif + +#ifdef GRUB_SETUP_BIOS + write_rootdev (root_dev, boot_img, bl.first_sector); +#endif + + /* Round up to the nearest sector boundary, and zero the extra memory */ + core_img = xrealloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE); + assert (core_img && (nsec * GRUB_DISK_SECTOR_SIZE >= core_size)); + memset (core_img + core_size, 0, nsec * GRUB_DISK_SECTOR_SIZE - core_size); + + bl.first_block = (struct grub_boot_blocklist *) (core_img + + GRUB_DISK_SECTOR_SIZE + - sizeof (*bl.block)); +#if GRUB_SETUP_BIOS + grub_size_t no_rs_length; + no_rs_length = grub_target_to_host16 + (grub_get_unaligned16 (core_img + + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH)); + + if (no_rs_length == 0xffff) + grub_util_error ("%s", _("core.img version mismatch")); + + if (add_rs_codes) + { + grub_set_unaligned32 ((core_img + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY), + grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size)); + + void *tmp = xmalloc (core_size); + grub_memcpy (tmp, core_img, core_size); + grub_reed_solomon_add_redundancy (core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE, + core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE, + nsec * GRUB_DISK_SECTOR_SIZE + - core_size); + assert (grub_memcmp (tmp, core_img, core_size) == 0); + free (tmp); + } + + /* Write the core image onto the disk. */ + for (i = 0; i < nsec; i++) + grub_disk_write (dest_dev->disk, sectors[i], 0, + GRUB_DISK_SECTOR_SIZE, + core_img + i * GRUB_DISK_SECTOR_SIZE); +#endif + +#ifdef GRUB_SETUP_SPARC64 + { + int isec = BOOT_SECTOR; + + /* Write the boot image onto the disk. */ + if (grub_disk_write (dest_dev->disk, sectors[isec++], 0, + GRUB_DISK_SECTOR_SIZE, boot_img)) + grub_util_error ("%s", grub_errmsg); + + /* Write the core image onto the disk. */ + for (i = 0 ; isec < nsec; i++, isec++) + { + if (grub_disk_write (dest_dev->disk, sectors[isec], 0, + GRUB_DISK_SECTOR_SIZE, + core_img + i * GRUB_DISK_SECTOR_SIZE)) + grub_util_error ("%s", grub_errmsg); + } + } + +#endif + grub_free (sectors); + + goto finish; + } + +unable_to_embed: + + if (dest_dev->disk->dev->id != root_dev->disk->dev->id) + grub_util_error ("%s", _("embedding is not possible, but this is required for " + "RAID and LVM install")); + + { + grub_fs_t fs; + fs = grub_fs_probe (root_dev); + if (!fs) + grub_util_error (_("can't determine filesystem on %s"), root); + + if (!fs->blocklist_install) + grub_util_error (_("filesystem `%s' doesn't support blocklists"), + fs->name); + } + +#ifdef GRUB_SETUP_BIOS + if (dest_dev->disk->id != root_dev->disk->id + || dest_dev->disk->dev->id != root_dev->disk->dev->id) + /* TRANSLATORS: cross-disk refers to /boot being on one disk + but MBR on another. */ + grub_util_error ("%s", _("embedding is not possible, but this is required for " + "cross-disk install")); +#else + core_dev = root_dev; +#endif + + grub_util_warn ("%s", _("Embedding is not possible. GRUB can only be installed in this " + "setup by using blocklists. However, blocklists are UNRELIABLE and " + "their use is discouraged.")); + if (! force) + /* TRANSLATORS: Here GRUB refuses to continue with blocklist install. */ + grub_util_error ("%s", _("will not proceed with blocklists")); + + /* The core image must be put on a filesystem unfortunately. */ + grub_util_info ("will leave the core image on the filesystem"); + + grub_util_biosdisk_flush (root_dev->disk); + + /* Clean out the blocklists. */ + bl.block = bl.first_block; + while (bl.block->len) + { + bl.block->start = 0; + bl.block->len = 0; +#ifdef GRUB_SETUP_BIOS + bl.block->segment = 0; +#endif + + bl.block--; + + if ((char *) bl.block <= core_img) + grub_util_error ("%s", _("no terminator in the core image")); + } + + bl.block = bl.first_block; + +#ifdef GRUB_SETUP_SPARC64 + { + grub_partition_t container = root_dev->disk->partition; + bl.gpt_offset = 0; + + if (grub_strstr (container->partmap->name, "gpt")) + bl.gpt_offset = grub_partition_get_start (container); + } +#endif + + grub_install_get_blocklist (root_dev, core_path, core_img, core_size, + save_blocklists, &bl); + + if (bl.first_sector == (grub_disk_addr_t)-1) + grub_util_error ("%s", _("can't retrieve blocklists")); + +#ifdef GRUB_SETUP_SPARC64 + { + char *boot_devpath; + boot_devpath = (char *) (boot_img + + GRUB_BOOT_AOUT_HEADER_SIZE + + GRUB_BOOT_MACHINE_BOOT_DEVPATH); + if (dest_dev->disk->id != root_dev->disk->id + || dest_dev->disk->dev->id != root_dev->disk->dev->id) + { + char *dest_ofpath; + dest_ofpath + = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk)); + /* FIXME handle NULL result */ + grub_util_info ("dest_ofpath is `%s'", dest_ofpath); + strncpy (boot_devpath, dest_ofpath, + GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1); + boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0; + free (dest_ofpath); + } + else + { + grub_util_info ("non cross-disk install"); + memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH); + } + grub_util_info ("boot device path %s", boot_devpath); + } +#endif + + write_rootdev (root_dev, boot_img, bl.first_sector); + + /* Write the first two sectors of the core image onto the disk. */ + grub_util_info ("opening the core image `%s'", core_path); + fp = grub_util_fd_open (core_path, GRUB_UTIL_FD_O_WRONLY); + if (! GRUB_UTIL_FD_IS_VALID (fp)) + grub_util_error (_("cannot open `%s': %s"), core_path, + grub_util_fd_strerror ()); + + if (grub_util_fd_write (fp, core_img, GRUB_DISK_SECTOR_SIZE * 2) + != GRUB_DISK_SECTOR_SIZE * 2) + grub_util_error (_("cannot write to `%s': %s"), + core_path, strerror (errno)); + if (grub_util_fd_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), core_path, strerror (errno)); + if (grub_util_fd_close (fp) < 0) + grub_util_error (_("cannot close `%s': %s"), core_path, strerror (errno)); + grub_util_biosdisk_flush (root_dev->disk); + + grub_disk_cache_invalidate_all (); + + { + char *buf, *ptr = core_img; + size_t len = core_size; + grub_uint64_t blk, offset = 0; + grub_partition_t container = core_dev->disk->partition; + grub_err_t err; + + core_dev->disk->partition = 0; +#ifdef GRUB_SETUP_SPARC64 + offset = bl.gpt_offset; +#endif + + buf = xmalloc (core_size); + blk = bl.first_sector; + err = grub_disk_read (core_dev->disk, blk + offset, 0, GRUB_DISK_SECTOR_SIZE, buf); + if (err) + grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name, + grub_errmsg); + if (grub_memcmp (buf, ptr, GRUB_DISK_SECTOR_SIZE) != 0) + grub_util_error ("%s", _("blocklists are invalid")); + + ptr += GRUB_DISK_SECTOR_SIZE; + len -= GRUB_DISK_SECTOR_SIZE; + + bl.block = bl.first_block; + while (bl.block->len) + { + size_t cur = grub_target_to_host16 (bl.block->len) << GRUB_DISK_SECTOR_BITS; + blk = grub_target_to_host64 (bl.block->start); + + if (cur > len) + cur = len; + + err = grub_disk_read (core_dev->disk, blk + offset, 0, cur, buf); + if (err) + grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name, + grub_errmsg); + + if (grub_memcmp (buf, ptr, cur) != 0) + grub_util_error ("%s", _("blocklists are invalid")); + + ptr += cur; + len -= cur; + bl.block--; + + if ((char *) bl.block <= core_img) + grub_util_error ("%s", _("no terminator in the core image")); + } + if (len) + grub_util_error ("%s", _("blocklists are incomplete")); + core_dev->disk->partition = container; + free (buf); + } + +#ifdef GRUB_SETUP_BIOS + finish: +#endif + + /* Write the boot image onto the disk. */ + if (grub_disk_write (dest_dev->disk, BOOT_SECTOR, + 0, GRUB_DISK_SECTOR_SIZE, boot_img)) + grub_util_error ("%s", grub_errmsg); + +#ifdef GRUB_SETUP_SPARC64 + finish: +#endif + + grub_util_biosdisk_flush (root_dev->disk); + grub_util_biosdisk_flush (dest_dev->disk); + + free (core_path); + free (core_img); + free (boot_img); + grub_device_close (dest_dev); + grub_device_close (root_dev); +} + diff --git a/Ventoy-src/GRUB2/buildgrub.sh b/Ventoy-src/GRUB2/buildgrub.sh new file mode 100644 index 0000000..1ddc089 --- /dev/null +++ b/Ventoy-src/GRUB2/buildgrub.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +VT_GRUB_DIR=$PWD + +rm -rf INSTALL +rm -rf SRC +rm -rf NBP +rm -rf PXE + +mkdir SRC +mkdir NBP +mkdir PXE + +tar -xf grub-2.04.tar.xz -C ./SRC/ + +/bin/cp -a ./MOD_SRC/grub-2.04 ./SRC/ + +cd ./SRC/grub-2.04 + + +# build for x86_64-efi +echo '======== build grub2 for x86_64-efi ===============' +make distclean +./autogen.sh +./configure --with-platform=efi --prefix=$VT_GRUB_DIR/INSTALL/ +make -j 16 || exit 1 +sh install.sh uefi + + +#build for i386-efi +echo '======== build grub2 for i386-efi ===============' +make distclean +./autogen.sh +./configure --target=i386 --with-platform=efi --prefix=$VT_GRUB_DIR/INSTALL/ +make -j 16 || exit 1 +sh install.sh i386efi + + + +#build for arm64 EFI +echo '======== build grub2 for arm64-efi ===============' +PATH=$PATH:/opt/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu/bin +make distclean +./autogen.sh +./configure --prefix=$VT_GRUB_DIR/INSTALL/ \ +--target=aarch64 --with-platform=efi \ +--host=x86_64-linux-gnu \ +HOST_CC=x86_64-linux-gnu-gcc \ +BUILD_CC=gcc \ +TARGET_CC=aarch64-linux-gnu-gcc \ +TARGET_OBJCOPY=aarch64-linux-gnu-objcopy \ +TARGET_STRIP=aarch64-linux-gnu-strip TARGET_NM=aarch64-linux-gnu-nm \ +TARGET_RANLIB=aarch64-linux-gnu-ranlib +make -j 16 || exit 1 +sh install.sh arm64 + + +#build for mips64el EFI +#http://ftp.loongnix.org/os/loongnix-server/1.7/os/Source/SPackages/grub2-2.02-0.40.lns7.14.loongnix.src.rpm +make distclean +./autogen.sh +./configure --prefix=/home/share/Ventoy/GRUB2/INSTALL/ \ +--target=mips64el --with-platform=efi \ +--host=x86_64-linux-gnu \ +HOST_CC=x86_64-linux-gnu-gcc \ +BUILD_CC=gcc \ +TARGET_CC="mips-linux-gnu-gcc -mabi=64 -Wno-error=cast-align -Wno-error=misleading-indentation" \ +TARGET_OBJCOPY=mips-linux-gnu-objcopy \ +TARGET_STRIP=mips-linux-gnu-strip TARGET_NM=mips-linux-gnu-nm \ +TARGET_RANLIB=mips-linux-gnu-ranlib +make -j 16 || exit 1 +sh install.sh mips64el + + + +# build for i386-pc +echo '======== build grub2 for i386-pc ===============' +make distclean +./autogen.sh +./configure --target=i386 --with-platform=pc --prefix=$VT_GRUB_DIR/INSTALL/ +make -j 16 || exit 1 +sh install.sh + + + +cd ../../ + diff --git a/Ventoy-src/README.md b/Ventoy-src/README.md new file mode 100644 index 0000000..5619fcc --- /dev/null +++ b/Ventoy-src/README.md @@ -0,0 +1,149 @@ +

+ Ventoy +

+ +

+ + + + + +

+ +

+Ventoy is an open source tool to create bootable USB drive for ISO/WIM/IMG/VHD(x)/EFI files.
+With Ventoy, you don't need to format the disk over and over, just copy the image files to the USB drive and boot them. +You can copy many image files at a time and Ventoy will give you a boot menu to select them.
+You can also browse ISO/WIM/IMG/VHD(x)/EFI files in local disk and boot them.
+x86 Legacy BIOS, IA32 UEFI, x86_64 UEFI, ARM64 UEFI and MIPS64EL UEFI are supported in the same way.
+Both MBR and GPT partition style are supported in the same way.
+Most type of OS supported(Windows/WinPE/Linux/Unix/ChromeOS/Vmware/Xen...)
+ 1300+ ISO files are tested (List). 90%+ distros in distrowatch.com supported (Details).
+
Official Website: https://www.ventoy.net +

+ +# Tested OS +**Windows** +Windows 7, Windows 8, Windows 8.1, Windows 10, Windows 11, Windows Server 2012, Windows Server 2012 R2, Windows Server 2016, Windows Server 2019, Windows Server 2022, Windows Server 2025, WinPE + +**Linux** +Debian, Ubuntu, CentOS(6/7/8/9/10), RHEL(6/7/8/9/10), Deepin, Fedora, Rocky Linux, AlmaLinux, EuroLinux(6/7/8/9), openEuler, OpenAnolis, SLES, openSUSE, MX Linux, Manjaro, Linux Mint, Endless OS, Elementary OS, Solus, Linx, Zorin, antiX, PClinuxOS, Arch, ArcoLinux, ArchLabs, BlackArch, Obarun, Artix Linux, Puppy Linux, Tails, Slax, Kali, Mageia, Slackware, Q4OS, Archman, Gentoo, Pentoo, NixOS, Kylin, openKylin, Ubuntu Kylin, KylinSec, Lubuntu, Xubuntu, Kubuntu, Ubuntu MATE, Ubuntu Budgie, Ubuntu Studio, Bluestar, OpenMandriva, ExTiX, Netrunner, ALT Linux, Nitrux, Peppermint, KDE neon, Linux Lite, Parrot OS, Qubes, Pop OS, ROSA, Void Linux, Star Linux, EndeavourOS, MakuluLinux, Voyager, Feren, ArchBang, LXLE, Knoppix, Calculate Linux, Clear Linux, Pure OS, Oracle Linux, Trident, Septor, Porteus, Devuan, GoboLinux, 4MLinux, Simplicity Linux, Zeroshell, Android-x86, netboot.xyz, Slitaz, SuperGrub2Disk, Proxmox VE, Kaspersky Rescue, SystemRescueCD, MemTest86, MemTest86+, MiniTool Partition Wizard, Parted Magic, veket, Sabayon, Scientific, alpine, ClearOS, CloneZilla, Berry Linux, Trisquel, Ataraxia Linux, Minimal Linux Live, BackBox Linux, Emmabuntüs, ESET SysRescue Live,Nova Linux, AV Linux, RoboLinux, NuTyX, IPFire, SELKS, ZStack, Enso Linux, Security Onion, Network Security Toolkit, Absolute Linux, TinyCore, Springdale Linux, Frost Linux, Shark Linux, LinuxFX, Snail Linux, Astra Linux, Namib Linux, Resilient Linux, Virage Linux, Blackweb Security OS, R-DriveImage, O-O.DiskImage, Macrium, ToOpPy LINUX, GNU Guix, YunoHost, foxclone, siduction, Adelie Linux, Elive, Pardus, CDlinux, AcademiX, Austrumi, Zenwalk, Anarchy, DuZeru, BigLinux, OpenMediaVault, Ubuntu DP, Exe GNU/Linux, 3CX Phone System, KANOTIX, Grml, Karoshi, PrimTux, ArchStrike, CAELinux, Cucumber, Fatdog, ForLEx, Hanthana, Kwort, MiniNo, Redcore, Runtu, Asianux, Clu Linux Live, Uruk, OB2D, BlueOnyx, Finnix, HamoniKR, Parabola, LinHES, LinuxConsole, BEE free, Untangle, Pearl, Thinstation, TurnKey, tuxtrans, Neptune, HefftorLinux, GeckoLinux, Mabox Linux, Zentyal, Maui, Reborn OS, SereneLinux , SkyWave Linux, Kaisen Linux, Regata OS, TROM-Jaro, DRBL Linux, Chalet OS, Chapeau, Desa OS, BlankOn, OpenMamba, Frugalware, Kibojoe Linux, Revenge OS, Tsurugi Linux, Drauger OS, Hash Linux, gNewSense, Ikki Boot, SteamOS, Hyperbola, VyOS, EasyNAS, SuperGamer, Live Raizo, Swift Linux, RebeccaBlackOS, Daphile, CRUX, Univention, Ufficio Zero, Rescuezilla, Phoenix OS, Garuda Linux, Mll, NethServer, OSGeoLive, Easy OS, Volumio, FreedomBox, paldo, UBOS, Recalbox, batocera, Lakka, LibreELEC, Pardus Topluluk, Pinguy, KolibriOS, Elastix, Arya, Omoikane, Omarine, Endian Firewall, Hamara, Rocks Cluster, MorpheusArch, Redo, Slackel, SME Server, APODIO, Smoothwall, Dragora, Linspire, Secure-K OS, Peach OSI, Photon, Plamo, SuperX, Bicom, Ploplinux, HP SPP, LliureX, Freespire, DietPi, BOSS, Webconverger, Lunar, TENS, Source Mage, RancherOS, T2, Vine, Pisi, blackPanther, mAid, Acronis, Active.Boot, AOMEI, Boot.Repair, CAINE, DaRT, EasyUEFI, R-Drive, PrimeOS, Avira Rescue System, bitdefender, Checkra1n Linux, Lenovo Diagnostics, Clover, Bliss-OS, Lenovo BIOS Update, Arcabit Rescue Disk, MiyoLinux, TeLOS, Kerio Control, RED OS, OpenWrt, MocaccinoOS, EasyStartup, Pyabr, Refracta, Eset SysRescue, Linpack Xtreme, Archcraft, NHVBOOT, pearOS, SeaTools, Easy Recovery Essentional, iKuai, StorageCraft SCRE, ZFSBootMenu, TROMjaro, BunsenLabs, Todo en Uno, ChallengerOS, Nobara, Holo, CachyOS, Peux OS, Vanilla OS, ShredOS, paladin, Palen1x, dban, ReviOS, HelenOS, XeroLinux, Tiny 11, chimera linux, CuteFish, DragonOs, Rhino Linux, vanilladpup, crystal, IGELOS, MiniOS, gnoppix, PikaOS, UwUntu, Noble, PocketHandyBox, DiskGenius, Commodore, Talos, Shebang Linux, hrmpf, Bazzite, ManualLinux, nyarchlinux, ultramarine, TempleOS, bluefin, Damn Small Linux, Kicksecure, SerentiyOS, AerynOS, ...... + +**Unix** +DragonFly, FreeBSD, pfSense, OPNsense, GhostBSD, FreeNAS, TrueNAS, XigmaNAS, FuryBSD, HardenedBSD, MidnightBSD, ClonOS, EmergencyBootKit, helloSystem + +**ChromeOS** +FydeOS, CloudReady, ChromeOS Flex, ThoriumOS + +**Other** +VMware ESXi, Citrix XenServer, Xen XCP-ng + + +# Tested Image Report +[【How to report a successfully tested image file】](https://github.com/ventoy/Ventoy/issues/1195) + +# Ventoy Browser +With Ventoy, you can also browse ISO/WIM/IMG/VHD(x)/EFI files in local disk and boot them. [Notes](https://www.ventoy.net/en/doc_browser.html) + +# VentoyPlugson +A GUI Ventoy plugin configurator. [VentoyPlugson](https://www.ventoy.net/en/plugin_plugson.html) + +# Features +* 100% open source +* Simple to use +* Fast (limited only by the speed of copying iso file) +* Can be installed in USB/Local Disk/SSD/NVMe/SD Card +* Directly boot from ISO/WIM/IMG/VHD(x)/EFI files, no extraction needed +* Support to browse and boot ISO/WIM/IMG/VHD(x)/EFI files in local disk +* No need to be continuous in disk for ISO/WIM/IMG/VHD(x)/EFI files +* MBR and GPT partition style supported (1.0.15+) +* x86 Legacy BIOS, IA32 UEFI, x86_64 UEFI, ARM64 UEFI, MIPS64EL UEFI supported +* IA32/x86_64 UEFI Secure Boot supported (1.0.07+) +* Linux Persistence supported (1.0.11+) +* Windows auto installation supported (1.0.09+) +* Linux auto installation supported (1.0.09+) +* Variables Expansion supported for Windows/Linux auto installation script +* FAT32/exFAT/NTFS/UDF/XFS/Btrfs/Ext2(3)(4) supported for main partition +* ISO files larger than 4GB supported +* Menu alias, Menu tip message supported +* Password protect supported +* Native boot menu style for Legacy & UEFI +* Most types of OS supported, 1300+ iso files tested +* Linux vDisk boot supported +* Not only boot but also complete installation process +* Menu dynamically switchable between List/TreeView mode +* "Ventoy Compatible" concept +* Plugin Framework and GUI plugin configurator +* Injection files to runtime environment +* Boot configuration file dynamically replacement +* Highly customizable theme and menu +* USB drive write-protected support +* USB normal use unaffected +* Data nondestructive during version upgrade +* No need to update Ventoy when a new distro is released + +![avatar](https://www.ventoy.net/static/img/screen/screen_uefi.png) + + +# Installation Instructions +See [https://www.ventoy.net/en/doc_start.html](https://www.ventoy.net/en/doc_start.html) for detailed instructions. + +# Compile Instructions +Please refer to [BuildVentoyFromSource.txt](DOC/BuildVentoyFromSource.txt) + +# Document +Title | Link +-|- +**Install & Update** | [https://www.ventoy.net/en/doc_start.html](https://www.ventoy.net/en/doc_start.html) +**Browse/Boot Files In Local Disk** | [https://www.ventoy.net/en/doc_browser.html](https://www.ventoy.net/en/doc_browser.html) +**Secure Boot** | [https://www.ventoy.net/en/doc_secure.html](https://www.ventoy.net/en/doc_secure.html) +**Customize Theme** | [https://www.ventoy.net/en/plugin_theme.html](https://www.ventoy.net/en/plugin_theme.html) +**Global Control** | [https://www.ventoy.net/en/plugin_control.html](https://www.ventoy.net/en/plugin_control.html) +**Image List** | [https://www.ventoy.net/en/plugin_imagelist.html](https://www.ventoy.net/en/plugin_imagelist.html) +**Auto Installation** | [https://www.ventoy.net/en/plugin_autoinstall.html](https://www.ventoy.net/en/plugin_autoinstall.html) +**Injection Plugin** | [https://www.ventoy.net/en/plugin_injection.html](https://www.ventoy.net/en/plugin_injection.html) +**Persistence Support** | [https://www.ventoy.net/en/plugin_persistence.html](https://www.ventoy.net/en/plugin_persistence.html) +**Boot WIM file** | [https://www.ventoy.net/en/plugin_wimboot.html](https://www.ventoy.net/en/plugin_wimboot.html) +**Windows VHD Boot** | [https://www.ventoy.net/en/plugin_vhdboot.html](https://www.ventoy.net/en/plugin_vhdboot.html) +**Linux vDisk Boot** | [https://www.ventoy.net/en/plugin_vtoyboot.html](https://www.ventoy.net/en/plugin_vtoyboot.html) +**DUD Plugin** | [https://www.ventoy.net/en/plugin_dud.html](https://www.ventoy.net/en/plugin_dud.html) +**Password Plugin** | [https://www.ventoy.net/en/plugin_password.html](https://www.ventoy.net/en/plugin_password.html) +**Conf Replace Plugin** | [https://www.ventoy.net/en/plugin_bootconf_replace.html](https://www.ventoy.net/en/plugin_bootconf_replace.html) +**Menu Class** | [https://www.ventoy.net/en/plugin_menuclass.html](https://www.ventoy.net/en/plugin_menuclass.html) +**Menu Alias** | [https://www.ventoy.net/en/plugin_menualias.html](https://www.ventoy.net/en/plugin_menualias.html) +**Menu Extension** | [https://www.ventoy.net/en/plugin_grubmenu.html](https://www.ventoy.net/en/plugin_grubmenu.html) +**Memdisk Mode** | [https://www.ventoy.net/en/doc_memdisk.html](https://www.ventoy.net/en/doc_memdisk.html) +**TreeView Mode** | [https://www.ventoy.net/en/doc_treeview.html](https://www.ventoy.net/en/doc_treeview.html) +**Disk Layout MBR** | [https://www.ventoy.net/en/doc_disk_layout.html](https://www.ventoy.net/en/doc_disk_layout.html) +**Disk Layout GPT** | [https://www.ventoy.net/en/doc_disk_layout_gpt.html](https://www.ventoy.net/en/doc_disk_layout_gpt.html) +**Search Configuration** | [https://www.ventoy.net/en/doc_search_path.html](https://www.ventoy.net/en/doc_search_path.html) + + +# FAQ +See [https://www.ventoy.net/en/faq.html](https://www.ventoy.net/en/faq.html) for detail + + +# Forum +[https://forums.ventoy.net](https://forums.ventoy.net) + +# Donation +It would be much appreciated if you want to make a small donation to support my work! +Alipay, WeChat Pay, PayPal and Bitcoin are available for donation. You can choose any of them. + +Alipay | WeChat Pay +-|- +| + +**PayPal** +You can transfer to my paypal account `admin@ventoy.net` or just click [https://www.paypal.me/ventoy](https://www.paypal.me/ventoy) + +**Bitcoin** +Bitcoin Address `19mZDWzZgzkHCi9YX9H3fYCUuCHq3W6wfT` + + + + + + + + diff --git a/Ventoy-src/SecureBoot.md b/Ventoy-src/SecureBoot.md new file mode 100644 index 0000000..c550f86 --- /dev/null +++ b/Ventoy-src/SecureBoot.md @@ -0,0 +1,41 @@ + +# Ventoy Secure Boot Policy + +## Why shim +Ventoy is based on grub2 which is in GPL license, so it will not directly get signed with UEFI Certificate. +Like most Linux distros, Ventoy grub2 must be launched by shim when Secure Boot is enabled. +Different is that, Ventoy does not have its own shim and must make use of a third-part shim. +When boot Ventoy with Secure Boot enabled, the shim will not directly boot Ventoy grub because Ventoy grub is not signed with the shim embedded Certificate. +The shim will open the MokManager and we must enroll Ventoy's Secure Boot Key and reboot, then the shim will accept Ventoy grub and boot it. + +## Which shim +I choose a shim file from Rocky Linux because it was signed with both UEFI CA 2011 and UEFI CA 2023. + +## Policy +Now you can boot into Ventoy after you enroll Ventoy Secure Boot Key. +Ventoy provides two secure boot policies. +1. Fully bypass secure boot. + This mode will bypass secure boot which means it will boot any EFI files without check. + This mode enables all features of Ventoy and is the most convenient to use. + However, it also carries certain risks, as the Secure Boot mechanism is effectively bypassed. + You must therefore be fully aware of the risks involved and decide whether to use this mode according to your actual circumstances. + +3. Follow UEFI firmware secure boot policy. + This mode will use the original UEFI secure boot policy to check every EFI file before boot it. + This means you can only boot these EFI files which are signed with UEFI CA (e.g. Windows bootmgr, another shim). + In this mode, certain features of Ventoy are disabled (such as grub2boot mode, insmod, etc.), but this mode is the most secure. + +Policy 1 is the default policy by now. + +If you want to use policy 2, you can set `VTOY_SECURE_BOOT_POLICY` to `1` in Ventoy global control plugin as follows: +(PS: `VTOY_SECURE_BOOT_POLICY` value `0` and `1` correspond to Policy 1 and Policy 2 respectively) + +``` +{ + "control":[ + { "VTOY_SECURE_BOOT_POLICY": "1" } + ] +} +``` + + diff --git a/Ventoy-src/docker-compose.yml b/Ventoy-src/docker-compose.yml new file mode 100644 index 0000000..57acf3d --- /dev/null +++ b/Ventoy-src/docker-compose.yml @@ -0,0 +1,8 @@ +version: '2' + +services: + ventoy: + build: . + privileged: true + volumes: + - .:/ventoy diff --git a/paravis/build-theme-main.py b/paravis/build-theme-main.py new file mode 100644 index 0000000..2fd905f --- /dev/null +++ b/paravis/build-theme-main.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +"""Background (centered layout) + theme.txt + preview.png""" +import argparse +import os +from psd_tools import PSDImage +from PIL import Image, ImageDraw, ImageFont + +parser = argparse.ArgumentParser(description=__doc__) +parser.add_argument('psd', help='layered PSD with the menu background') +parser.add_argument('out', help='output directory') +parser.add_argument('--bar', default=None, + help='selected-row image (default: /sel_bar.png)') +parser.add_argument('--font', default='Montserrat-SemiBold.ttf', + help='TTF used for the preview text') +args = parser.parse_args() + +SRC = args.psd +T = args.out +os.makedirs(T, exist_ok=True) + +KEEP_HEADERS = {'главное меню', 'paravis flash', '© paravis.ru'} +DROP_PIXELS = {'shape and color'} # frame of the right "additional menu" + +psd = PSDImage.open(SRC) + + +def walk(layer): + for ch in layer: + nm = (ch.name or '').strip().lower() + if ch.kind == 'group': + walk(ch) + elif ch.kind == 'type': + if nm not in KEEP_HEADERS: + ch.visible = False + elif ch.kind == 'pixel': + if nm in DROP_PIXELS: + ch.visible = False + + +for layer in psd: + nm = (layer.name or '') + if nm.startswith('ТЕКСТ_БЕЗ_ОБВОДКИ'): + layer.visible = False + elif nm.startswith('ВЫДЕЛЕНЫЕ'): + layer.visible = False + else: + walk(layer) + +bg = psd.composite().convert('RGB') +bg.save(os.path.join(T, 'background.png')) +print('background:', bg.size) + +# ---------------------------------------------------------------- geometry +LEFT, TOP, WIDTH = 202, 100, 620 +ITEM_H, SPACING = 46, 4 +ROWS = [ + ('Super Grub2 (поиск и запуск ОС)', '(1)'), + ('Поиск и запуск Windows 7-11', '(2)'), + ('Установка Windows 7, 10, 11 x64', '(3)'), + ('Ventoy (ISO-образы)', '(4)'), + ('Kaspersky Rescue Disk 18', '(5)'), + None, + ('Windows 10, 11 PE Sergei Strelec', '(6)'), + ('Утилиты для диагностики', '(7)'), + ('Восстановление Windows MSDaRT', '(8)'), + ('Запуск / Установка Linux', '(9)'), + None, + ('Перезагрузка', '(R)'), + ('Выключение', '(S)'), +] +HEIGHT = len(ROWS) * (ITEM_H + SPACING) + +theme = f'''# Paravis Flash - GRUB2 theme (main menu) +desktop-image: "background.png" +desktop-color: "#e9e9e9" +title-text: "" +terminal-font: "Unifont Regular 16" + ++ boot_menu {{ + left = {LEFT} + top = {TOP} + width = {WIDTH} + height = {HEIGHT} + item_font = "Montserrat SemiBold 17" + item_color = "#2b3a55" + selected_item_color = "#ffffff" + item_height = {ITEM_H} + item_spacing = {SPACING} + item_padding = 26 + item_icon_space = 0 + icon_width = 0 + icon_height = 0 + selected_item_pixmap_style = "sel_*.png" + scrollbar = false +}} +''' +open(os.path.join(T, 'theme.txt'), 'w', encoding='utf-8').write(theme) +print('theme.txt written') + +# ---------------------------------------------------------------- preview +bar_path = args.bar or os.path.join(T, 'sel_bar.png') +bar = Image.open(bar_path).convert('RGBA').resize((WIDTH, ITEM_H)) +font = ImageFont.truetype(args.font, 17) +img = bg.copy().convert('RGBA') +d = ImageDraw.Draw(img) +col = max(len(r[0]) for r in ROWS if r) +for i, row in enumerate(ROWS): + y = TOP + i * (ITEM_H + SPACING) + if row is None: + continue + label, num = row + if i == 0: + img.alpha_composite(bar, (LEFT, y)) + color = (255, 255, 255) if i == 0 else (43, 58, 85) + d.text((LEFT + 26, y + ITEM_H / 2), label, font=font, fill=color, anchor='lm') + d.text((LEFT + WIDTH - 22, y + ITEM_H / 2), num, font=font, fill=color, anchor='rm') +img.convert('RGB').save(os.path.join(T, 'preview.png')) +print('preview.png written') diff --git a/paravis/patch-ventoy-lang.sh b/paravis/patch-ventoy-lang.sh new file mode 100644 index 0000000..fde3b23 --- /dev/null +++ b/paravis/patch-ventoy-lang.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e +F=${1:?usage: patch-ventoy-lang.sh } +python3 - "$F" <<'EOF' +import io, sys +p = sys.argv[1] +s = io.open(p, encoding='utf-8', newline='').read() +old = '''if [ -n "$VTOY_MENU_LANGUAGE" ]; then + vt_init_menu_lang "$VTOY_MENU_LANGUAGE" +else + vt_init_menu_lang en_US +fi''' +new = '''if [ -n "$VTOY_MENU_LANGUAGE" ]; then + vt_init_menu_lang "$VTOY_MENU_LANGUAGE" +else + vt_init_menu_lang ru_RU +fi''' +if new in s: + print("already patched") +elif old in s: + s = s.replace(old, new, 1) + io.open(p, 'w', encoding='utf-8', newline='').write(s) + print("patched: default menu language -> ru_RU") +else: + print("BLOCK NOT FOUND") + sys.exit(1) +EOF +grep -n -A3 'VTOY_MENU_LANGUAGE' "$F" | head -12 diff --git a/paravis/patch_ventoy_grubcfg.py b/paravis/patch_ventoy_grubcfg.py new file mode 100644 index 0000000..674446e --- /dev/null +++ b/paravis/patch_ventoy_grubcfg.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +""" +Patch Ventoy 1.1.18 grub.cfg for the custom Xorboot layout: + + * data (ISO) partition is detected by marker file /ISO/Ventoy/NOT.DEL + instead of being hardcoded to partition 1; + * partition numbers are exported to the ventoy GRUB module + (VTOY_DATA_PART_IDX / VTOY_EFI_PART_IDX); + * user config + custom menu live in /ISO/Ventoy/ instead of /ventoy/. + +Usage: + python3 patch_ventoy_grubcfg.py +""" + +import io +import sys + +MARK = "# VTOY-CUSTOM-LAYOUT" + +OLD_BLOCK = ( + " set vtoydev=$vtoy_dev\n" + " set vtoy_iso_part=($vtoy_dev,1)\n" + " set vtoy_efi_part=($vtoy_dev,2)\n" + " \n" + " vt_load_file_to_mem \"auto\" $prefix/fonts/unicode.pf2 vtoy_font_mem\n" +) + +NEW_BLOCK = ( + " set vtoydev=$vtoy_dev\n" + " set vtoy_iso_part=($vtoy_dev,1)\n" + " set VTOY_DATA_PART_IDX=1\n" + " set vtoy_efi_part=($vtoy_dev,2)\n" + " set VTOY_EFI_PART_IDX=2\n" + "\n" + " " + MARK + ": data (ISO) partition is the one that contains\n" + " # /ISO/Ventoy/NOT.DEL (fallback: partition 1). VTOYEFI stays partition 2.\n" + " for vt_part in 1 2 3 4; do\n" + " if [ -f ($vtoy_dev,$vt_part)/ISO/Ventoy/NOT.DEL ]; then\n" + " set vtoy_iso_part=($vtoy_dev,$vt_part)\n" + " set VTOY_DATA_PART_IDX=$vt_part\n" + " break\n" + " fi\n" + " done\n" + " export VTOY_DATA_PART_IDX\n" + " export VTOY_EFI_PART_IDX\n" + "\n" + " vt_load_file_to_mem \"auto\" $prefix/fonts/unicode.pf2 vtoy_font_mem\n" +) + +REPLACEMENTS = [ + # plugin json at /ISO/Ventoy/ (both tftp and normal branches) + ("$vtoy_iso_part/ventoy/ventoy.json", "$vtoy_iso_part/ISO/Ventoy/ventoy.json"), + # custom menu file at /ISO/Ventoy/ + ("$vt_plugin_path/ventoy/ventoy_grub.cfg", "$vt_plugin_path/ISO/Ventoy/ventoy_grub.cfg"), + # default menu language: Russian (Ventoy opens in Russian unless user picks) + (' vt_init_menu_lang en_US\n', ' vt_init_menu_lang ru_RU\n'), + # WinPE with a non-standard BCD (Sergei Strelec: SSTR/BCD, WePE: WEPE/B64...). + # Ventoy reads the list of wims to patch from BCD files; the x86 wims of such + # PEs are only referenced there, so without this the mount under ia32 never + # happens. Same set as the legacy branch uses. + ('for file in "efi/microsoft/boot/bcd"; do', + 'for file in "efi/microsoft/boot/bcd" "boot/bcd" "SSTR/BCD" "WEPE/B64" "WEPE/B32" "WEPE/BCD" "ISPE/BCD" "ISYL/BCD" "2K10/FONTS/BCD" "2K10/BCD" "boot/uqi/BCD"; do'), + ('for file in "boot/bcd" "/efi/microsoft/boot/bcd" "SSTR/BCD" "boot/bce"; do', + 'for file in "boot/bcd" "/efi/microsoft/boot/bcd" "SSTR/BCD" "WEPE/B64" "WEPE/B32" "WEPE/BCD" "ISPE/BCD" "ISYL/BCD" "2K10/FONTS/BCD" "2K10/BCD" "boot/uqi/BCD" "boot/bce"; do'), +] + + +def main(): + path = sys.argv[1] + src = io.open(path, encoding="utf-8", newline="").read() + + if MARK in src: + print("already patched:", path) + return + + if src.count(OLD_BLOCK) != 1: + raise SystemExit("layout block not found exactly once") + + src = src.replace(OLD_BLOCK, NEW_BLOCK, 1) + print("layout block: marker-based data partition") + + for old, new in REPLACEMENTS: + n = src.count(old) + if n == 0: + raise SystemExit("not found: %s" % old) + src = src.replace(old, new) + print("replaced %d x %s" % (n, old)) + + io.open(path, "w", encoding="utf-8", newline="").write(src) + print("written:", path) + + +if __name__ == "__main__": + main() diff --git a/paravis/patch_ventoy_hook.py b/paravis/patch_ventoy_hook.py new file mode 100644 index 0000000..e9f101d --- /dev/null +++ b/paravis/patch_ventoy_hook.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python3 +""" +Patch Ventoy 1.1.18 initramfs hook for a non-standard layout. + +Problem +------- +VtoyTool/vtoydm.c hardcodes: + + int part = 1; /* ISO partition is assumed to be partition 1 */ + uint64_t offset = 2048; /* ... starting at sector 2048 */ + +so `vtoydm -p/-r` always emits device-mapper tables for `1`. When the +ISO partition is, say, partition 3, the guest kernel rejects the table +("sda1 too small for target") and Linux live systems fail to boot. + +Fix +--- +`vtoy_os_param.vtoy_disk_part_id` (packed struct, byte offset 41) already +contains the real partition number. The hook library gets two small +functions that rewrite the generated tables: + + * chunk table (-p): 1 + (offset + 2048 - part_start) -> N + (offset - part_start) + * raw table (-r): size of 1 -> size of N, device N + +Partition 1 layouts are left untouched. + +The script rewrites the newc cpio archives in place (only the changed entry +changes), so names, order, modes and timestamps are preserved: + + ventoy.cpio + └── ventoy/hook.cpio.xz (xz) + └── hook/ventoy-hook-lib.sh (patched) + +Usage: + python3 patch_ventoy_hook.py +""" + +import io +import lzma +import sys + +MARK = "VTOY-CUSTOM-LAYOUT" + +HELPER = '''# %s: vtoydm assumes the ISO partition is number 1 with offset 2048. +# Rewrite generated dm tables when the ISO lives on another partition. +ventoy_dm_fix() { + vtfile="$1" + vtdisk="${2#/dev/}" + vtmode="$3" + + [ -f /ventoy/ventoy_os_param ] || return 0 + vtpart=$($BUSYBOX_PATH/hexdump -s 41 -n 1 -e '1/1 "%%u"' /ventoy/ventoy_os_param 2>/dev/null) + [ -z "$vtpart" ] && return 0 + [ "$vtpart" = "0" ] && return 0 + [ "$vtpart" = "1" ] && return 0 + + case "$vtdisk" in + nvme*|mmc*|nbd*) vtsep="p" ;; + *) vtsep="" ;; + esac + vtbase="/sys/class/block/${vtdisk}${vtsep}${vtpart}" + [ -d "$vtbase" ] || return 0 + vtstart=$($CAT "$vtbase/start" 2>/dev/null) + vtsize=$($CAT "$vtbase/size" 2>/dev/null) + [ -z "$vtstart" ] && return 0 + + vtdev="/dev/${vtdisk}${vtsep}${vtpart}" + vtold="/dev/${vtdisk}${vtsep}1" + + if [ "$vtmode" = "1" ]; then + $AWK -v dev="$vtdev" -v old="$vtold" -v st="$vtstart" ' + $3 == "linear" && $4 == old { $4 = dev; $5 = $5 + 2048 - st } + { print } + ' "$vtfile" > "${vtfile}.fix" + else + $AWK -v dev="$vtdev" -v old="$vtold" -v sz="$vtsize" ' + $3 == "linear" && $4 == old { $1 = 0; $2 = sz; $4 = dev; $5 = 0 } + { print } + ' "$vtfile" > "${vtfile}.fix" + fi + $BUSYBOX_PATH/mv "${vtfile}.fix" "$vtfile" + vtlog "dm table fixed: $vtfile dev=$vtdev start=$vtstart part=$vtpart" +} + +''' % MARK + +ANCHOR_FUNC = "create_ventoy_device_mapper() {\n" + +CALLS_AFTER = ( + " $VTOY_PATH/tool/vtoydm -r -f $VTOY_PATH/ventoy_image_map -d $1 > $VTOY_PATH/ventoy_raw_table \n" +) + +CALLS_ADD = ( + " # " + MARK + ": fix dm tables for a non-part1 ISO partition\n" + " ventoy_dm_fix $VTOY_PATH/ventoy_dm_table \"$1\" 1\n" + " ventoy_dm_fix $VTOY_PATH/ventoy_raw_table \"$1\" 0\n" +) + +PERSIST_AFTER = ( + " $VTOY_PATH/tool/vtoydm -p -f $VTOY_PATH/ventoy_persistent_map -d $1 > $VTOY_PATH/persistent_dm_table \n" +) + +PERSIST_ADD = ( + " ventoy_dm_fix $VTOY_PATH/persistent_dm_table \"$1\" 1\n" +) + + +def parse_newc(data): + """Return list of (fields, name, body) preserving header values.""" + entries = [] + pos = 0 + while pos + 110 <= len(data): + hdr = data[pos:pos + 110] + if hdr[:6] != b"070701": + break + f = [int(hdr[6 + i * 8:14 + i * 8], 16) for i in range(13)] + namesize = f[11] + filesize = f[6] + name_start = pos + 110 + name = data[name_start:name_start + namesize - 1].decode("utf-8", "surrogateescape") + p = name_start + namesize + p = (p + 3) & ~3 + body = data[p:p + filesize] + p += filesize + p = (p + 3) & ~3 + entries.append({"fields": f, "name": name, "body": body}) + pos = p + if name == "TRAILER!!!": + break + return entries + + +def build_newc(entries): + out = bytearray() + for e in entries: + f = list(e["fields"]) + name = e["name"].encode("utf-8", "surrogateescape") + b"\0" + body = e["body"] + f[6] = len(body) + f[11] = len(name) + hdr = b"070701" + b"".join(b"%08X" % (v & 0xFFFFFFFF) for v in f) + name_pad = (4 - ((110 + len(name)) % 4)) % 4 + out += hdr + out += name + out += b"\0" * name_pad + out += body + out += b"\0" * ((-len(body)) % 4) + return bytes(out) + + +def patch_hook_sh(text): + if MARK in text: + return text, False + + if ANCHOR_FUNC not in text: + raise SystemExit("anchor create_ventoy_device_mapper not found") + text = text.replace(ANCHOR_FUNC, HELPER + ANCHOR_FUNC, 1) + + if CALLS_AFTER not in text: + raise SystemExit("anchor vtoydm -r line not found") + text = text.replace(CALLS_AFTER, CALLS_AFTER + CALLS_ADD, 1) + + if PERSIST_AFTER in text: + text = text.replace(PERSIST_AFTER, PERSIST_AFTER + PERSIST_ADD, 1) + else: + print(" note: persistent mapper anchor not found (skipped)") + + return text, True + + +def main(): + src, dst = sys.argv[1], sys.argv[2] + data = open(src, "rb").read() + entries = parse_newc(data) + print("ventoy.cpio entries:", [e["name"] for e in entries if e["name"] != "TRAILER!!!"][:20]) + + hook_idx = None + for i, e in enumerate(entries): + if e["name"] == "ventoy/hook.cpio.xz": + hook_idx = i + break + if hook_idx is None: + raise SystemExit("ventoy/hook.cpio.xz not found") + + hook_cpio = lzma.decompress(entries[hook_idx]["body"]) + hook_entries = parse_newc(hook_cpio) + print("hook.cpio entries:", len(hook_entries)) + + target = "hook/ventoy-hook-lib.sh" + idx = None + for i, e in enumerate(hook_entries): + if e["name"] == target: + idx = i + break + if idx is None: + raise SystemExit("%s not found" % target) + + text = hook_entries[idx]["body"].decode("utf-8", "surrogateescape") + new_text, changed = patch_hook_sh(text) + if not changed: + print("already patched") + return + + hook_entries[idx]["body"] = new_text.encode("utf-8", "surrogateescape") + new_hook = build_newc(hook_entries) + entries[hook_idx]["body"] = lzma.compress(new_hook, format=lzma.FORMAT_XZ, preset=6) + + out = build_newc(entries) + open(dst, "wb").write(out) + print("written %s (%d bytes)" % (dst, len(out))) + + +if __name__ == "__main__": + main() diff --git a/paravis/patch_ventoy_layout.py b/paravis/patch_ventoy_layout.py new file mode 100644 index 0000000..ab7f80e --- /dev/null +++ b/paravis/patch_ventoy_layout.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 +""" +Patch Ventoy 1.1.18 GRUB sources for the custom Xorboot layout: + + * data (ISO) partition is NOT partition 1 any more: it is selected at + runtime by grub.cfg (marker file /ISO/Ventoy/NOT.DEL) and passed in + VTOY_DATA_PART_IDX; VTOYEFI stays partition 2 (VTOY_EFI_PART_IDX). + * the "official device" geometry check is disabled (it hardcodes + data=part1 @1MB, VTOYEFI=part2 right after it). + * plugin config is read from /ISO/Ventoy/ventoy.json instead of + /ventoy/ventoy.json. + +Run inside WSL against the build tree: + python3 patch_ventoy_layout.py /root/vtbuild/GRUB2/SRC/grub-2.04/grub-core/ventoy +""" + +import os +import re +import sys + +MARK = "/* VTOY-CUSTOM-LAYOUT */" + + +def patch_cmd(path): + src = open(path, encoding="utf-8", errors="surrogateescape").read() + changed = False + + # --- 1. disable official-device geometry check ------------------------ + anchor = " char *label = NULL;\n struct grub_partition *partition;\n\n" + early = ( + " char *label = NULL;\n" + " struct grub_partition *partition;\n" + "\n" + " " + MARK + "\n" + " /* Custom layout: ISO partition is found by marker file and VTOYEFI\n" + " is partition 2, so the original geometry checks do not apply. */\n" + " (void)workaround; (void)file; (void)offset; (void)devname;\n" + " (void)fs; (void)mbr; (void)disk; (void)dev2; (void)label;\n" + " (void)partition;\n" + " return ventoy_set_check_result(0, NULL);\n" + "\n" + " if (dev->disk == NULL || dev->disk->partition == NULL)\n" + ) + if MARK in src: + print(" ventoy_cmd.c: device check already patched") + else: + if anchor not in src: + raise SystemExit("anchor for device check not found") + src = src.replace(anchor, early, 1) + changed = True + print(" ventoy_cmd.c: device check disabled") + + # --- 2. partition size lookup via env -------------------------------- + old_fn = re.search( + r"grub_uint64_t ventoy_get_vtoy_partsize\(int part\)\n\{.*?\n\}\n", + src, re.S) + if not old_fn: + raise SystemExit("ventoy_get_vtoy_partsize not found") + + new_fn = ( + "grub_uint64_t ventoy_get_vtoy_partsize(int part)\n" + "{\n" + " grub_uint64_t sectors;\n" + " const char *env;\n" + " int idx = part;\n" + "\n" + " " + MARK + "\n" + " /* part 0 = data (ISO) partition, part 1 = VTOYEFI.\n" + " Real partition numbers come from grub.cfg (1-based). */\n" + " env = ventoy_get_env(part == 0 ? \"VTOY_DATA_PART_IDX\" : \"VTOY_EFI_PART_IDX\");\n" + " if (env)\n" + " {\n" + " idx = (int)grub_strtol(env, NULL, 10) - 1;\n" + " }\n" + " if (idx < 0)\n" + " {\n" + " idx = 0;\n" + " }\n" + " if (idx > 3)\n" + " {\n" + " idx = 3;\n" + " }\n" + "\n" + " if (grub_strncmp(g_ventoy_part_info->Head.Signature, \"EFI PART\", 8) == 0)\n" + " {\n" + " sectors = g_ventoy_part_info->PartTbl[idx].LastLBA + 1 - g_ventoy_part_info->PartTbl[idx].StartLBA;\n" + " }\n" + " else\n" + " {\n" + " sectors = g_ventoy_part_info->MBR.PartTbl[idx].SectorCount;\n" + " }\n" + "\n" + " return sectors * 512;\n" + "}\n" + ) + if marker_in(old_fn.group(0)): + print(" ventoy_cmd.c: partsize already patched") + else: + src = src[:old_fn.start()] + new_fn + src[old_fn.end():] + changed = True + print(" ventoy_cmd.c: partsize now uses VTOY_DATA_PART_IDX") + + if changed: + open(path, "w", encoding="utf-8", errors="surrogateescape").write(src) + return changed + + +def marker_in(text): + return MARK in text + + +def patch_plugin(path): + src = open(path, encoding="utf-8", errors="surrogateescape").read() + if "ISO/Ventoy/ventoy.json" in src: + print(" ventoy_plugin.c: json path already patched") + return False + + n = src.count('"%s/ventoy/ventoy.json"') + if n != 2: + raise SystemExit("expected 2 json path occurrences, found %d" % n) + src = src.replace('"%s/ventoy/ventoy.json"', '"%s/ISO/Ventoy/ventoy.json"') + src = src.replace( + 'grub_printf("Plugin json file /ventoy/ventoy.json does NOT exist.\\n");', + 'grub_printf("Plugin json file /ISO/Ventoy/ventoy.json does NOT exist.\\n");') + open(path, "w", encoding="utf-8", errors="surrogateescape").write(src) + print(" ventoy_plugin.c: json path -> /ISO/Ventoy/ventoy.json") + return True + + +def patch_vhd(path): + """ventoy_vhd.c: VHD/IMG on the Ventoy data partition used partIndex = 0 (p1).""" + src = open(path, encoding="utf-8", errors="surrogateescape").read() + if MARK in src: + print(" ventoy_vhd.c: already patched") + return False + + pat = re.compile(r"(gpt = g_ventoy_part_info;[ \t]*\n)(\s*)partIndex = 0;") + m = pat.search(src) + if not m: + raise SystemExit("vhd partIndex anchor not found") + + ind = m.group(2) + new = ( + m.group(1) + + ind + MARK + "\n" + + ind + "/* data partition number comes from grub.cfg (VTOY_DATA_PART_IDX) */\n" + + ind + "partIndex = 0;\n" + + ind + "{\n" + + ind + " const char *vtEnv = ventoy_get_env(\"VTOY_DATA_PART_IDX\");\n" + + ind + " if (vtEnv)\n" + + ind + " {\n" + + ind + " partIndex = (int)grub_strtol(vtEnv, NULL, 10) - 1;\n" + + ind + " }\n" + + ind + " if (partIndex < 0)\n" + + ind + " {\n" + + ind + " partIndex = 0;\n" + + ind + " }\n" + + ind + " if (partIndex > 3)\n" + + ind + " {\n" + + ind + " partIndex = 3;\n" + + ind + " }\n" + + ind + "}" + ) + src = src[:m.start()] + new + src[m.end():] + open(path, "w", encoding="utf-8", errors="surrogateescape").write(src) + print(" ventoy_vhd.c: partIndex now uses VTOY_DATA_PART_IDX") + return True + + +def main(): + d = sys.argv[1] if len(sys.argv) > 1 else "." + patch_cmd(os.path.join(d, "ventoy_cmd.c")) + patch_plugin(os.path.join(d, "ventoy_plugin.c")) + patch_vhd(os.path.join(d, "ventoy_vhd.c")) + print("OK") + + +if __name__ == "__main__": + main() diff --git a/paravis/patch_vtoyjump.py b/paravis/patch_vtoyjump.py new file mode 100644 index 0000000..8c1ba8e --- /dev/null +++ b/paravis/patch_vtoyjump.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +""" +Patch Ventoy 1.1.18 vtoyjump32.exe / vtoyjump64.exe to skip the "Ventoy disk" +MBR marker check (CheckVentoyDisk), so the ISO can be mounted when the USB +stick uses a third-party MBR (Xorboot) instead of Ventoy's own MBR. + +CheckVentoyDisk() in vtoyjump.c does: + UINT8 check[8] = { 0x56,0x54,0x00,0x47,0x65,0x00,0x48,0x44 }; + ... + if (memcmp(SectorBuf + 0x190, check, 8) == 0) + return TRUE; + return FALSE; + +Patches (always return TRUE, code size unchanged): + + vtoyjump64.exe (PE32+, .text VMA 0x140001000, file off 0x400) + 0x140008D0E 0F 94 C3 sete %bl + -> B3 01 90 mov $1,%bl ; nop + (ebx is zeroed at function entry, then copied to eax at 0x140008D11) + + vtoyjump32.exe (PE32, .text VMA 0x00401000, file off 0x400) + 0x00407BEB 75 87 jne -> false + -> 90 90 nop nop + 0x00407BF3 0F 85 7B FF FF FF jne -> false + -> 90 90 90 90 90 90 nop x6 + +Usage: + python3 patch_vtoyjump.py + +Re-running is safe: already patched files are detected and skipped. +""" + +import os +import sys + +PATCHES = { + "vtoyjump64.exe": [ + (0x810E, bytes([0x0F, 0x94, 0xC3]), bytes([0xB3, 0x01, 0x90])), + ], + "vtoyjump32.exe": [ + (0x6FEB, bytes([0x75, 0x87]), bytes([0x90, 0x90])), + (0x6FF3, bytes([0x0F, 0x85, 0x7B, 0xFF, 0xFF, 0xFF]), + bytes([0x90, 0x90, 0x90, 0x90, 0x90, 0x90])), + ], +} + + +def patch_file(path, patches): + with open(path, "rb") as f: + data = bytearray(f.read()) + + changed = False + for off, orig, new in patches: + cur = bytes(data[off:off + len(orig)]) + if cur == new: + print(" %s @0x%X already patched" % (os.path.basename(path), off)) + continue + if cur != orig: + raise SystemExit( + " %s @0x%X unexpected bytes: %s (expected %s)" % ( + os.path.basename(path), off, cur.hex(" "), orig.hex(" "))) + data[off:off + len(new)] = new + print(" %s @0x%X patched: %s -> %s" % ( + os.path.basename(path), off, orig.hex(" "), new.hex(" "))) + changed = True + + if changed: + with open(path, "wb") as f: + f.write(data) + return changed + + +def main(): + if len(sys.argv) != 2: + print(__doc__) + return 1 + + d = sys.argv[1] + rc = 0 + for name, patches in PATCHES.items(): + path = os.path.join(d, name) + if not os.path.isfile(path): + print("MISSING: %s" % path) + rc = 1 + continue + print("%s (%d bytes)" % (path, os.path.getsize(path))) + try: + patch_file(path, patches) + except SystemExit as e: + print(e) + rc = 1 + + print("DONE" if rc == 0 else "FAILED") + return rc + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/paravis/theme/OFL.txt b/paravis/theme/OFL.txt new file mode 100644 index 0000000..4515774 --- /dev/null +++ b/paravis/theme/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2024 The Montserrat.Git Project Authors (https://github.com/JulietaUla/Montserrat.git) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/paravis/theme/background.png b/paravis/theme/background.png new file mode 100644 index 0000000..cd6d8c6 Binary files /dev/null and b/paravis/theme/background.png differ diff --git a/paravis/theme/f12_chip.png b/paravis/theme/f12_chip.png new file mode 100644 index 0000000..570bdf5 Binary files /dev/null and b/paravis/theme/f12_chip.png differ diff --git a/paravis/theme/paravis.pf2 b/paravis/theme/paravis.pf2 new file mode 100644 index 0000000..bf4f373 Binary files /dev/null and b/paravis/theme/paravis.pf2 differ diff --git a/paravis/theme/sel_c.png b/paravis/theme/sel_c.png new file mode 100644 index 0000000..5a6daae Binary files /dev/null and b/paravis/theme/sel_c.png differ diff --git a/paravis/theme/sel_e.png b/paravis/theme/sel_e.png new file mode 100644 index 0000000..26448a3 Binary files /dev/null and b/paravis/theme/sel_e.png differ diff --git a/paravis/theme/sel_w.png b/paravis/theme/sel_w.png new file mode 100644 index 0000000..25553ed Binary files /dev/null and b/paravis/theme/sel_w.png differ diff --git a/paravis/theme/slider_c.png b/paravis/theme/slider_c.png new file mode 100644 index 0000000..f32fe69 Binary files /dev/null and b/paravis/theme/slider_c.png differ diff --git a/paravis/theme/slider_n.png b/paravis/theme/slider_n.png new file mode 100644 index 0000000..361f03b Binary files /dev/null and b/paravis/theme/slider_n.png differ diff --git a/paravis/theme/slider_s.png b/paravis/theme/slider_s.png new file mode 100644 index 0000000..7e6ac86 Binary files /dev/null and b/paravis/theme/slider_s.png differ diff --git a/paravis/theme/terminal_box_c.png b/paravis/theme/terminal_box_c.png new file mode 100644 index 0000000..d0dd52a Binary files /dev/null and b/paravis/theme/terminal_box_c.png differ diff --git a/paravis/theme/terminal_box_e.png b/paravis/theme/terminal_box_e.png new file mode 100644 index 0000000..394cbe4 Binary files /dev/null and b/paravis/theme/terminal_box_e.png differ diff --git a/paravis/theme/terminal_box_n.png b/paravis/theme/terminal_box_n.png new file mode 100644 index 0000000..476f8bc Binary files /dev/null and b/paravis/theme/terminal_box_n.png differ diff --git a/paravis/theme/terminal_box_ne.png b/paravis/theme/terminal_box_ne.png new file mode 100644 index 0000000..9e26959 Binary files /dev/null and b/paravis/theme/terminal_box_ne.png differ diff --git a/paravis/theme/terminal_box_nw.png b/paravis/theme/terminal_box_nw.png new file mode 100644 index 0000000..5c3cba8 Binary files /dev/null and b/paravis/theme/terminal_box_nw.png differ diff --git a/paravis/theme/terminal_box_s.png b/paravis/theme/terminal_box_s.png new file mode 100644 index 0000000..85a8901 Binary files /dev/null and b/paravis/theme/terminal_box_s.png differ diff --git a/paravis/theme/terminal_box_se.png b/paravis/theme/terminal_box_se.png new file mode 100644 index 0000000..d8627ee Binary files /dev/null and b/paravis/theme/terminal_box_se.png differ diff --git a/paravis/theme/terminal_box_sw.png b/paravis/theme/terminal_box_sw.png new file mode 100644 index 0000000..67c600c Binary files /dev/null and b/paravis/theme/terminal_box_sw.png differ diff --git a/paravis/theme/terminal_box_w.png b/paravis/theme/terminal_box_w.png new file mode 100644 index 0000000..d066e2d Binary files /dev/null and b/paravis/theme/terminal_box_w.png differ diff --git a/paravis/theme/theme.txt b/paravis/theme/theme.txt new file mode 100644 index 0000000..5587b28 --- /dev/null +++ b/paravis/theme/theme.txt @@ -0,0 +1,88 @@ +# Paravis Flash - Ventoy theme (1024x768) +desktop-image: "background.png" +desktop-color: "#e8e8e8" +title-text: "" +title-color: "#293554" +message-color: "#293554" +terminal-box: "terminal_box_*.png" + ++ boot_menu { + left = 80 + top = 120 + width = 864 + height = 500 + item_font = "Tahoma Regular 20" + item_color = "#293554" + selected_item_color = "#ffffff" + item_height = 38 + item_spacing = 3 + item_padding = 10 + item_icon_space = 0 + icon_width = 0 + icon_height = 0 + selected_item_pixmap_style = "sel_*.png" + scrollbar = true + scrollbar_width = 8 + scrollbar_thumb = "slider_*.png" +} + ++ progress_bar { + id = "__timeout__" + text = "@TIMEOUT_NOTIFICATION_SHORT@" + left = 30% + width = 20% + top = 12% + text_color = "#293554" + bar_style = "*" + highlight_style = "*" +} + ++ hbox { + left = 4% + top = 92% + width = 60% + height = 20 + + label { text = "@VTOY_HOTKEY_TIP@" color = "#293554" align = "left" } +} + + + ++ hbox { + left = 4% + top = 86% + width = 40% + height = 20 + + label { text = "@VTOY_MEM_DISK@" color = "#293554" align = "left" } +} + ++ hbox { + left = 4% + top = 83% + width = 40% + height = 20 + + label { text = "@VTOY_ISO_RAW@" color = "#293554" align = "left" } +} + ++ hbox { + left = 50% + top = 83% + width = 40% + height = 20 + + label { text = "@VTOY_GRUB2_MODE@" color = "#293554" align = "left" } +} + ++ hbox { + left = 50% + top = 86% + width = 40% + height = 20 + + label { text = "@VTOY_WIMBOOT_MODE@" color = "#293554" align = "left" } +} + ++ hbox { + left = 88% + top = 10% + width = 10% + height = 20 + + label { text = "@VTOY_ISO_UEFI_DRV@" color = "#293554" align = "left" } +} diff --git a/paravis/theme/ventoy.json b/paravis/theme/ventoy.json new file mode 100644 index 0000000..da325ba --- /dev/null +++ b/paravis/theme/ventoy.json @@ -0,0 +1,16 @@ +{ + "theme": { + "file": "/ISO/Ventoy/theme/theme.txt", + "gfxmode": "1024x768", + "display_mode": "GUI", + "ventoy_left": "76%", + "ventoy_top": "95%", + "ventoy_color": "#8a8a8a", + "fonts": [ + "/ISO/Ventoy/theme/tahoma20.pf2", + "/ISO/Ventoy/theme/tahoma16.pf2", + "/ISO/Ventoy/theme/tahoma-bold16.pf2", + "/ISO/Ventoy/theme/tahoma-bold14.pf2" + ] + } +} diff --git a/paravis/ventoy_grub-f7.cfg b/paravis/ventoy_grub-f7.cfg new file mode 100644 index 0000000..6bbc241 --- /dev/null +++ b/paravis/ventoy_grub-f7.cfg @@ -0,0 +1,17 @@ +menuentry "Возврат в главное меню сборки [F7]" --hotkey=f7 --class=vtoyret { + if [ "$grub_platform" = "efi" ]; then + search --no-floppy --file --set=root /efi/Paravis/Boot/grub2/grub.cfg + if [ "$grub_cpu" = "x86_64" ]; then + chainloader /efi/Paravis/Boot/grub2/grubx64.efi + else + chainloader /EFI/Boot/bootia32.efi + fi + else + chainloader (${vtoydev})+1 + fi + boot +} + +menuentry "← Назад в меню Ventoy [Esc]" --class=vtoyret VTOY_RET { + echo "Return ..." +} diff --git a/paravis/ventoy_grub.cfg b/paravis/ventoy_grub.cfg new file mode 100644 index 0000000..301f827 --- /dev/null +++ b/paravis/ventoy_grub.cfg @@ -0,0 +1,3 @@ +menuentry "← Назад в меню Ventoy [Esc]" --class=vtoyret VTOY_RET { + echo "Return ..." +}