mirror of https://github.com/ventoy/Ventoy.git
commit
458506df75
|
@ -0,0 +1 @@
|
|||
blank_issues_enabled: false
|
|
@ -0,0 +1,93 @@
|
|||
name: Issue Report
|
||||
description: File an issue report
|
||||
title: "[issue]: "
|
||||
assignees:
|
||||
- octocat
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this issue report!
|
||||
- type: checkboxes
|
||||
id: faq
|
||||
attributes:
|
||||
label: Official FAQ
|
||||
description: Have you checked the official FAQ at [https://www.ventoy.net/en/faq.html](https://www.ventoy.net/en/faq.html) ?
|
||||
options:
|
||||
- label: I have checked the official FAQ.
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Ventoy Version
|
||||
description: What version of ventoy are you running?
|
||||
placeholder: 1.0.49
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: latestrelease
|
||||
attributes:
|
||||
label: What about latest release
|
||||
description: Have you tried with the latest release of Ventoy?
|
||||
options:
|
||||
- Yes. I have tried the latest release, but the bug still exist.
|
||||
- No. I didn't try the latest release.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: bios
|
||||
attributes:
|
||||
label: BIOS Mode
|
||||
description: In which BIOS mode did you find the bug?
|
||||
options:
|
||||
- Legacy BIOS Mode
|
||||
- UEFI Mode
|
||||
- Both
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: partstyle
|
||||
attributes:
|
||||
label: Partition Style
|
||||
description: Which partition style did you select when you install Ventoy?
|
||||
options:
|
||||
- MBR
|
||||
- GPT
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: capacity
|
||||
attributes:
|
||||
label: Disk Capacity
|
||||
description: What is the capacity of the disk installed with Ventoy?
|
||||
placeholder: 32GB
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: checksum
|
||||
attributes:
|
||||
label: Image file checksum (if applicable)
|
||||
description: Have you checked the image file in Ventoy's menu as [https://www.ventoy.net/en/faq.html#faq_boot_checksum](https://www.ventoy.net/en/faq.html#faq_boot_checksum) ?
|
||||
options:
|
||||
- Yes.
|
||||
- No.
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: link
|
||||
attributes:
|
||||
label: Image file download link (if applicable)
|
||||
description: What is the image file download link?
|
||||
placeholder: https://xxx
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Tell me what happened. It's highly recommended to include some photo or video about the bug.
|
||||
placeholder: Tell us what you see!
|
||||
value: "A bug happened!"
|
||||
validations:
|
||||
required: true
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
name: Ventoy CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run docker-compose up
|
||||
run: docker-compose up
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ventoy-windows
|
||||
path: INSTALL/ventoy-*windows*
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ventoy-linux
|
||||
path: INSTALL/ventoy-*linux*
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ventoy-livecd
|
||||
path: INSTALL/ventoy-*livecd*
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: xxx-build-log
|
||||
path: DOC/build.log
|
|
@ -0,0 +1,25 @@
|
|||
name: Mirror GitHub to Gitee
|
||||
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the main branch
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
run:
|
||||
name: Sync-GitHub-to-Gitee
|
||||
if: ${{ github.repository_owner == 'ventoy' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Mirror the Github repos to Gitee.
|
||||
uses: Yikun/hub-mirror-action@master
|
||||
with:
|
||||
src: github/ventoy
|
||||
dst: gitee/LongPanda
|
||||
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
|
||||
dst_token: ${{ secrets.GITEE_TOKEN }}
|
||||
static_list: "Ventoy"
|
||||
force_update: true
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,55 @@
|
|||
======== How to build ash/hexdump/xzcat for aarch64 ========
|
||||
#How to get ash.config/hexdump.cofig/xzcat.config
|
||||
#ARCH=arm64 CROSS_COMPILE=aarch64-linux- make allnoconfig
|
||||
#ARCH=arm64 CROSS_COMPILE=aarch64-linux- make menuconfig
|
||||
#----> enable static build
|
||||
#----> enable xzcat
|
||||
#get aarch64_xzcat.config
|
||||
|
||||
tar xf busybox-1.32.0.tar.bz2
|
||||
cd busybox-1.32.0
|
||||
copy aarch64_xzcat.config as .config
|
||||
ARCH=arm64 CROSS_COMPILE=aarch64-linux- make
|
||||
rename ./busybox to xzcat
|
||||
|
||||
|
||||
======== How to build ash/hexdump/xzcat for mips64el ========
|
||||
#download mips64el-musl cross toolchain from https://github.com/ventoy/musl-cross-make/releases/download/latest/
|
||||
#How to get ash.config/hexdump.cofig/xzcat.config
|
||||
#ARCH=mips CROSS_COMPILE=mips64el-linux-musl- make allnoconfig "CFLAGS+=-mips64r2 -mabi=64 -Os" "LDFLAGS+=-mips64r2 -mabi=64 -Os"
|
||||
#ARCH=mips CROSS_COMPILE=mips64el-linux-musl- make menuconfig "CFLAGS+=-mips64r2 -mabi=64 -Os" "LDFLAGS+=-mips64r2 -mabi=64 -Os"
|
||||
#----> enable static build
|
||||
#----> enable xzcat
|
||||
#get mips64el_xzcat.config
|
||||
|
||||
tar xf busybox-1.32.0.tar.bz2
|
||||
cd busybox-1.32.0
|
||||
copy mips64el_xzcat.config as .config
|
||||
ARCH=mips CROSS_COMPILE=mips64el-linux-musl- make "CFLAGS+=-mips64r2 -mabi=64 -Os" "LDFLAGS+=-mips64r2 -mabi=64 -Os"
|
||||
rename ./busybox to xzcat
|
||||
|
||||
|
||||
======== How to build full busybox =========
|
||||
#make defconfig
|
||||
#make menuconfig select static build
|
||||
|
||||
======== How to build ash/hexdump/xzcat for x86_64 ==========
|
||||
#How to get ash.config/hexdump.cofig/xzcat.config
|
||||
#make allnoconfig
|
||||
#make menuconfig
|
||||
#----> enable static build
|
||||
#----> enable xzcat
|
||||
#get x86_64_xzcat.config
|
||||
|
||||
|
||||
tar xf busybox-1.32.0.tar.bz2
|
||||
cd busybox-1.32.0
|
||||
copy x86_64_xzcat.config as .config
|
||||
modify Makefile
|
||||
CC = gcc -specs "/usr/local/musl/lib/musl-gcc.specs"
|
||||
MODFLAGS = -DMODULE -specs "/usr/local/musl/lib/musl-gcc.specs"
|
||||
make
|
||||
rename ./busybox to xzcat
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#!/bin/sh
|
||||
|
||||
DSTDIR=../../IMG/cpio/ventoy/busybox
|
||||
|
||||
rm -f vtchmod32 vtchmod64 vtchmod64_musl vtchmodaa64
|
||||
rm -f $DSTDIR/vtchmod32 $DSTDIR/vtchmod64 $DSTDIR/vtchmodaa64 $DSTDIR/vtchmodm64e
|
||||
|
||||
/opt/diet32/bin/diet gcc -Os -m32 vtchmod.c -o vtchmod32
|
||||
/opt/diet64/bin/diet gcc -Os vtchmod.c -o vtchmod64
|
||||
aarch64-linux-gcc -Os -static vtchmod.c -o vtchmodaa64
|
||||
aarch64-linux-strip --strip-all vtchmodaa64
|
||||
|
||||
mips64el-linux-musl-gcc -mips64r2 -mabi=64 -Os -static vtchmod.c -o vtchmodm64e
|
||||
mips64el-linux-musl-strip --strip-all vtchmodm64e
|
||||
|
||||
|
||||
gcc -specs "/usr/local/musl/lib/musl-gcc.specs" -Os -static vtchmod.c -o vtchmod64_musl
|
||||
strip --strip-all vtchmod64_musl
|
||||
|
||||
chmod 777 vtchmod32
|
||||
chmod 777 vtchmod64
|
||||
chmod 777 vtchmodaa64
|
||||
chmod 777 vtchmod64_musl
|
||||
chmod 777 vtchmodm64e
|
||||
|
||||
cp -a vtchmod32 $DSTDIR/
|
||||
cp -a vtchmod64 $DSTDIR/
|
||||
cp -a vtchmodaa64 $DSTDIR/
|
||||
cp -a vtchmod64_musl $DSTDIR/
|
||||
cp -a vtchmodm64e $DSTDIR/
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return chmod(argv[1], 0777);
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,31 +1,70 @@
|
|||
Build a static linked, small dmsetup tool
|
||||
|
||||
======== Source Code ========
|
||||
use an old version of dmsetup
|
||||
http://vault.centos.org/5.3/os/SRPMS/device-mapper-1.02.28-2.el5.src.rpm
|
||||
https://www.fefe.de/dietlibc/dietlibc-0.34.tar.xz
|
||||
|
||||
======== Build Envrioment ========
|
||||
build for 32bit, static linked with dietlibc
|
||||
1. install centos 6.10 i386 with CentOS-6.10-i386-bin-DVD1.iso
|
||||
2. yum install gcc kernel-devel package
|
||||
3. install dietc libc (just make && make install)
|
||||
4. export PATH=$PATH:/opt/diet/bin
|
||||
|
||||
======== Build Step ========
|
||||
1. extract device mapper source code
|
||||
2. CC="diet gcc" ./configure --disable-nls --disable-selinux --disable-shared
|
||||
3. modify include/configure.h file
|
||||
--- delete the line with "#define malloc rpl_malloc"
|
||||
--- add 2 defines as follow:
|
||||
#ifndef UINT32_MAX
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#endif
|
||||
|
||||
#ifndef UINT64_C
|
||||
#define UINT64_C(c) c ## ULL
|
||||
#endif
|
||||
|
||||
4. make
|
||||
5. strip dmsetup/dmsetup
|
||||
5. get dmsetup/dmsetup as the binary file
|
||||
Build a static linked, small dmsetup tool
|
||||
|
||||
======== Source Code ========
|
||||
use an old version of dmsetup
|
||||
http://vault.centos.org/5.3/os/SRPMS/device-mapper-1.02.28-2.el5.src.rpm
|
||||
https://www.fefe.de/dietlibc/dietlibc-0.34.tar.xz
|
||||
|
||||
======== Build Envrioment ========
|
||||
build for 32bit, static linked with dietlibc
|
||||
1. install centos 6.10 i386 with CentOS-6.10-i386-bin-DVD1.iso
|
||||
2. yum install gcc kernel-devel package
|
||||
3. install dietc libc (just make && make install)
|
||||
4. export PATH=$PATH:/opt/diet/bin
|
||||
|
||||
======== Build Step ========
|
||||
1. extract device mapper source code
|
||||
2. CC="diet gcc" ./configure --disable-nls --disable-selinux --disable-shared
|
||||
3. modify include/configure.h file
|
||||
--- delete the line with "#define malloc rpl_malloc"
|
||||
--- add 2 defines as follow:
|
||||
#ifndef UINT32_MAX
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#endif
|
||||
|
||||
#ifndef UINT64_C
|
||||
#define UINT64_C(c) c ## ULL
|
||||
#endif
|
||||
|
||||
4. make
|
||||
5. strip dmsetup/dmsetup
|
||||
6. get dmsetup/dmsetup as the dmsetup32 binary file
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
======================== Build for 64bit dmsetup =========================
|
||||
1. extract device mapper source code
|
||||
2. ./configure --disable-nls --disable-selinux --disable-shared --enable-static_link CC='gcc -specs /usr/local/musl/lib/musl-gcc.specs'
|
||||
3. touch include/linux/limits.h include/linux/types.h
|
||||
echo '#include <sys/mount.h>' > include/linux/fs.h
|
||||
4. make
|
||||
5. strip --strip-all dmsetup/dmsetup.static
|
||||
6. get dmsetup/dmsetup.static as the dmsetup64 binary file
|
||||
|
||||
|
||||
======================== Build for arm64 dmsetup =========================
|
||||
1. extract device mapper source code
|
||||
2. ./configure CC=aarch64-linux-gcc --target=arm --host=x86_64-linux-gnu --disable-nls --disable-selinux --disable-shared --enable-static_link
|
||||
3. modify include/configure.h file
|
||||
--- delete the line with "#define malloc rpl_malloc"
|
||||
4. make
|
||||
5. aarch64-linux-strip dmsetup/dmsetup.static
|
||||
6. get dmsetup/dmsetup.static as the dmsetupaa64 binary file
|
||||
|
||||
|
||||
======================== Build for mips64 dmsetup =========================
|
||||
1. extract device mapper source code
|
||||
2. ./configure CC="mips64el-linux-musl-gcc -mips64r2 -mabi=64" --target=mips --host=x86_64-linux-gnu --disable-nls --disable-selinux --disable-shared --enable-static_link
|
||||
3. modify include/configure.h file
|
||||
--- delete the line with "#define malloc rpl_malloc"
|
||||
4. make
|
||||
5. mips64el-linux-musl-strip dmsetup/dmsetup.static
|
||||
6. get dmsetup/dmsetup.static as the dmsetupm64e binary file
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,204 +1,260 @@
|
|||
|
||||
==========================================
|
||||
1. Compile Enviroment
|
||||
==========================================
|
||||
My build envrioment is CentOS 7.8 x86_64. So here I first explain how to create the build environment from scratch.
|
||||
Because Ventoy is based on many open source projects, so the envrioment is important. I suggest you test it on a virtual machine first.
|
||||
|
||||
1.1 Install CentOS 7.8
|
||||
I use CentOS-7-x86_64-Everything-2003.iso and select Minimal install
|
||||
|
||||
1.2 Install Packages
|
||||
yum install \
|
||||
libXpm net-tools bzip2 wget vim gcc gcc-c++ samba dos2unix glibc-devel glibc.i686 glibc-devel.i686 \
|
||||
mpfr.i686 mpfr-devel.i686 zlib.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
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
2. Download Source Code
|
||||
==========================================
|
||||
2.1 Download Ventoy source code from github and decompress it.
|
||||
Next I assume that you have unzipped the code into the /home directory (check /home/Ventoy-master/README.md file for the directory level).
|
||||
|
||||
2.2 Download third-part source code
|
||||
|
||||
https://www.fefe.de/dietlibc/dietlibc-0.34.tar.xz ===> /home/Ventoy-master/DOC/dietlibc-0.34.tar.xz
|
||||
https://ftp.gnu.org/gnu/grub/grub-2.04.tar.xz ===> /home/Ventoy-master/GRUB2/grub-2.04.tar.xz
|
||||
https://codeload.github.com/tianocore/edk2/zip/edk2-stable201911 ===> /home/Ventoy-master/EDK2/edk2-edk2-stable201911.zip
|
||||
https://codeload.github.com/relan/exfat/zip/v1.3.0 ===> /home/Ventoy-master/ExFAT/exfat-1.3.0.zip
|
||||
https://codeload.github.com/libfuse/libfuse/zip/fuse-2.9.9 ===> /home/Ventoy-master/ExFAT/libfuse-fuse-2.9.9.zip
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
3. All in one script
|
||||
==========================================
|
||||
I have made the whole build process in all_in_one.sh, you can run this script to build and pack ventoy.
|
||||
If you want to compile a certain part separately, you can continue to refer to the later chapters of this text.
|
||||
|
||||
cd /home/Ventoy-master/INSTALL
|
||||
sh all_in_one.sh
|
||||
|
||||
It should be noted that, some part of Ventoy has 32bit&64bit version (like 4.9 4.10 4.11 follows)
|
||||
all_in_one.sh only build 64bit version of them, if you want to rebuild the 32bit verison. You should create a 32bit CentOS environment and build them.
|
||||
Fortunately these parts are few modified, you only need to build once or you can directly use the binary I have built.
|
||||
|
||||
Besides, after a fully compile and pack, you can only build the part you modified (for example grub2) and run ventoy_pack.sh to generate the package.
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
4. Build every part of Ventoy
|
||||
==========================================
|
||||
4.1 == Build grub2 ==
|
||||
cd /home/Ventoy-master/GRUB2
|
||||
sh buildgrub.sh
|
||||
|
||||
4.2 == Build ipxe.krn ==
|
||||
cd /home/Ventoy-master/IPXE
|
||||
sh buildipxe.sh
|
||||
|
||||
4.3 == Build Ventoy2Disk.exe ==
|
||||
Ventoy2Disk.exe is the installer in Windows platform. And it must be built in Windows with Microsoft Visual Studio (2013+).
|
||||
Open /home/Ventoy-master/Ventoy2Disk/Ventoy2Disk.sln with Visual Studio and build it.
|
||||
|
||||
4.4 == Build vtoyjump64.exe/vtoyjump32.exe ==
|
||||
vtoyjump64.exe/vtoyjump32.exe is used to mount iso file in windows PE. You should install Microsoft Visual Studio (2013+) to build it.
|
||||
Open /home/Ventoy-master/vtoyjump/vtoyjump.sln with Visual Studio and build it (64&32).
|
||||
|
||||
4.5 == Build dmsetup ==
|
||||
Please refer to DMSETUP/build.txt
|
||||
|
||||
4.6 == Build ventoy_x64.efi ==
|
||||
cd /home/Ventoy-master/EDK2
|
||||
sh buildedk.sh
|
||||
|
||||
4.7 == Build VtoyTool ==
|
||||
cd /home/Ventoy-master/VtoyTool
|
||||
sh build.sh
|
||||
|
||||
4.8 == Build vtoyfat ==
|
||||
cd /home/Ventoy-master/vtoyfat/fat_io_lib
|
||||
sh buildlib.sh
|
||||
cd /home/Ventoy-master/vtoyfat
|
||||
sh build.sh
|
||||
|
||||
4.9 == Build exfat-util ==
|
||||
cd /home/Ventoy-master/ExFAT
|
||||
sh buidlibfuse.sh
|
||||
sh buidexfat.sh
|
||||
|
||||
After that, copy EXFAT/shared/mkexfatfs ===> /home/Ventoy-master/INSTALL/tool/mkexfatfs_64
|
||||
After that, copy EXFAT/shared/mount.exfat-fuse ===> /home/Ventoy-master/INSTALL/tool/mount.exfat-fuse_64
|
||||
|
||||
Use the same build step to build exfat-util 32bit in a 32bit CentOS system and get mkexfatfs_32 and mount.exfat-fuse_32
|
||||
|
||||
4.10 == Build vtoy_fuse_iso_64/vtoy_fuse_iso_32 ==
|
||||
cd /home/Ventoy-master/FUSEISO
|
||||
sh build_libfuse.sh
|
||||
sh build.sh
|
||||
|
||||
Use the same build step to build in a 32bit CentOS system and get vtoy_fuse_iso_32
|
||||
|
||||
4.11 == Build unsquashfs_64/unsquashfs_32 ==
|
||||
cd /home/Ventoy-master/SQUASHFS/SRC
|
||||
sh build_lz4.sh
|
||||
sh build_lzma.sh
|
||||
sh build_lzo.sh
|
||||
sh build_zstd.sh
|
||||
|
||||
cd /home/Ventoy-master/SQUASHFS/squashfs-tools-4.4/squashfs-tools
|
||||
sh build.sh
|
||||
|
||||
Use the same build step to build in a 32bit CentOS system and get unsquashfs_32
|
||||
|
||||
4.12 == Build vblade_64/vblade_32 ==
|
||||
cd /home/Ventoy-master/VBLADE/vblade-master
|
||||
sh build.sh
|
||||
|
||||
4.13 == Build zstdcat ==
|
||||
Please refer to ZSTD/build.txt
|
||||
|
||||
4.14 == Build vtoy_gen_uuid ==
|
||||
cd /home/Ventoy-master/GenUUID
|
||||
sh build.sh
|
||||
|
||||
4.15 == Build xzminidec ==
|
||||
cd /home/Ventoy-master/xz-embedded-20130513/userspace
|
||||
make -f ventoy_makefile
|
||||
strip --strip-all xzminidec
|
||||
|
||||
4.16 == Build iso9660_x64.efi ==
|
||||
This efi driver is from https://github.com/pbatard/efifs
|
||||
Follow all the build instructions in this project. I modified 3 files (the original and modified source are at /home/Ventoy-master/EDK2/efiffs)
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
5. Binaries
|
||||
==========================================
|
||||
There some binaries in Ventoy install package. These files are downloaded from other open source project's website, such as busybox.
|
||||
Here is the list of the binaries, their SHA-256 and the download urls:
|
||||
|
||||
5.1 IMG/cpio/ventoy/tool/lz4cat
|
||||
https://create.stephan-brumme.com/smallz4 smallz4cat-x32-v1.4
|
||||
SHA-256: 13d293ddeedb469f51da41167f79b2cbdb904e681716f6e6191b233dbb162438
|
||||
|
||||
5.2 IMG/cpio/ventoy/tool/ar
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686 busybox_AR
|
||||
SHA-256: f29b7d81a983c0c85d22496f4a833c18f2528a1b666eb7d47c93084c1ed66ae0
|
||||
|
||||
5.3 IMG/cpio/ventoy/tool/inotifyd
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686 busybox_INOTIFYD
|
||||
SHA-256: 3532162a8695e91a1ed9ddea28b2cb22259a90e93d5d9c4a517b6c36842c686f
|
||||
|
||||
5.4 IMG/cpio/ventoy/busybox/tmpsh
|
||||
https://busybox.net/downloads/binaries/1.27.1-i686 busybox_ASH
|
||||
SHA-256: 44a6274bca580c2758ffc173fc76d18bb855b1fe8dcf70efd9ee75cbd57dee97
|
||||
|
||||
5.5 IMG/cpio/ventoy/busybox/tmpxz
|
||||
https://busybox.net/downloads/binaries/1.27.1-i686 busybox_XZ
|
||||
SHA-256: f6cdb6293680424c29b89bde0685ca27f455166c9b302cd6082ef90681456291
|
||||
|
||||
5.6 INSTALL/tool/xzcat
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686/ busybox_XZCAT
|
||||
SHA-256: 7399db642c2beaf52a16ab5264ffc55cfd1ff5699a524f63e5d48edf84e20f44
|
||||
|
||||
5.7 INSTALL/tool/hexdump
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686/ busybox_HEXDUMP
|
||||
SHA-256: cde08b6a2cf5ad914f05203e18e3f7c2ed6060a63604e3d75536f19b55e8e0af
|
||||
|
||||
5.8 imdisk
|
||||
download http://www.ltr-data.se/files/imdiskinst.exe and extract it by 7zip.
|
||||
|
||||
INSTALL/ventoy/imdisk/64/imdisk.sys --> sys/amd64/imdisk.sys SHA-256: 6702202220268787e361f5a82dae53362c8e6c6dcd240bb01b44dd77ae0788da
|
||||
INSTALL/ventoy/imdisk/64/imdisk.exe --> cli/amd64/imdisk.exe SHA-256: 9759175380af836869443e5f21ce2e33022125d154bc6b3d1c04dc36b190de04
|
||||
INSTALL/ventoy/imdisk/64/imdisk.cpl --> cpl/amd64/imdisk.cpl SHA-256: aea2ebbea2b073c947263744962af8a3eab025ff4c9d825c543e380e738a4c99
|
||||
|
||||
INSTALL/ventoy/imdisk/32/imdisk.sys --> sys/i386/imdisk.sys SHA-256: a94caec2f71a924d6a914c093ad4b905d7cfdea3f515ed48aaa8c3950b2dc191
|
||||
INSTALL/ventoy/imdisk/32/imdisk.exe --> cli/i386/imdisk.exe SHA-256: 33b53858e2139704cf603b115a3e5e1dfd4daeaaed4d3e03c633f2df3b55dbaa
|
||||
INSTALL/ventoy/imdisk/32/imdisk.cpl --> cpl/i386/imdisk.cpl SHA-256: b781d3e2d286ac8bf548f44e50cbbb3fe78203296e41e4d2e73b407668f88f2d
|
||||
|
||||
5.9 INSTALL/ventoy/memdisk
|
||||
https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz
|
||||
decompress it and memdisk is at syslinux-6.03/bios/memdisk/memdisk
|
||||
SHA-256: 3f6cd656b8a14109cd3f906fee2dd2e75418f983a5e1bfdb64f44f7765588cbb
|
||||
|
||||
|
||||
5.10 UEFIinSecureBoot
|
||||
https://github.com/ValdikSS/Super-UEFIinSecureBoot-Disk/releases Super-UEFIinSecureBoot-Disk_minimal_v3.zip
|
||||
unzip it and get Super-UEFIinSecureBoot-Disk_minimal.img, extract the img by 7zip.
|
||||
|
||||
INSTALL/EFI/BOOT/BOOTX64.EFI --> EFI/BOOT/BOOTX64.EFI SHA-256: 475552c7476ad45e42344eee8b30d44c264d200ac2468428aa86fc8795fb6e34
|
||||
INSTALL/EFI/BOOT/grubx64.efi --> EFI/BOOT/grubx64.efi SHA-256: 25d858157349dc52fa70f3cdf5c62fe1e0bae37ddfc3a6b6528af9a3c745775f
|
||||
INSTALL/EFI/BOOT/MokManager.efi --> EFI/BOOT/MokManager.efi SHA-256: 3bf1f46cee0832355c7dd1dba880dea9bcaa78cc44375a1559d43bc9db18933b
|
||||
|
||||
|
||||
5.11 INSTALL/tool/ash
|
||||
https://busybox.net/downloads/binaries/1.31.0-i686-uclibc/ busybox_ASH
|
||||
SHA-256: 2943f02f85fee0c9551aec47110a558a73f919c032b3c51e56d6f197b5ec4d7b
|
||||
|
||||
|
||||
==========================================
|
||||
1. Compile Enviroment
|
||||
==========================================
|
||||
My build envrioment is CentOS 7.8 x86_64. So here I first explain how to create the build environment from scratch.
|
||||
Because Ventoy is based on many open source projects, so the environment is important. I suggest you test it on a virtual machine firstly.
|
||||
|
||||
1.1 Install CentOS 7.8
|
||||
I use CentOS-7-x86_64-Everything-2003.iso and select Minimal install
|
||||
|
||||
1.2 Install Packages
|
||||
yum install \
|
||||
libXpm net-tools bzip2 wget vim gcc gcc-c++ samba dos2unix glibc-devel glibc.i686 glibc-devel.i686 \
|
||||
mpfr.i686 mpfr-devel.i686 zlib.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
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
2. Download Source Code
|
||||
==========================================
|
||||
2.1 Download Ventoy source code from github and decompress it.
|
||||
Next I assume that you have unzipped the code into the /home directory (check /home/Ventoy-master/README.md file for the directory layout).
|
||||
|
||||
2.2 Download third-part source code and tool
|
||||
|
||||
https://www.fefe.de/dietlibc/dietlibc-0.34.tar.xz ===> /home/Ventoy-master/DOC/dietlibc-0.34.tar.xz
|
||||
https://musl.libc.org/releases/musl-1.2.1.tar.gz ===> /home/Ventoy-master/DOC/musl-1.2.1.tar.gz
|
||||
https://ftp.gnu.org/gnu/grub/grub-2.04.tar.xz ===> /home/Ventoy-master/GRUB2/grub-2.04.tar.xz
|
||||
https://codeload.github.com/tianocore/edk2/zip/edk2-stable201911 ===> /home/Ventoy-master/EDK2/edk2-edk2-stable201911.zip
|
||||
https://codeload.github.com/relan/exfat/zip/v1.3.0 ===> /home/Ventoy-master/ExFAT/exfat-1.3.0.zip
|
||||
https://codeload.github.com/libfuse/libfuse/zip/fuse-2.9.9 ===> /home/Ventoy-master/ExFAT/libfuse-fuse-2.9.9.zip
|
||||
https://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/aarch64-linux-gnu/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz ===> /opt/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz
|
||||
https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64/tarballs/aarch64--uclibc--stable-2020.08-1.tar.bz2 ===> /opt/aarch64--uclibc--stable-2020.08-1.tar.bz2
|
||||
http://ftp.loongnix.org/toolchain/gcc/release/mips-loongson-gcc7.3-2019.06-29-linux-gnu.tar.gz ===> /opt/mips-loongson-gcc7.3-2019.06-29-linux-gnu.tar.gz
|
||||
https://github.com/ventoy/musl-cross-make/releases/download/latest/output.tar.bz2 ===> /opt/output.tar.bz2
|
||||
|
||||
|
||||
http://www.tinycorelinux.net/11.x/x86_64/release/distribution_files/vmlinuz64 ===> /home/Ventoy-master/LiveCD/ISO/EFI/boot/vmlinuz64
|
||||
http://www.tinycorelinux.net/11.x/x86_64/release/distribution_files/corepure64.gz ===> /home/Ventoy-master/LiveCD/ISO/EFI/boot/corepure64.gz
|
||||
http://www.tinycorelinux.net/11.x/x86_64/release/distribution_files/modules64.gz ===> /home/Ventoy-master/LiveCD/ISO/EFI/boot/modules64.gz
|
||||
|
||||
2.3 Prepare third-part tools
|
||||
cd /home/Ventoy-master/DOC/
|
||||
tar xf musl-1.2.1.tar.gz
|
||||
cd musl-1.2.1
|
||||
./configure && make install
|
||||
|
||||
tar xf /opt/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz -C /opt
|
||||
tar xf /opt/aarch64--uclibc--stable-2020.08-1.tar.bz2 -C /opt
|
||||
tar xf /opt/output.tar.bz2 -C /opt
|
||||
mv /opt/output /opt/mips64el-linux-musl-gcc730
|
||||
|
||||
|
||||
2.4 Set PATH envrioment
|
||||
export PATH=$PATH:/opt/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu/bin:/opt/aarch64--uclibc--stable-2020.08-1/bin:/opt/mips64el-linux-musl-gcc730/bin
|
||||
better to add this line to /root/.bashrc and relogin as root
|
||||
|
||||
|
||||
==========================================
|
||||
3. All in one script
|
||||
==========================================
|
||||
I have made a all_in_one.sh, you can run this script to build and pack ventoy.
|
||||
If you want to compile a certain part separately, you can continue to refer to the later chapters of this text.
|
||||
|
||||
cd /home/Ventoy-master/INSTALL
|
||||
sh all_in_one.sh
|
||||
|
||||
It should be noted that:
|
||||
1. Only grub2/EDK2/IPXE will be recompiled in all_in_one.sh. Other part contains the binaries and are few modified, so will no be recompiled everytime.
|
||||
You can rebuild these parts separately if you want.
|
||||
|
||||
2. some part of Ventoy has 32bit&64bit version (like 4.9 4.10 4.11 follows)
|
||||
all_in_one.sh only build 64bit version of them, if you want to rebuild the 32bit verison. You should create a 32bit CentOS environment and build them.
|
||||
Fortunately these parts are few modified, you only need to build once or you can directly use the binary I have built.
|
||||
|
||||
Besides, after a fully compile and pack, you can only build the part you modified (for example grub2) and run ventoy_pack.sh to generate the package.
|
||||
|
||||
==========================================
|
||||
4. Build every part of Ventoy
|
||||
==========================================
|
||||
4.1 == Build grub2 ==
|
||||
cd /home/Ventoy-master/GRUB2
|
||||
sh buildgrub.sh
|
||||
|
||||
4.2 == Build ipxe.krn ==
|
||||
cd /home/Ventoy-master/IPXE
|
||||
sh buildipxe.sh
|
||||
|
||||
4.3 == Build Ventoy2Disk.exe ==
|
||||
Ventoy2Disk.exe is the installer in Windows platform. And it must be built in Windows with Microsoft Visual Studio (2013+).
|
||||
Open /home/Ventoy-master/Ventoy2Disk/Ventoy2Disk.sln with Visual Studio and build it.
|
||||
|
||||
4.4 == Build vtoyjump64.exe/vtoyjump32.exe ==
|
||||
vtoyjump64.exe/vtoyjump32.exe is used to mount iso file in windows PE. You should install Microsoft Visual Studio (2013+) to build it.
|
||||
Open /home/Ventoy-master/vtoyjump/vtoyjump.sln with Visual Studio and build it (64&32).
|
||||
|
||||
4.5 == Build dmsetup ==
|
||||
Please refer to DMSETUP/build.txt
|
||||
|
||||
4.6 == Build ventoy_x64.efi ==
|
||||
cd /home/Ventoy-master/EDK2
|
||||
sh buildedk.sh
|
||||
|
||||
4.7 == Build VtoyTool ==
|
||||
cd /home/Ventoy-master/VtoyTool
|
||||
sh build.sh
|
||||
|
||||
4.8 == Build vtoyfat ==
|
||||
cd /home/Ventoy-master/vtoyfat/fat_io_lib
|
||||
sh buildlib.sh
|
||||
cd /home/Ventoy-master/vtoyfat
|
||||
sh build.sh
|
||||
|
||||
4.9 == Build exfat-util ==
|
||||
cd /home/Ventoy-master/ExFAT
|
||||
sh buidlibfuse.sh
|
||||
sh buidexfat.sh
|
||||
|
||||
After that, copy EXFAT/shared/mkexfatfs ===> /home/Ventoy-master/INSTALL/tool/mkexfatfs_64
|
||||
After that, copy EXFAT/shared/mount.exfat-fuse ===> /home/Ventoy-master/INSTALL/tool/mount.exfat-fuse_64
|
||||
|
||||
Use the same build step to build exfat-util 32bit in a 32bit CentOS system and get mkexfatfs_32 and mount.exfat-fuse_32
|
||||
|
||||
4.10 == Build vtoy_fuse_iso_64/vtoy_fuse_iso_32 ==
|
||||
cd /home/Ventoy-master/FUSEISO
|
||||
sh build_libfuse.sh
|
||||
sh build.sh
|
||||
|
||||
Use the same build step to build in a 32bit CentOS system and get vtoy_fuse_iso_32
|
||||
|
||||
4.11 == Build unsquashfs_64/unsquashfs_32 ==
|
||||
cd /home/Ventoy-master/SQUASHFS/SRC
|
||||
sh build_lz4.sh
|
||||
sh build_lzma.sh
|
||||
sh build_lzo.sh
|
||||
sh build_zstd.sh
|
||||
|
||||
cd /home/Ventoy-master/SQUASHFS/squashfs-tools-4.4/squashfs-tools
|
||||
sh build.sh
|
||||
|
||||
Use the same build step to build in a 32bit CentOS system and get unsquashfs_32
|
||||
|
||||
4.12 == Build vblade_64/vblade_32 ==
|
||||
cd /home/Ventoy-master/VBLADE/vblade-master
|
||||
sh build.sh
|
||||
|
||||
4.13 == Build zstdcat ==
|
||||
Please refer to ZSTD/build.txt
|
||||
|
||||
4.14 == Build vtoy_gen_uuid ==
|
||||
cd /home/Ventoy-master/GenUUID
|
||||
sh build.sh
|
||||
|
||||
4.15 == Build xzminidec32 ==
|
||||
cd /home/Ventoy-master/Ventoy2Disk/Ventoy2Disk/xz-embedded-20130513/userspace
|
||||
make -f ventoy_makefile
|
||||
strip --strip-all xzminidec
|
||||
|
||||
4.16 == Build xzminidec64 ==
|
||||
cd /home/Ventoy-master/Ventoy2Disk/Ventoy2Disk/xz-embedded-20130513/userspace
|
||||
make -f ventoy_makefile64
|
||||
strip --strip-all xzminidec
|
||||
|
||||
4.17 == Build iso9660_x64.efi ==
|
||||
This efi driver is from https://github.com/pbatard/efifs
|
||||
Follow all the build instructions in this project. I modified 3 files (the original and modified source are at /home/Ventoy-master/EDK2/efiffs)
|
||||
|
||||
4.18 IMG/cpio/ventoy/busybox/64h
|
||||
https://www.uclibc.org/downloads/binaries/0.9.30.1/mini-native-x86_64.tar.bz2
|
||||
https://busybox.net/downloads/busybox-1.32.0.tar.bz2
|
||||
use BUSYBOX/x86_64_ash.config and uclibc to build busybox-1.32
|
||||
|
||||
4.19 == Build lunzip32/lunzip64 ==
|
||||
http://mirror.yongbok.net/nongnu/lzip/lunzip/lunzip-1.11.tar.gz
|
||||
PATH=$PATH:/opt/diet/bin
|
||||
./configure --disable-nls CC='diet gcc -nostdinc'
|
||||
make
|
||||
strip --strip-all lunzip
|
||||
|
||||
#aarch64
|
||||
./configure --disable-nls CC='aarch64-buildroot-linux-uclibc-gcc -static'
|
||||
make
|
||||
aarch64-buildroot-linux-uclibc-strip --strip-all lunzip
|
||||
|
||||
|
||||
|
||||
==========================================
|
||||
5. Binaries
|
||||
==========================================
|
||||
There some binaries in Ventoy install package. These files are downloaded from other open source project's website, such as busybox.
|
||||
Here is the list of the binaries, their SHA-256 and the download urls:
|
||||
|
||||
5.1 IMG/cpio/ventoy/tool/lz4cat
|
||||
https://create.stephan-brumme.com/smallz4 smallz4cat-x32-v1.4
|
||||
SHA-256: 13d293ddeedb469f51da41167f79b2cbdb904e681716f6e6191b233dbb162438
|
||||
|
||||
5.2 IMG/cpio/ventoy/tool/ar
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686 busybox_AR
|
||||
SHA-256: f29b7d81a983c0c85d22496f4a833c18f2528a1b666eb7d47c93084c1ed66ae0
|
||||
|
||||
5.3 IMG/cpio/ventoy/tool/inotifyd
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686 busybox_INOTIFYD
|
||||
SHA-256: 3532162a8695e91a1ed9ddea28b2cb22259a90e93d5d9c4a517b6c36842c686f
|
||||
|
||||
5.4 IMG/cpio/ventoy/busybox/ash
|
||||
https://busybox.net/downloads/binaries/1.27.1-i686 busybox_ASH
|
||||
SHA-256: 44a6274bca580c2758ffc173fc76d18bb855b1fe8dcf70efd9ee75cbd57dee97
|
||||
|
||||
5.5 IMG/cpio/ventoy/busybox/tmpxz
|
||||
https://busybox.net/downloads/binaries/1.27.1-i686 busybox_XZ
|
||||
SHA-256: f6cdb6293680424c29b89bde0685ca27f455166c9b302cd6082ef90681456291
|
||||
|
||||
5.6 INSTALL/tool/i386/xzcat
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686/ busybox_XZCAT
|
||||
SHA-256: 7399db642c2beaf52a16ab5264ffc55cfd1ff5699a524f63e5d48edf84e20f44
|
||||
|
||||
5.7 INSTALL/tool/i386/hexdump
|
||||
https://busybox.net/downloads/binaries/1.30.0-i686/ busybox_HEXDUMP
|
||||
SHA-256: cde08b6a2cf5ad914f05203e18e3f7c2ed6060a63604e3d75536f19b55e8e0af
|
||||
|
||||
5.8 imdisk
|
||||
download http://www.ltr-data.se/files/imdiskinst.exe and extract it by 7zip.
|
||||
|
||||
INSTALL/ventoy/imdisk/64/imdisk.sys --> sys/amd64/imdisk.sys SHA-256: 6702202220268787e361f5a82dae53362c8e6c6dcd240bb01b44dd77ae0788da
|
||||
INSTALL/ventoy/imdisk/64/imdisk.exe --> cli/amd64/imdisk.exe SHA-256: 9759175380af836869443e5f21ce2e33022125d154bc6b3d1c04dc36b190de04
|
||||
INSTALL/ventoy/imdisk/64/imdisk.cpl --> cpl/amd64/imdisk.cpl SHA-256: aea2ebbea2b073c947263744962af8a3eab025ff4c9d825c543e380e738a4c99
|
||||
|
||||
INSTALL/ventoy/imdisk/32/imdisk.sys --> sys/i386/imdisk.sys SHA-256: a94caec2f71a924d6a914c093ad4b905d7cfdea3f515ed48aaa8c3950b2dc191
|
||||
INSTALL/ventoy/imdisk/32/imdisk.exe --> cli/i386/imdisk.exe SHA-256: 33b53858e2139704cf603b115a3e5e1dfd4daeaaed4d3e03c633f2df3b55dbaa
|
||||
INSTALL/ventoy/imdisk/32/imdisk.cpl --> cpl/i386/imdisk.cpl SHA-256: b781d3e2d286ac8bf548f44e50cbbb3fe78203296e41e4d2e73b407668f88f2d
|
||||
|
||||
5.9 INSTALL/ventoy/memdisk
|
||||
https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz
|
||||
decompress it and memdisk is at syslinux-6.03/bios/memdisk/memdisk
|
||||
SHA-256: 3f6cd656b8a14109cd3f906fee2dd2e75418f983a5e1bfdb64f44f7765588cbb
|
||||
|
||||
|
||||
5.10 UEFIinSecureBoot
|
||||
https://github.com/ValdikSS/Super-UEFIinSecureBoot-Disk/releases Super-UEFIinSecureBoot-Disk_minimal_v3.zip
|
||||
unzip it and get Super-UEFIinSecureBoot-Disk_minimal.img, extract the img by 7zip.
|
||||
|
||||
INSTALL/EFI/BOOT/BOOTX64.EFI --> EFI/BOOT/BOOTX64.EFI SHA-256: 475552c7476ad45e42344eee8b30d44c264d200ac2468428aa86fc8795fb6e34
|
||||
INSTALL/EFI/BOOT/grubx64.efi --> EFI/BOOT/grubx64.efi SHA-256: 25d858157349dc52fa70f3cdf5c62fe1e0bae37ddfc3a6b6528af9a3c745775f
|
||||
INSTALL/EFI/BOOT/MokManager.efi --> EFI/BOOT/MokManager.efi SHA-256: 3bf1f46cee0832355c7dd1dba880dea9bcaa78cc44375a1559d43bc9db18933b
|
||||
|
||||
|
||||
5.11 INSTALL/tool/ash
|
||||
https://busybox.net/downloads/binaries/1.31.0-i686-uclibc/ busybox_ASH
|
||||
SHA-256: 2943f02f85fee0c9551aec47110a558a73f919c032b3c51e56d6f197b5ec4d7b
|
||||
|
||||
5.12 7za.exe
|
||||
download from https://www.7-zip.org/a/7z1900-extra.7z
|
||||
ISNTALL/ventoy/7z/64/7za.exe SHA-256: 8117e40ee7f824f63373a4f5625bb62749f69159d0c449b3ce2f35aad3b83549
|
||||
ISNTALL/ventoy/7z/32/7za.exe SHA-256: ea308c76a2f927b160a143d94072b0dce232e04b751f0c6432a94e05164e716d
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
1. LAKKA dm-mod.ko
|
||||
LaKKa config
|
||||
https://github.com/libretro/Lakka-LibreELEC/releases download source code
|
||||
\projects\Generic\linux\linux.x86_64.conf
|
||||
|
||||
Linux Kernel
|
||||
linux-4.11.12.tar.xz & patch-4.11.12-rt14.patch.xz
|
||||
patch -p1 < ../patch-4.11.12-rt14
|
||||
|
||||
make menuconfig
|
||||
select device mapper as module
|
||||
make -j 16
|
||||
get drivers\md\dm-mod.ko
|
||||
|
||||
2. LibreELEC dm-mod.ko
|
||||
LibreELEC config
|
||||
https://github.com/LibreELEC/LibreELEC.tv/releases download source code
|
||||
\projects\Generic\linux\linux.x86_64.conf
|
||||
|
||||
Linux Kernel
|
||||
linux-5.1.6.tar.xz
|
||||
make menuconfig
|
||||
select device mapper as module
|
||||
make -j 16
|
||||
get drivers\md\dm-mod.ko
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
#[ -d /opt/diet64 ] || sh ./installdietlibc.sh
|
||||
|
||||
[ -d /opt/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu ] || tar xf /opt/gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu.tar.xz -C /opt
|
||||
|
||||
[ -d /opt/aarch64--uclibc--stable-2020.08-1 ] || tar xf /opt/aarch64--uclibc--stable-2020.08-1.tar.bz2 -C /opt
|
||||
|
||||
[ -d /opt/mips-loongson-gcc7.3-linux-gnu ] || tar xf /opt/mips-loongson-gcc7.3-2019.06-29-linux-gnu.tar.gz -C /opt
|
15
Dockerfile
15
Dockerfile
|
@ -1,17 +1,10 @@
|
|||
FROM centos:7
|
||||
|
||||
RUN yum -y install \
|
||||
RUN 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 zlib.i686 rsync autogen autoconf automake libtool gettext* bison binutils \
|
||||
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
|
||||
|
||||
CMD cd /ventoy \
|
||||
&& wget -P DOC/ https://www.fefe.de/dietlibc/dietlibc-0.34.tar.xz \
|
||||
&& wget -P GRUB2/ https://ftp.gnu.org/gnu/grub/grub-2.04.tar.xz \
|
||||
&& wget -O EDK2/edk2-edk2-stable201911.zip https://codeload.github.com/tianocore/edk2/zip/edk2-stable201911 \
|
||||
&& wget -O ExFAT/exfat-1.3.0.zip https://codeload.github.com/relan/exfat/zip/v1.3.0 \
|
||||
&& wget -O ExFAT/libfuse-fuse-2.9.9.zip https://codeload.github.com/libfuse/libfuse/zip/fuse-2.9.9 \
|
||||
&& cd INSTALL && ls -la && sh all_in_one.sh
|
||||
iscsi-initiator-utils grub2-tools zip nasm acpica-tools glibc-static zlib-static xorriso
|
||||
|
||||
CMD cd /ventoy/INSTALL && ls -la && sh docker_ci_build.sh
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
EDKARCH=X64
|
||||
postfix=x64
|
||||
elif [ "$1" = "ia32" ]; then
|
||||
EDKARCH=IA32
|
||||
postfix=ia32
|
||||
shift
|
||||
elif [ "$1" = "aa64" ]; then
|
||||
EDKARCH=AARCH64
|
||||
postfix=aa64
|
||||
shift
|
||||
fi
|
||||
|
||||
cd edk2-edk2-stable201911
|
||||
|
||||
rm -rf ./Conf/.cache
|
||||
rm -f ./Conf/.AutoGenIdFile.txt
|
||||
|
||||
VTEFI_PATH=Build/MdeModule/RELEASE_GCC48/$EDKARCH/MdeModulePkg/Application/Ventoy/Ventoy/OUTPUT/Ventoy.efi
|
||||
DST_PATH=../../INSTALL/ventoy/ventoy_${postfix}.efi
|
||||
|
||||
VTEFI_PATH2=Build/MdeModule/RELEASE_GCC48/$EDKARCH/MdeModulePkg/Application/VtoyUtil/VtoyUtil/OUTPUT/VtoyUtil.efi
|
||||
DST_PATH2=../../INSTALL/ventoy/vtoyutil_${postfix}.efi
|
||||
|
||||
VTEFI_PATH3=Build/MdeModule/RELEASE_GCC48/$EDKARCH/MdeModulePkg/Application/VDiskChain/VDiskChain/OUTPUT/VDiskChain.efi
|
||||
DST_PATH3=../../VDiskChain/Tool/vdiskchain_${postfix}.efi
|
||||
|
||||
|
||||
rm -f $VTEFI_PATH
|
||||
rm -f $DST_PATH
|
||||
rm -f $VTEFI_PATH2
|
||||
rm -f $DST_PATH2
|
||||
rm -f $VTEFI_PATH3
|
||||
[ -d ../../VDiskChain ] && rm -f $DST_PATH3
|
||||
|
||||
unset WORKSPACE
|
||||
source ./edksetup.sh
|
||||
|
||||
if [ "$EDKARCH" = "AARCH64" ]; then
|
||||
GCC48_AARCH64_PREFIX=aarch64-linux-gnu- \
|
||||
build -p MdeModulePkg/MdeModulePkg.dsc -a $EDKARCH -b RELEASE -t GCC48
|
||||
else
|
||||
build -p MdeModulePkg/MdeModulePkg.dsc -a $EDKARCH -b RELEASE -t GCC48
|
||||
fi
|
||||
|
||||
if [ -e $VTEFI_PATH ] && [ -e $VTEFI_PATH2 ] && [ -e $VTEFI_PATH3 ]; then
|
||||
echo -e '\n\n====================== SUCCESS ========================\n\n'
|
||||
cp -a $VTEFI_PATH $DST_PATH
|
||||
cp -a $VTEFI_PATH2 $DST_PATH2
|
||||
[ -d ../../VDiskChain ] && cp -a $VTEFI_PATH3 $DST_PATH3
|
||||
cd ..
|
||||
else
|
||||
echo -e '\n\n====================== FAILED ========================\n\n'
|
||||
cd ..
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -2,32 +2,20 @@
|
|||
|
||||
rm -rf edk2-edk2-stable201911
|
||||
|
||||
unzip edk2-edk2-stable201911.zip
|
||||
unzip edk2-edk2-stable201911.zip > /dev/null
|
||||
|
||||
/bin/cp -a ./edk2_mod/edk2-edk2-stable201911 ./
|
||||
|
||||
cd edk2-edk2-stable201911
|
||||
|
||||
VTEFI_PATH=Build/MdeModule/RELEASE_GCC48/X64/MdeModulePkg/Application/Ventoy/Ventoy/OUTPUT/Ventoy.efi
|
||||
DST_PATH=../../INSTALL/ventoy/ventoy_x64.efi
|
||||
|
||||
rm -f $VTEFI_PATH
|
||||
rm -f $DST_PATH
|
||||
|
||||
make -j 4 -C BaseTools/
|
||||
cd ..
|
||||
|
||||
source ./edksetup.sh
|
||||
build -p MdeModulePkg/MdeModulePkg.dsc -a X64 -b RELEASE -t GCC48
|
||||
|
||||
if [ -e $VTEFI_PATH ]; then
|
||||
echo -e '\n\n====================== SUCCESS ========================\n\n'
|
||||
cp -a $VTEFI_PATH $DST_PATH
|
||||
cd ..
|
||||
else
|
||||
echo -e '\n\n====================== FAILED ========================\n\n'
|
||||
cd ..
|
||||
exit 1
|
||||
fi
|
||||
echo '======== build EDK2 for i386-efi ==============='
|
||||
sh ./build.sh ia32 || exit 1
|
||||
|
||||
echo '======== build EDK2 for arm64-efi ==============='
|
||||
sh ./build.sh aa64 || exit 1
|
||||
|
||||
echo '======== build EDK2 for x86_64-efi ==============='
|
||||
sh ./build.sh || exit 1
|
||||
|
||||
|
|
|
@ -0,0 +1,466 @@
|
|||
/******************************************************************************
|
||||
* VDiskChain.c
|
||||
*
|
||||
* Copyright (c) 2021, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/UefiApplicationEntryPoint.h>
|
||||
#include <Library/UefiDecompressLib.h>
|
||||
#include <Protocol/LoadedImage.h>
|
||||
#include <Guid/FileInfo.h>
|
||||
#include <Guid/FileSystemInfo.h>
|
||||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/RamDisk.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <VDiskChain.h>
|
||||
|
||||
BOOLEAN gVDiskDebugPrint = FALSE;
|
||||
vdisk_block_data gVDiskBlockData;
|
||||
|
||||
/* Boot filename */
|
||||
CONST CHAR16 *gEfiBootFileName[] =
|
||||
{
|
||||
L"@",
|
||||
EFI_REMOVABLE_MEDIA_FILE_NAME,
|
||||
#if defined (MDE_CPU_IA32)
|
||||
L"\\EFI\\BOOT\\GRUBIA32.EFI",
|
||||
L"\\EFI\\BOOT\\BOOTia32.EFI",
|
||||
L"\\EFI\\BOOT\\bootia32.efi",
|
||||
L"\\efi\\boot\\bootia32.efi",
|
||||
#elif defined (MDE_CPU_X64)
|
||||
L"\\EFI\\BOOT\\GRUBX64.EFI",
|
||||
L"\\EFI\\BOOT\\BOOTx64.EFI",
|
||||
L"\\EFI\\BOOT\\bootx64.efi",
|
||||
L"\\efi\\boot\\bootx64.efi",
|
||||
#elif defined (MDE_CPU_ARM)
|
||||
L"\\EFI\\BOOT\\GRUBARM.EFI",
|
||||
L"\\EFI\\BOOT\\BOOTarm.EFI",
|
||||
L"\\EFI\\BOOT\\bootarm.efi",
|
||||
L"\\efi\\boot\\bootarm.efi",
|
||||
#elif defined (MDE_CPU_AARCH64)
|
||||
L"\\EFI\\BOOT\\GRUBAA64.EFI",
|
||||
L"\\EFI\\BOOT\\BOOTaa64.EFI",
|
||||
L"\\EFI\\BOOT\\bootaa64.efi",
|
||||
L"\\efi\\boot\\bootaa64.efi",
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
UINT8 *g_disk_buf_addr = NULL;
|
||||
UINT64 g_disk_buf_size = 0;
|
||||
|
||||
STATIC EFI_GET_VARIABLE g_org_get_variable = NULL;
|
||||
STATIC EFI_EXIT_BOOT_SERVICES g_org_exit_boot_service = NULL;
|
||||
|
||||
VOID EFIAPI VDiskDebug(IN CONST CHAR8 *Format, ...)
|
||||
{
|
||||
VA_LIST Marker;
|
||||
CHAR16 Buffer[512];
|
||||
|
||||
VA_START (Marker, Format);
|
||||
UnicodeVSPrintAsciiFormat(Buffer, sizeof(Buffer), Format, Marker);
|
||||
VA_END (Marker);
|
||||
|
||||
gST->ConOut->OutputString(gST->ConOut, Buffer);
|
||||
}
|
||||
|
||||
VOID EFIAPI vdisk_clear_input(VOID)
|
||||
{
|
||||
EFI_INPUT_KEY Key;
|
||||
|
||||
gST->ConIn->Reset(gST->ConIn, FALSE);
|
||||
while (EFI_SUCCESS == gST->ConIn->ReadKeyStroke(gST->ConIn, &Key))
|
||||
{
|
||||
;
|
||||
}
|
||||
gST->ConIn->Reset(gST->ConIn, FALSE);
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI vdisk_load_image
|
||||
(
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *pDevicePath,
|
||||
IN CONST CHAR16 *FileName,
|
||||
IN UINTN FileNameLen,
|
||||
OUT EFI_HANDLE *Image
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
CHAR16 TmpBuf[256] = {0};
|
||||
FILEPATH_DEVICE_PATH *pFilePath = NULL;
|
||||
EFI_DEVICE_PATH_PROTOCOL *pImgPath = NULL;
|
||||
|
||||
pFilePath = (FILEPATH_DEVICE_PATH *)TmpBuf;
|
||||
pFilePath->Header.Type = MEDIA_DEVICE_PATH;
|
||||
pFilePath->Header.SubType = MEDIA_FILEPATH_DP;
|
||||
pFilePath->Header.Length[0] = FileNameLen + sizeof(EFI_DEVICE_PATH_PROTOCOL);
|
||||
pFilePath->Header.Length[1] = 0;
|
||||
CopyMem(pFilePath->PathName, FileName, FileNameLen);
|
||||
|
||||
pImgPath = AppendDevicePathNode(pDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)pFilePath);
|
||||
if (!pImgPath)
|
||||
{
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
Status = gBS->LoadImage(FALSE, ImageHandle, pImgPath, NULL, 0, Image);
|
||||
|
||||
debug("Load Image File %r DP: <%s>", Status, ConvertDevicePathToText(pImgPath, FALSE, FALSE));
|
||||
|
||||
FreePool(pImgPath);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI vdisk_decompress_vdisk(IN EFI_LOADED_IMAGE_PROTOCOL *pImageInfo)
|
||||
{
|
||||
UINT32 Size;
|
||||
UINT32 DestinationSize;
|
||||
UINT32 ScratchSize;
|
||||
UINT8 *buf;
|
||||
VOID *ScratchBuf;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
||||
(VOID)pImageInfo;
|
||||
|
||||
vdisk_get_vdisk_raw(&buf, &Size);
|
||||
UefiDecompressGetInfo(buf + VDISK_MAGIC_LEN, Size - VDISK_MAGIC_LEN, &DestinationSize, &ScratchSize);
|
||||
debug("vdisk: size:%u realsize:%u", Size, DestinationSize);
|
||||
|
||||
g_disk_buf_size = DestinationSize;
|
||||
g_disk_buf_addr = AllocatePool(DestinationSize);
|
||||
ScratchBuf = AllocatePool(ScratchSize);
|
||||
|
||||
Status = UefiDecompress(buf + VDISK_MAGIC_LEN, g_disk_buf_addr, ScratchBuf);
|
||||
FreePool(ScratchBuf);
|
||||
|
||||
debug("Status:%r %p %u", Status, g_disk_buf_addr, (UINT32)g_disk_buf_size);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS vdisk_patch_vdisk_path(CHAR16 *pos)
|
||||
{
|
||||
UINTN i;
|
||||
UINTN j;
|
||||
CHAR16 *end;
|
||||
CHAR8 *buf = (char *)g_disk_buf_addr;
|
||||
|
||||
if (*pos == L'\"')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
|
||||
end = StrStr(pos, L".vtoy");
|
||||
end += 5;//string length
|
||||
|
||||
for (i = 0; i < g_disk_buf_size; i++)
|
||||
{
|
||||
if (*(UINT32 *)(buf + i) == 0x59595959)
|
||||
{
|
||||
for (j = 0; j < 300; j++)
|
||||
{
|
||||
if (buf[i + j] != 'Y')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j >= 300)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= g_disk_buf_size)
|
||||
{
|
||||
debug("No need to fill vdisk path");
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("Fill vdisk path at %d", i);
|
||||
|
||||
while (pos != end)
|
||||
{
|
||||
buf[i++] = (CHAR8)(*pos++);
|
||||
}
|
||||
|
||||
buf[i++] = '\"';
|
||||
|
||||
while (buf[i] == 'Y' || buf[i] == '\"')
|
||||
{
|
||||
buf[i] = ' ';
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_get_variable_wrapper
|
||||
(
|
||||
IN CHAR16 *VariableName,
|
||||
IN EFI_GUID *VendorGuid,
|
||||
OUT UINT32 *Attributes, OPTIONAL
|
||||
IN OUT UINTN *DataSize,
|
||||
OUT VOID *Data OPTIONAL
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
||||
Status = g_org_get_variable(VariableName, VendorGuid, Attributes, DataSize, Data);
|
||||
if (StrCmp(VariableName, L"SecureBoot") == 0)
|
||||
{
|
||||
if ((*DataSize == 1) && Data)
|
||||
{
|
||||
*(UINT8 *)Data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_exit_boot_service_wrapper
|
||||
(
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN UINTN MapKey
|
||||
)
|
||||
{
|
||||
return g_org_exit_boot_service(ImageHandle, MapKey);
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI vdisk_disable_secure_boot(IN EFI_HANDLE ImageHandle)
|
||||
{
|
||||
/* step1: wrapper security protocol. */
|
||||
/* Do we still need it since we have been loaded ? */
|
||||
|
||||
|
||||
/* step2: fake SecureBoot variable */
|
||||
g_org_exit_boot_service = gBS->ExitBootServices;
|
||||
gBS->ExitBootServices = vdisk_exit_boot_service_wrapper;
|
||||
|
||||
g_org_get_variable = gRT->GetVariable;
|
||||
gRT->GetVariable = vdisk_get_variable_wrapper;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI vdisk_parse_cmdline(IN EFI_HANDLE ImageHandle)
|
||||
{
|
||||
CHAR16 *Pos = NULL;
|
||||
CHAR16 *pCmdLine = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_LOADED_IMAGE_PROTOCOL *pImageInfo = NULL;
|
||||
|
||||
Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&pImageInfo);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
VDiskDebug("Failed to handle load image protocol %r\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
pCmdLine = (CHAR16 *)AllocatePool(pImageInfo->LoadOptionsSize + 4);
|
||||
SetMem(pCmdLine, pImageInfo->LoadOptionsSize + 4, 0);
|
||||
CopyMem(pCmdLine, pImageInfo->LoadOptions, pImageInfo->LoadOptionsSize);
|
||||
|
||||
if (StrStr(pCmdLine, L"debug"))
|
||||
{
|
||||
gVDiskDebugPrint = TRUE;
|
||||
}
|
||||
|
||||
debug("cmdline:<%s>", pCmdLine);
|
||||
vdisk_debug_pause();
|
||||
|
||||
Pos = StrStr(pCmdLine, L"vdisk=");
|
||||
if (NULL == Pos || NULL == StrStr(pCmdLine, L".vtoy"))
|
||||
{
|
||||
VDiskDebug("vdisk parameter not found!\n");
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
vdisk_decompress_vdisk(pImageInfo);
|
||||
|
||||
vdisk_patch_vdisk_path(Pos + 6);
|
||||
|
||||
if (StrStr(pCmdLine, L"secureboot=off"))
|
||||
{
|
||||
vdisk_disable_secure_boot(ImageHandle);
|
||||
}
|
||||
|
||||
FreePool(pCmdLine);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_boot(IN EFI_HANDLE ImageHandle)
|
||||
{
|
||||
UINTN t = 0;
|
||||
UINTN i = 0;
|
||||
UINTN j = 0;
|
||||
UINTN Find = 0;
|
||||
UINTN Count = 0;
|
||||
EFI_HANDLE Image = NULL;
|
||||
EFI_HANDLE *Handles = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFile = NULL;
|
||||
EFI_DEVICE_PATH_PROTOCOL *pDevPath = NULL;
|
||||
|
||||
for (t = 0; t < 3; t++)
|
||||
{
|
||||
Count = 0;
|
||||
Handles = NULL;
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
debug("vdisk_boot fs count:%u", Count);
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&pFile);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("FS:%u Protocol:%p OpenVolume:%p", i, pFile, pFile->OpenVolume);
|
||||
|
||||
Status = gBS->OpenProtocol(Handles[i], &gEfiDevicePathProtocolGuid,
|
||||
(VOID **)&pDevPath,
|
||||
ImageHandle,
|
||||
Handles[i],
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
debug("Failed to open device path protocol %r", Status);
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Handle:%p FS DP: <%s>", Handles[i], ConvertDevicePathToText(pDevPath, FALSE, FALSE));
|
||||
if (CompareMem(gVDiskBlockData.Path, pDevPath, gVDiskBlockData.DevicePathCompareLen))
|
||||
{
|
||||
debug("Not ventoy disk file system");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 1; j < ARRAY_SIZE(gEfiBootFileName); j++)
|
||||
{
|
||||
Status = vdisk_load_image(ImageHandle, pDevPath, gEfiBootFileName[j],
|
||||
StrSize(gEfiBootFileName[j]), &Image);
|
||||
if (EFI_SUCCESS == Status)
|
||||
{
|
||||
break;
|
||||
}
|
||||
debug("Failed to load image %r <%s>", Status, gEfiBootFileName[j]);
|
||||
}
|
||||
|
||||
if (j >= ARRAY_SIZE(gEfiBootFileName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Find++;
|
||||
debug("Find boot file, now try to boot .....");
|
||||
vdisk_debug_pause();
|
||||
|
||||
if (gVDiskDebugPrint)
|
||||
{
|
||||
gST->ConIn->Reset(gST->ConIn, FALSE);
|
||||
}
|
||||
|
||||
/* can't add debug print here */
|
||||
//ventoy_wrapper_system();
|
||||
Status = gBS->StartImage(Image, NULL, NULL);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
debug("Failed to start image %r", Status);
|
||||
sleep(3);
|
||||
gBS->UnloadImage(Image);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FreePool(Handles);
|
||||
|
||||
if (Find == 0)
|
||||
{
|
||||
debug("Fs not found, now wait and retry...");
|
||||
sleep(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (Find == 0)
|
||||
{
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI VDiskChainEfiMain
|
||||
(
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
||||
gST->ConOut->ClearScreen(gST->ConOut);
|
||||
vdisk_clear_input();
|
||||
|
||||
Status = vdisk_parse_cmdline(ImageHandle);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
vdisk_install_blockio(ImageHandle, g_disk_buf_size);
|
||||
vdisk_debug_pause();
|
||||
|
||||
Status = vdisk_boot(ImageHandle);
|
||||
|
||||
gBS->DisconnectController(gVDiskBlockData.Handle, NULL, NULL);
|
||||
gBS->UninstallMultipleProtocolInterfaces(gVDiskBlockData.Handle,
|
||||
&gEfiBlockIoProtocolGuid, &gVDiskBlockData.BlockIo,
|
||||
&gEfiDevicePathProtocolGuid, gVDiskBlockData.Path,
|
||||
NULL);
|
||||
|
||||
if (EFI_NOT_FOUND == Status)
|
||||
{
|
||||
gST->ConOut->OutputString(gST->ConOut, L"No bootfile found for UEFI!\r\n");
|
||||
gST->ConOut->OutputString(gST->ConOut, L"Maybe the image does not support " VENTOY_UEFI_DESC L"!\r\n");
|
||||
sleep(30);
|
||||
}
|
||||
|
||||
vdisk_clear_input();
|
||||
gST->ConOut->ClearScreen(gST->ConOut);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/******************************************************************************
|
||||
* VDiskChain.h
|
||||
*
|
||||
* Copyright (c) 2021, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VENTOY_H__
|
||||
#define __VENTOY_H__
|
||||
|
||||
#define VDISK_MAGIC_LEN 32
|
||||
|
||||
#define VDISK_BLOCK_DEVICE_PATH_GUID \
|
||||
{ 0x6ed2134e, 0xc2ea, 0x4943, { 0x99, 0x54, 0xa7, 0x76, 0xe5, 0x9c, 0x12, 0xc3 }}
|
||||
|
||||
#define VDISK_BLOCK_DEVICE_PATH_NAME L"vdisk"
|
||||
|
||||
#if defined (MDE_CPU_IA32)
|
||||
#define VENTOY_UEFI_DESC L"IA32 UEFI"
|
||||
#elif defined (MDE_CPU_X64)
|
||||
#define VENTOY_UEFI_DESC L"X64 UEFI"
|
||||
#elif defined (MDE_CPU_EBC)
|
||||
#elif defined (MDE_CPU_ARM)
|
||||
#define VENTOY_UEFI_DESC L"ARM UEFI"
|
||||
#elif defined (MDE_CPU_AARCH64)
|
||||
#define VENTOY_UEFI_DESC L"ARM64 UEFI"
|
||||
#else
|
||||
#error Unknown Processor Type
|
||||
#endif
|
||||
|
||||
typedef struct vdisk_block_data
|
||||
{
|
||||
EFI_HANDLE Handle;
|
||||
EFI_BLOCK_IO_MEDIA Media; /* Media descriptor */
|
||||
EFI_BLOCK_IO_PROTOCOL BlockIo; /* Block I/O protocol */
|
||||
|
||||
UINTN DevicePathCompareLen;
|
||||
EFI_DEVICE_PATH_PROTOCOL *Path; /* Device path protocol */
|
||||
|
||||
EFI_HANDLE RawBlockIoHandle;
|
||||
EFI_BLOCK_IO_PROTOCOL *pRawBlockIo;
|
||||
EFI_DEVICE_PATH_PROTOCOL *pDiskDevPath;
|
||||
|
||||
/* ventoy disk part2 ESP */
|
||||
EFI_HANDLE DiskFsHandle;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pDiskFs;
|
||||
EFI_DEVICE_PATH_PROTOCOL *pDiskFsDevPath;
|
||||
|
||||
EFI_HANDLE IsoDriverImage;
|
||||
}vdisk_block_data;
|
||||
|
||||
|
||||
#define debug(expr, ...) if (gVDiskDebugPrint) VDiskDebug("[VDISK] "expr"\r\n", ##__VA_ARGS__)
|
||||
#define trace(expr, ...) VDiskDebug("[VDISK] "expr"\r\n", ##__VA_ARGS__)
|
||||
#define sleep(sec) gBS->Stall(1000000 * (sec))
|
||||
|
||||
#define vdisk_debug_pause() \
|
||||
if (gVDiskDebugPrint) \
|
||||
{ \
|
||||
UINTN __Index = 0; \
|
||||
gST->ConOut->OutputString(gST->ConOut, L"[VDISK] ###### Press Enter to continue... ######\r\n");\
|
||||
gST->ConIn->Reset(gST->ConIn, FALSE); \
|
||||
gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &__Index);\
|
||||
}
|
||||
|
||||
extern BOOLEAN gVDiskDebugPrint;
|
||||
VOID EFIAPI VDiskDebug(IN CONST CHAR8 *Format, ...);
|
||||
EFI_STATUS EFIAPI vdisk_block_io_read
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
);
|
||||
|
||||
extern UINT8 *g_disk_buf_addr;
|
||||
extern UINT64 g_disk_buf_size;
|
||||
extern vdisk_block_data gVDiskBlockData;
|
||||
EFI_STATUS EFIAPI vdisk_install_blockio(IN EFI_HANDLE ImageHandle, IN UINT64 ImgSize);
|
||||
int vdisk_get_vdisk_raw(UINT8 **buf, UINT32 *size);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
#************************************************************************************
|
||||
# Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#************************************************************************************
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = VDiskChain
|
||||
FILE_GUID = 5bce96e3-ba11-4440-833b-299cf5849193
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = VDiskChainEfiMain
|
||||
|
||||
|
||||
[Sources]
|
||||
VDiskChain.h
|
||||
VDiskChain.c
|
||||
VDiskRawData.c
|
||||
VDiskChainProtocol.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
ShellPkg/ShellPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
UefiApplicationEntryPoint
|
||||
UefiLib
|
||||
DebugLib
|
||||
UefiDecompressLib
|
||||
|
||||
[Guids]
|
||||
gShellVariableGuid
|
||||
gEfiVirtualCdGuid
|
||||
gEfiFileInfoGuid
|
||||
|
||||
[Protocols]
|
||||
gEfiLoadedImageProtocolGuid
|
||||
gEfiBlockIoProtocolGuid
|
||||
gEfiDevicePathProtocolGuid
|
||||
gEfiSimpleFileSystemProtocolGuid
|
||||
gEfiRamDiskProtocolGuid
|
||||
gEfiAbsolutePointerProtocolGuid
|
||||
gEfiAcpiTableProtocolGuid
|
||||
gEfiBlockIo2ProtocolGuid
|
||||
gEfiBusSpecificDriverOverrideProtocolGuid
|
||||
gEfiComponentNameProtocolGuid
|
||||
gEfiComponentName2ProtocolGuid
|
||||
gEfiDriverBindingProtocolGuid
|
||||
gEfiDiskIoProtocolGuid
|
||||
gEfiDiskIo2ProtocolGuid
|
||||
gEfiGraphicsOutputProtocolGuid
|
||||
gEfiHiiConfigAccessProtocolGuid
|
||||
gEfiHiiFontProtocolGuid
|
||||
gEfiLoadFileProtocolGuid
|
||||
gEfiLoadFile2ProtocolGuid
|
||||
gEfiLoadedImageProtocolGuid
|
||||
gEfiLoadedImageDevicePathProtocolGuid
|
||||
gEfiPciIoProtocolGuid
|
||||
gEfiSerialIoProtocolGuid
|
||||
gEfiSimpleTextInProtocolGuid
|
||||
gEfiSimpleTextInputExProtocolGuid
|
||||
gEfiSimpleTextOutProtocolGuid
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
/******************************************************************************
|
||||
* VDiskChainProtocol.c
|
||||
*
|
||||
* Copyright (c) 2021, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/UefiApplicationEntryPoint.h>
|
||||
#include <Protocol/LoadedImage.h>
|
||||
#include <Guid/FileInfo.h>
|
||||
#include <Guid/FileSystemInfo.h>
|
||||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/RamDisk.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <VDiskChain.h>
|
||||
|
||||
/* EFI block device vendor device path GUID */
|
||||
EFI_GUID gVDiskBlockDevicePathGuid = VDISK_BLOCK_DEVICE_PATH_GUID;
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_block_io_reset
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN BOOLEAN ExtendedVerification
|
||||
)
|
||||
{
|
||||
(VOID)This;
|
||||
(VOID)ExtendedVerification;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_block_io_flush(IN EFI_BLOCK_IO_PROTOCOL *This)
|
||||
{
|
||||
(VOID)This;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_block_io_read
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
(VOID)This;
|
||||
(VOID)MediaId;
|
||||
|
||||
debug("vdisk_block_io_read %lu %lu\n", Lba, BufferSize / 512);
|
||||
CopyMem(Buffer, g_disk_buf_addr + (Lba * 512), BufferSize);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_block_io_write
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
(VOID)This;
|
||||
(VOID)MediaId;
|
||||
(VOID)Buffer;
|
||||
|
||||
debug("vdisk_block_io_read %lu %lu\n", Lba, BufferSize / 512);
|
||||
return EFI_WRITE_PROTECTED;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_fill_device_path(VOID)
|
||||
{
|
||||
UINTN NameLen = 0;
|
||||
UINT8 TmpBuf[128] = {0};
|
||||
VENDOR_DEVICE_PATH *venPath = NULL;
|
||||
|
||||
venPath = (VENDOR_DEVICE_PATH *)TmpBuf;
|
||||
NameLen = StrSize(VDISK_BLOCK_DEVICE_PATH_NAME);
|
||||
venPath->Header.Type = HARDWARE_DEVICE_PATH;
|
||||
venPath->Header.SubType = HW_VENDOR_DP;
|
||||
venPath->Header.Length[0] = sizeof(VENDOR_DEVICE_PATH) + NameLen;
|
||||
venPath->Header.Length[1] = 0;
|
||||
CopyMem(&venPath->Guid, &gVDiskBlockDevicePathGuid, sizeof(EFI_GUID));
|
||||
CopyMem(venPath + 1, VDISK_BLOCK_DEVICE_PATH_NAME, NameLen);
|
||||
|
||||
gVDiskBlockData.Path = AppendDevicePathNode(NULL, (EFI_DEVICE_PATH_PROTOCOL *)TmpBuf);
|
||||
gVDiskBlockData.DevicePathCompareLen = sizeof(VENDOR_DEVICE_PATH) + NameLen;
|
||||
|
||||
debug("gVDiskBlockData.Path=<%s>\n", ConvertDevicePathToText(gVDiskBlockData.Path, FALSE, FALSE));
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_connect_driver(IN EFI_HANDLE ControllerHandle, IN CONST CHAR16 *DrvName)
|
||||
{
|
||||
UINTN i = 0;
|
||||
UINTN Count = 0;
|
||||
CHAR16 *DriverName = NULL;
|
||||
EFI_HANDLE *Handles = NULL;
|
||||
EFI_HANDLE DrvHandles[2] = { NULL };
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_COMPONENT_NAME_PROTOCOL *NameProtocol = NULL;
|
||||
EFI_COMPONENT_NAME2_PROTOCOL *Name2Protocol = NULL;
|
||||
|
||||
debug("vdisk_connect_driver <%s>...", DrvName);
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentName2ProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiComponentName2ProtocolGuid, (VOID **)&Name2Protocol);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Status = Name2Protocol->GetDriverName(Name2Protocol, "en", &DriverName);
|
||||
if (EFI_ERROR(Status) || NULL == DriverName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (StrStr(DriverName, DrvName))
|
||||
{
|
||||
debug("Find driver name2:<%s>: <%s>", DriverName, DrvName);
|
||||
DrvHandles[0] = Handles[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < Count)
|
||||
{
|
||||
Status = gBS->ConnectController(ControllerHandle, DrvHandles, NULL, TRUE);
|
||||
debug("vdisk_connect_driver:<%s> <%r>", DrvName, Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
debug("%s NOT found, now try COMPONENT_NAME", DrvName);
|
||||
|
||||
Count = 0;
|
||||
FreePool(Handles);
|
||||
Handles = NULL;
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentNameProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiComponentNameProtocolGuid, (VOID **)&NameProtocol);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Status = NameProtocol->GetDriverName(NameProtocol, "en", &DriverName);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (StrStr(DriverName, DrvName))
|
||||
{
|
||||
debug("Find driver name:<%s>: <%s>", DriverName, DrvName);
|
||||
DrvHandles[0] = Handles[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < Count)
|
||||
{
|
||||
Status = gBS->ConnectController(ControllerHandle, DrvHandles, NULL, TRUE);
|
||||
debug("vdisk_connect_driver:<%s> <%r>", DrvName, Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = EFI_NOT_FOUND;
|
||||
|
||||
end:
|
||||
FreePool(Handles);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI vdisk_install_blockio(IN EFI_HANDLE ImageHandle, IN UINT64 ImgSize)
|
||||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_BLOCK_IO_PROTOCOL *pBlockIo = &(gVDiskBlockData.BlockIo);
|
||||
|
||||
vdisk_fill_device_path();
|
||||
|
||||
debug("install block io protocol %p", ImageHandle);
|
||||
vdisk_debug_pause();
|
||||
|
||||
gVDiskBlockData.Media.BlockSize = 512;
|
||||
gVDiskBlockData.Media.LastBlock = ImgSize / 512 - 1;
|
||||
gVDiskBlockData.Media.ReadOnly = TRUE;
|
||||
gVDiskBlockData.Media.MediaPresent = 1;
|
||||
gVDiskBlockData.Media.LogicalBlocksPerPhysicalBlock = 1;
|
||||
|
||||
pBlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
|
||||
pBlockIo->Media = &(gVDiskBlockData.Media);
|
||||
pBlockIo->Reset = vdisk_block_io_reset;
|
||||
pBlockIo->ReadBlocks = vdisk_block_io_read;
|
||||
pBlockIo->WriteBlocks = vdisk_block_io_write;
|
||||
pBlockIo->FlushBlocks = vdisk_block_io_flush;
|
||||
|
||||
Status = gBS->InstallMultipleProtocolInterfaces(&gVDiskBlockData.Handle,
|
||||
&gEfiBlockIoProtocolGuid, &gVDiskBlockData.BlockIo,
|
||||
&gEfiDevicePathProtocolGuid, gVDiskBlockData.Path,
|
||||
NULL);
|
||||
debug("Install protocol %r %p", Status, gVDiskBlockData.Handle);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = vdisk_connect_driver(gVDiskBlockData.Handle, L"Disk I/O Driver");
|
||||
debug("Connect disk IO driver %r", Status);
|
||||
|
||||
Status = vdisk_connect_driver(gVDiskBlockData.Handle, L"Partition Driver");
|
||||
debug("Connect partition driver %r", Status);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
Status = gBS->ConnectController(gVDiskBlockData.Handle, NULL, NULL, TRUE);
|
||||
debug("Connect all controller %r", Status);
|
||||
}
|
||||
|
||||
vdisk_debug_pause();
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#include <Uefi.h>
|
||||
int vdisk_get_vdisk_raw(UINT8 **buf, UINT32 *size) { *buf = NULL; *size = 0; return 0; }
|
|
@ -34,11 +34,17 @@
|
|||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/RamDisk.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <Protocol/DriverBinding.h>
|
||||
#include <Ventoy.h>
|
||||
|
||||
BOOLEAN gDebugPrint = FALSE;
|
||||
BOOLEAN gBootFallBack = FALSE;
|
||||
BOOLEAN gDotEfiBoot = FALSE;
|
||||
BOOLEAN gLoadIsoEfi = FALSE;
|
||||
BOOLEAN gIsoUdf = FALSE;
|
||||
ventoy_ram_disk g_ramdisk_param;
|
||||
ventoy_chain_head *g_chain;
|
||||
void *g_vtoy_img_location_buf;
|
||||
ventoy_img_chunk *g_chunk;
|
||||
UINT8 *g_os_param_reserved;
|
||||
UINT32 g_img_chunk_num;
|
||||
|
@ -48,10 +54,16 @@ ventoy_virt_chunk *g_virt_chunk;
|
|||
UINT32 g_virt_chunk_num;
|
||||
vtoy_block_data gBlockData;
|
||||
static grub_env_get_pf grub_env_get = NULL;
|
||||
static grub_env_set_pf grub_env_set = NULL;
|
||||
|
||||
ventoy_grub_param_file_replace *g_file_replace_list = NULL;
|
||||
ventoy_efi_file_replace g_efi_file_replace;
|
||||
|
||||
CONST CHAR16 gIso9660EfiDriverPath[] = ISO9660_EFI_DRIVER_PATH;
|
||||
CONST CHAR16 gUdfEfiDriverPath[] = UDF_EFI_DRIVER_PATH;
|
||||
|
||||
BOOLEAN g_fix_windows_1st_cdrom_issue = FALSE;
|
||||
|
||||
STATIC BOOLEAN g_hook_keyboard = FALSE;
|
||||
|
||||
CHAR16 gFirstTryBootFile[256] = {0};
|
||||
|
@ -62,10 +74,28 @@ CONST CHAR16 *gEfiBootFileName[] =
|
|||
{
|
||||
L"@",
|
||||
EFI_REMOVABLE_MEDIA_FILE_NAME,
|
||||
#if defined (MDE_CPU_IA32)
|
||||
L"\\EFI\\BOOT\\GRUBIA32.EFI",
|
||||
L"\\EFI\\BOOT\\BOOTia32.EFI",
|
||||
L"\\EFI\\BOOT\\bootia32.efi",
|
||||
L"\\efi\\boot\\bootia32.efi",
|
||||
#elif defined (MDE_CPU_X64)
|
||||
L"\\EFI\\BOOT\\GRUBX64.EFI",
|
||||
L"\\EFI\\BOOT\\BOOTx64.EFI",
|
||||
L"\\EFI\\BOOT\\bootx64.efi",
|
||||
L"\\efi\\boot\\bootx64.efi",
|
||||
#elif defined (MDE_CPU_ARM)
|
||||
L"\\EFI\\BOOT\\GRUBARM.EFI",
|
||||
L"\\EFI\\BOOT\\BOOTarm.EFI",
|
||||
L"\\EFI\\BOOT\\bootarm.efi",
|
||||
L"\\efi\\boot\\bootarm.efi",
|
||||
#elif defined (MDE_CPU_AARCH64)
|
||||
L"\\EFI\\BOOT\\GRUBAA64.EFI",
|
||||
L"\\EFI\\BOOT\\BOOTaa64.EFI",
|
||||
L"\\EFI\\BOOT\\bootaa64.efi",
|
||||
L"\\efi\\boot\\bootaa64.efi",
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
VOID EFIAPI VtoyDebug(IN CONST CHAR8 *Format, ...)
|
||||
|
@ -242,6 +272,7 @@ static int ventoy_update_image_location(ventoy_os_param *param)
|
|||
}
|
||||
|
||||
address = (UINTN)buffer;
|
||||
g_vtoy_img_location_buf = buffer;
|
||||
|
||||
if (address % 4096)
|
||||
{
|
||||
|
@ -266,19 +297,33 @@ static int ventoy_update_image_location(ventoy_os_param *param)
|
|||
}
|
||||
|
||||
CopyMem(&location->guid, ¶m->guid, sizeof(ventoy_guid));
|
||||
location->image_sector_size = 2048;
|
||||
location->image_sector_size = gSector512Mode ? 512 : 2048;
|
||||
location->disk_sector_size = g_chain->disk_sector_size;
|
||||
location->region_count = g_img_chunk_num;
|
||||
|
||||
region = location->regions;
|
||||
|
||||
for (i = 0; i < g_img_chunk_num; i++)
|
||||
if (gSector512Mode)
|
||||
{
|
||||
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++;
|
||||
for (i = 0; i < g_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 < g_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++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -318,15 +363,27 @@ EFI_HANDLE EFIAPI ventoy_get_parent_handle(IN EFI_DEVICE_PATH_PROTOCOL *pDevPath
|
|||
return Handle;
|
||||
}
|
||||
|
||||
STATIC ventoy_ram_disk g_backup_ramdisk_param;
|
||||
STATIC ventoy_os_param g_backup_os_param_var;
|
||||
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_save_ramdisk_param(VOID)
|
||||
{
|
||||
UINTN DataSize;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_GUID VarGuid = VENTOY_GUID;
|
||||
|
||||
DataSize = sizeof(g_backup_ramdisk_param);
|
||||
Status = gRT->GetVariable(L"VentoyRamDisk", &VarGuid, NULL, &DataSize, &g_backup_ramdisk_param);
|
||||
if (!EFI_ERROR(Status))
|
||||
{
|
||||
debug("find previous ramdisk variable <%llu>", g_backup_ramdisk_param.DiskSize);
|
||||
}
|
||||
|
||||
Status = gRT->SetVariable(L"VentoyRamDisk", &VarGuid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
sizeof(g_ramdisk_param), &(g_ramdisk_param));
|
||||
debug("set efi variable %r", Status);
|
||||
debug("set ramdisk variable %r", Status);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
@ -335,21 +392,38 @@ EFI_STATUS EFIAPI ventoy_delete_ramdisk_param(VOID)
|
|||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_GUID VarGuid = VENTOY_GUID;
|
||||
|
||||
Status = gRT->SetVariable(L"VentoyRamDisk", &VarGuid,
|
||||
|
||||
if (g_backup_ramdisk_param.DiskSize > 0 && g_backup_ramdisk_param.PhyAddr > 0)
|
||||
{
|
||||
Status = gRT->SetVariable(L"VentoyRamDisk", &VarGuid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
sizeof(g_backup_ramdisk_param), &g_backup_ramdisk_param);
|
||||
debug("resotre ramdisk variable %r", Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = gRT->SetVariable(L"VentoyRamDisk", &VarGuid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
0, NULL);
|
||||
debug("delete efi variable %r", Status);
|
||||
debug("delete ramdisk variable %r", Status);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_save_variable(VOID)
|
||||
{
|
||||
UINTN DataSize;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_GUID VarGuid = VENTOY_GUID;
|
||||
|
||||
|
||||
DataSize = sizeof(g_backup_os_param_var);
|
||||
Status = gRT->GetVariable(L"VentoyOsParam", &VarGuid, NULL, &DataSize, &g_backup_os_param_var);
|
||||
if (!EFI_ERROR(Status))
|
||||
{
|
||||
debug("find previous efi variable <%a>", g_backup_os_param_var.vtoy_img_path);
|
||||
}
|
||||
|
||||
Status = gRT->SetVariable(L"VentoyOsParam", &VarGuid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
sizeof(g_chain->os_param), &(g_chain->os_param));
|
||||
|
@ -362,15 +436,55 @@ EFI_STATUS EFIAPI ventoy_delete_variable(VOID)
|
|||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_GUID VarGuid = VENTOY_GUID;
|
||||
|
||||
Status = gRT->SetVariable(L"VentoyOsParam", &VarGuid,
|
||||
|
||||
if (0 == CompareMem(&(g_backup_os_param_var.guid), &VarGuid, sizeof(EFI_GUID)))
|
||||
{
|
||||
Status = gRT->SetVariable(L"VentoyOsParam", &VarGuid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
sizeof(g_backup_os_param_var), &(g_backup_os_param_var));
|
||||
debug("restore efi variable %r", Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = gRT->SetVariable(L"VentoyOsParam", &VarGuid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
0, NULL);
|
||||
debug("delete efi variable %r", Status);
|
||||
debug("delete efi variable %r", Status);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
#if (VENTOY_DEVICE_WARN != 0)
|
||||
STATIC VOID ventoy_warn_invalid_device(VOID)
|
||||
{
|
||||
STATIC BOOLEAN flag = FALSE;
|
||||
|
||||
if (flag)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
flag = TRUE;
|
||||
gST->ConOut->ClearScreen(gST->ConOut);
|
||||
gST->ConOut->OutputString(gST->ConOut, VTOY_WARNING L"\r\n");
|
||||
gST->ConOut->OutputString(gST->ConOut, VTOY_WARNING L"\r\n");
|
||||
gST->ConOut->OutputString(gST->ConOut, VTOY_WARNING L"\r\n\r\n\r\n");
|
||||
|
||||
gST->ConOut->OutputString(gST->ConOut, L"This is NOT a standard Ventoy device and is NOT supported.\r\n\r\n");
|
||||
gST->ConOut->OutputString(gST->ConOut, L"You should follow the official instructions in https://www.ventoy.net\r\n");
|
||||
|
||||
gST->ConOut->OutputString(gST->ConOut, L"\r\n\r\nWill exit after 10 seconds ...... ");
|
||||
|
||||
sleep(10);
|
||||
}
|
||||
#else
|
||||
STATIC VOID ventoy_warn_invalid_device(VOID)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_load_image
|
||||
(
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
|
@ -413,6 +527,7 @@ STATIC EFI_STATUS EFIAPI ventoy_find_iso_disk(IN EFI_HANDLE ImageHandle)
|
|||
UINTN i = 0;
|
||||
UINTN Count = 0;
|
||||
UINT64 DiskSize = 0;
|
||||
MBR_HEAD *pMBR = NULL;
|
||||
UINT8 *pBuffer = NULL;
|
||||
EFI_HANDLE *Handles;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
@ -456,6 +571,18 @@ STATIC EFI_STATUS EFIAPI ventoy_find_iso_disk(IN EFI_HANDLE ImageHandle)
|
|||
|
||||
if (CompareMem(g_chain->os_param.vtoy_disk_guid, pBuffer + 0x180, 16) == 0)
|
||||
{
|
||||
pMBR = (MBR_HEAD *)pBuffer;
|
||||
if (pMBR->PartTbl[0].FsFlag != 0xEE)
|
||||
{
|
||||
if (pMBR->PartTbl[0].StartSectorId != 2048 ||
|
||||
pMBR->PartTbl[1].SectorCount != 65536 ||
|
||||
pMBR->PartTbl[1].StartSectorId != pMBR->PartTbl[0].StartSectorId + pMBR->PartTbl[0].SectorCount)
|
||||
{
|
||||
debug("Failed to check disk part table");
|
||||
ventoy_warn_invalid_device();
|
||||
}
|
||||
}
|
||||
|
||||
gBlockData.RawBlockIoHandle = Handles[i];
|
||||
gBlockData.pRawBlockIo = pBlockIo;
|
||||
gBS->OpenProtocol(Handles[i], &gEfiDevicePathProtocolGuid,
|
||||
|
@ -482,17 +609,117 @@ STATIC EFI_STATUS EFIAPI ventoy_find_iso_disk(IN EFI_HANDLE ImageHandle)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_find_iso_disk_fs(IN EFI_HANDLE ImageHandle)
|
||||
{
|
||||
UINTN i = 0;
|
||||
UINTN Count = 0;
|
||||
EFI_HANDLE Parent = NULL;
|
||||
EFI_HANDLE *Handles = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFile = NULL;
|
||||
EFI_DEVICE_PATH_PROTOCOL *pDevPath = NULL;
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
debug("ventoy_find_iso_disk_fs fs count:%u", Count);
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&pFile);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol(Handles[i], &gEfiDevicePathProtocolGuid,
|
||||
(VOID **)&pDevPath,
|
||||
ImageHandle,
|
||||
Handles[i],
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
debug("Failed to open device path protocol %r", Status);
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Handle:%p FS DP: <%s>", Handles[i], ConvertDevicePathToText(pDevPath, FALSE, FALSE));
|
||||
Parent = ventoy_get_parent_handle(pDevPath);
|
||||
|
||||
if (Parent == gBlockData.RawBlockIoHandle)
|
||||
{
|
||||
debug("Find ventoy disk fs");
|
||||
gBlockData.DiskFsHandle = Handles[i];
|
||||
gBlockData.pDiskFs = pFile;
|
||||
gBlockData.pDiskFsDevPath = pDevPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FreePool(Handles);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_load_isoefi_driver(IN EFI_HANDLE ImageHandle)
|
||||
{
|
||||
EFI_HANDLE Image = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
CHAR16 LogVar[4] = L"5";
|
||||
|
||||
if (gIsoUdf)
|
||||
{
|
||||
Status = ventoy_load_image(ImageHandle, gBlockData.pDiskFsDevPath,
|
||||
gUdfEfiDriverPath,
|
||||
sizeof(gUdfEfiDriverPath),
|
||||
&Image);
|
||||
debug("load iso UDF efi driver status:%r", Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = ventoy_load_image(ImageHandle, gBlockData.pDiskFsDevPath,
|
||||
gIso9660EfiDriverPath,
|
||||
sizeof(gIso9660EfiDriverPath),
|
||||
&Image);
|
||||
debug("load iso 9660 efi driver status:%r", Status);
|
||||
}
|
||||
|
||||
if (gDebugPrint)
|
||||
{
|
||||
gRT->SetVariable(L"FS_LOGGING", &gShellVariableGuid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
sizeof(LogVar), LogVar);
|
||||
}
|
||||
|
||||
gRT->SetVariable(L"FS_NAME_NOCASE", &gShellVariableGuid,
|
||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
sizeof(LogVar), LogVar);
|
||||
|
||||
gBlockData.IsoDriverImage = Image;
|
||||
Status = gBS->StartImage(Image, NULL, NULL);
|
||||
debug("Start iso efi driver status:%r", Status);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
|
||||
{
|
||||
UINT32 i = 0;
|
||||
UINT32 old_cnt = 0;
|
||||
UINTN size = 0;
|
||||
UINT8 chksum = 0;
|
||||
const char *pEnv = NULL;
|
||||
CHAR16 *pPos = NULL;
|
||||
CHAR16 *pCmdLine = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
ventoy_grub_param *pGrubParam = NULL;
|
||||
EFI_LOADED_IMAGE_PROTOCOL *pImageInfo = NULL;
|
||||
ventoy_chain_head *chain = NULL;
|
||||
|
||||
Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&pImageInfo);
|
||||
if (EFI_ERROR(Status))
|
||||
|
@ -509,6 +736,26 @@ STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
|
|||
{
|
||||
gDebugPrint = TRUE;
|
||||
}
|
||||
|
||||
if (StrStr(pCmdLine, L"fallback"))
|
||||
{
|
||||
gBootFallBack = TRUE;
|
||||
}
|
||||
|
||||
if (StrStr(pCmdLine, L"dotefi"))
|
||||
{
|
||||
gDotEfiBoot = TRUE;
|
||||
}
|
||||
|
||||
if (StrStr(pCmdLine, L"isoefi=on"))
|
||||
{
|
||||
gLoadIsoEfi = TRUE;
|
||||
}
|
||||
|
||||
if (StrStr(pCmdLine, L"iso_udf"))
|
||||
{
|
||||
gIsoUdf = TRUE;
|
||||
}
|
||||
|
||||
pPos = StrStr(pCmdLine, L"FirstTry=@");
|
||||
if (pPos)
|
||||
|
@ -544,8 +791,20 @@ STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
|
|||
}
|
||||
|
||||
pGrubParam = (ventoy_grub_param *)StrHexToUintn(pPos + StrLen(L"env_param="));
|
||||
grub_env_set = pGrubParam->grub_env_set;
|
||||
grub_env_get = pGrubParam->grub_env_get;
|
||||
pEnv = grub_env_get("VTOY_CHKDEV_RESULT_STRING");
|
||||
if (!pEnv)
|
||||
{
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (pEnv[0] != '0' || pEnv[1] != 0)
|
||||
{
|
||||
ventoy_warn_invalid_device();
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
g_file_replace_list = &pGrubParam->file_replace;
|
||||
old_cnt = g_file_replace_list->old_file_cnt;
|
||||
debug("file replace: magic:0x%x virtid:%u name count:%u <%a> <%a> <%a> <%a>",
|
||||
|
@ -559,20 +818,33 @@ STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
|
|||
);
|
||||
|
||||
pPos = StrStr(pCmdLine, L"mem:");
|
||||
g_chain = (ventoy_chain_head *)StrHexToUintn(pPos + 4);
|
||||
chain = (ventoy_chain_head *)StrHexToUintn(pPos + 4);
|
||||
|
||||
pPos = StrStr(pPos, L"size:");
|
||||
size = StrDecimalToUintn(pPos + 5);
|
||||
|
||||
debug("memory addr:%p size:%lu", g_chain, size);
|
||||
debug("memory addr:%p size:%lu", chain, size);
|
||||
|
||||
if (StrStr(pCmdLine, L"sector512"))
|
||||
{
|
||||
gSector512Mode = TRUE;
|
||||
}
|
||||
|
||||
if (StrStr(pCmdLine, L"memdisk"))
|
||||
{
|
||||
g_iso_buf_size = size;
|
||||
g_iso_data_buf = (UINT8 *)chain + sizeof(ventoy_chain_head);
|
||||
g_iso_buf_size = size - sizeof(ventoy_chain_head);
|
||||
debug("memdisk mode iso_buf_size:%u", g_iso_buf_size);
|
||||
|
||||
g_chain = chain;
|
||||
gMemdiskMode = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug("This is normal mode");
|
||||
g_chain = AllocatePool(size);
|
||||
CopyMem(g_chain, chain, size);
|
||||
|
||||
g_chunk = (ventoy_img_chunk *)((char *)g_chain + g_chain->img_chunk_offset);
|
||||
g_img_chunk_num = g_chain->img_chunk_num;
|
||||
g_override_chunk = (ventoy_override_chunk *)((char *)g_chain + g_chain->override_chunk_offset);
|
||||
|
@ -583,12 +855,12 @@ STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
|
|||
g_os_param_reserved = (UINT8 *)(g_chain->os_param.vtoy_reserved);
|
||||
|
||||
/* Workaround for Windows & ISO9660 */
|
||||
if (g_os_param_reserved[2] == 1 && g_os_param_reserved[3] == 0)
|
||||
if (g_os_param_reserved[2] == ventoy_chain_windows && g_os_param_reserved[3] == 0)
|
||||
{
|
||||
g_fixup_iso9660_secover_enable = TRUE;
|
||||
}
|
||||
|
||||
if (g_os_param_reserved[2] == 1 && g_os_param_reserved[4] != 1)
|
||||
if (g_os_param_reserved[2] == ventoy_chain_windows && g_os_param_reserved[4] != 1)
|
||||
{
|
||||
g_hook_keyboard = TRUE;
|
||||
}
|
||||
|
@ -613,6 +885,19 @@ STATIC EFI_STATUS EFIAPI ventoy_parse_cmdline(IN EFI_HANDLE ImageHandle)
|
|||
}
|
||||
}
|
||||
|
||||
g_fix_windows_1st_cdrom_issue = FALSE;
|
||||
if (ventoy_chain_windows == g_os_param_reserved[2] ||
|
||||
ventoy_chain_wim == g_os_param_reserved[2])
|
||||
{
|
||||
if (ventoy_is_cdrom_dp_exist())
|
||||
{
|
||||
debug("fixup the 1st cdrom influences when boot windows ...");
|
||||
g_fix_windows_1st_cdrom_issue = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
ventoy_debug_pause();
|
||||
|
||||
FreePool(pCmdLine);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
@ -622,6 +907,11 @@ EFI_STATUS EFIAPI ventoy_clean_env(VOID)
|
|||
FreePool(g_sector_flag);
|
||||
g_sector_flag_num = 0;
|
||||
|
||||
if (gLoadIsoEfi && gBlockData.IsoDriverImage)
|
||||
{
|
||||
gBS->UnloadImage(gBlockData.IsoDriverImage);
|
||||
}
|
||||
|
||||
gBS->DisconnectController(gBlockData.Handle, NULL, NULL);
|
||||
|
||||
gBS->UninstallMultipleProtocolInterfaces(gBlockData.Handle,
|
||||
|
@ -631,9 +921,50 @@ EFI_STATUS EFIAPI ventoy_clean_env(VOID)
|
|||
|
||||
ventoy_delete_variable();
|
||||
|
||||
if (g_chain->os_param.vtoy_img_location_addr)
|
||||
if (g_vtoy_img_location_buf)
|
||||
{
|
||||
FreePool((VOID *)(UINTN)g_chain->os_param.vtoy_img_location_addr);
|
||||
FreePool(g_vtoy_img_location_buf);
|
||||
}
|
||||
|
||||
if (!gMemdiskMode)
|
||||
{
|
||||
FreePool(g_chain);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS ventoy_hook_start(VOID)
|
||||
{
|
||||
/* don't add debug print in this function */
|
||||
|
||||
if (g_fix_windows_1st_cdrom_issue)
|
||||
{
|
||||
ventoy_hook_1st_cdrom_start();
|
||||
}
|
||||
|
||||
/* let this the last */
|
||||
if (g_hook_keyboard)
|
||||
{
|
||||
ventoy_hook_keyboard_start();
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS ventoy_hook_stop(VOID)
|
||||
{
|
||||
/* don't add debug print in this function */
|
||||
|
||||
if (g_fix_windows_1st_cdrom_issue)
|
||||
{
|
||||
ventoy_hook_1st_cdrom_stop();
|
||||
}
|
||||
|
||||
/* let this the last */
|
||||
if (g_hook_keyboard)
|
||||
{
|
||||
ventoy_hook_keyboard_stop();
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
|
@ -725,17 +1056,11 @@ EFI_STATUS EFIAPI ventoy_boot(IN EFI_HANDLE ImageHandle)
|
|||
pFile->OpenVolume = ventoy_wrapper_open_volume;
|
||||
}
|
||||
|
||||
if (g_hook_keyboard)
|
||||
{
|
||||
ventoy_hook_keyboard_start();
|
||||
}
|
||||
ventoy_hook_start();
|
||||
/* can't add debug print here */
|
||||
//ventoy_wrapper_system();
|
||||
Status = gBS->StartImage(Image, NULL, NULL);
|
||||
if (g_hook_keyboard)
|
||||
{
|
||||
ventoy_hook_keyboard_stop();
|
||||
}
|
||||
ventoy_hook_stop();
|
||||
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
|
@ -750,8 +1075,13 @@ EFI_STATUS EFIAPI ventoy_boot(IN EFI_HANDLE ImageHandle)
|
|||
|
||||
if (Find == 0)
|
||||
{
|
||||
if (gDotEfiBoot)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
debug("Fs not found, now wait and retry...");
|
||||
sleep(2);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -789,46 +1119,90 @@ EFI_STATUS EFIAPI VentoyEfiMain
|
|||
gST->ConOut->ClearScreen(gST->ConOut);
|
||||
ventoy_clear_input();
|
||||
|
||||
ventoy_parse_cmdline(ImageHandle);
|
||||
Status = ventoy_parse_cmdline(ImageHandle);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
ventoy_disable_ex_filesystem();
|
||||
|
||||
if (gMemdiskMode)
|
||||
{
|
||||
g_ramdisk_param.PhyAddr = (UINT64)(UINTN)g_chain;
|
||||
g_ramdisk_param.PhyAddr = (UINT64)(UINTN)g_iso_data_buf;
|
||||
g_ramdisk_param.DiskSize = (UINT64)g_iso_buf_size;
|
||||
|
||||
ventoy_save_ramdisk_param();
|
||||
|
||||
if (gLoadIsoEfi)
|
||||
{
|
||||
ventoy_find_iso_disk(ImageHandle);
|
||||
ventoy_find_iso_disk_fs(ImageHandle);
|
||||
ventoy_load_isoefi_driver(ImageHandle);
|
||||
}
|
||||
|
||||
ventoy_install_blockio(ImageHandle, g_iso_buf_size);
|
||||
ventoy_debug_pause();
|
||||
|
||||
Status = ventoy_boot(ImageHandle);
|
||||
|
||||
ventoy_delete_ramdisk_param();
|
||||
|
||||
if (gLoadIsoEfi && gBlockData.IsoDriverImage)
|
||||
{
|
||||
gBS->UnloadImage(gBlockData.IsoDriverImage);
|
||||
}
|
||||
|
||||
gBS->DisconnectController(gBlockData.Handle, NULL, NULL);
|
||||
gBS->UninstallMultipleProtocolInterfaces(gBlockData.Handle,
|
||||
&gEfiBlockIoProtocolGuid, &gBlockData.BlockIo,
|
||||
&gEfiDevicePathProtocolGuid, gBlockData.Path,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
ventoy_save_variable();
|
||||
ventoy_find_iso_disk(ImageHandle);
|
||||
Status = ventoy_find_iso_disk(ImageHandle);
|
||||
if (!EFI_ERROR(Status))
|
||||
{
|
||||
if (gLoadIsoEfi)
|
||||
{
|
||||
ventoy_find_iso_disk_fs(ImageHandle);
|
||||
ventoy_load_isoefi_driver(ImageHandle);
|
||||
}
|
||||
|
||||
ventoy_debug_pause();
|
||||
ventoy_debug_pause();
|
||||
|
||||
ventoy_install_blockio(ImageHandle, g_chain->virt_img_size_in_bytes);
|
||||
|
||||
ventoy_debug_pause();
|
||||
|
||||
Status = ventoy_boot(ImageHandle);
|
||||
}
|
||||
|
||||
ventoy_install_blockio(ImageHandle, g_chain->virt_img_size_in_bytes);
|
||||
|
||||
ventoy_debug_pause();
|
||||
|
||||
Status = ventoy_boot(ImageHandle);
|
||||
|
||||
ventoy_clean_env();
|
||||
}
|
||||
|
||||
if (EFI_NOT_FOUND == Status)
|
||||
if (FALSE == gDotEfiBoot && FALSE == gBootFallBack)
|
||||
{
|
||||
gST->ConOut->OutputString(gST->ConOut, L"No bootfile found for UEFI!\r\n");
|
||||
gST->ConOut->OutputString(gST->ConOut, L"Maybe the image does not support " VENTOY_UEFI_DESC L"!\r\n");
|
||||
sleep(30);
|
||||
if (EFI_NOT_FOUND == Status)
|
||||
{
|
||||
gST->ConOut->OutputString(gST->ConOut, L"No bootfile found for UEFI!\r\n");
|
||||
gST->ConOut->OutputString(gST->ConOut, L"Maybe the image does not support " VENTOY_UEFI_DESC L"!\r\n");
|
||||
sleep(30);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ventoy_clear_input();
|
||||
gST->ConOut->ClearScreen(gST->ConOut);
|
||||
|
||||
if (gDotEfiBoot && (EFI_NOT_FOUND == Status))
|
||||
{
|
||||
grub_env_set("vtoy_dotefi_retry", "YES");
|
||||
}
|
||||
|
||||
ventoy_enable_ex_filesystem();
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,15 @@
|
|||
|
||||
#define VENTOY_GUID { 0x77772020, 0x2e77, 0x6576, { 0x6e, 0x74, 0x6f, 0x79, 0x2e, 0x6e, 0x65, 0x74 }}
|
||||
|
||||
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
|
||||
|
@ -159,21 +168,32 @@ typedef struct ventoy_virt_chunk
|
|||
#define VTOY_BLOCK_DEVICE_PATH_GUID \
|
||||
{ 0x37b87ac6, 0xc180, 0x4583, { 0xa7, 0x05, 0x41, 0x4d, 0xa8, 0xf7, 0x7e, 0xd2 }}
|
||||
|
||||
#define VTOY_BLOCK_DEVICE_PATH_NAME L"ventoy"
|
||||
|
||||
|
||||
#if defined (MDE_CPU_IA32)
|
||||
#define VENTOY_UEFI_DESC L"IA32 UEFI"
|
||||
#define ISO9660_EFI_DRIVER_PATH L"\\ventoy\\iso9660_ia32.efi"
|
||||
#define UDF_EFI_DRIVER_PATH L"\\ventoy\\udf_ia32.efi"
|
||||
#elif defined (MDE_CPU_X64)
|
||||
#define VENTOY_UEFI_DESC L"X64 UEFI"
|
||||
#define ISO9660_EFI_DRIVER_PATH L"\\ventoy\\iso9660_x64.efi"
|
||||
#define UDF_EFI_DRIVER_PATH L"\\ventoy\\udf_x64.efi"
|
||||
#elif defined (MDE_CPU_EBC)
|
||||
#elif defined (MDE_CPU_ARM)
|
||||
#define VENTOY_UEFI_DESC L"ARM UEFI"
|
||||
#define ISO9660_EFI_DRIVER_PATH L"\\ventoy\\iso9660_arm.efi"
|
||||
#define UDF_EFI_DRIVER_PATH L"\\ventoy\\udf_arm.efi"
|
||||
#elif defined (MDE_CPU_AARCH64)
|
||||
#define VENTOY_UEFI_DESC L"ARM64 UEFI"
|
||||
#define ISO9660_EFI_DRIVER_PATH L"\\ventoy\\iso9660_aa64.efi"
|
||||
#define UDF_EFI_DRIVER_PATH L"\\ventoy\\udf_aa64.efi"
|
||||
#else
|
||||
#error Unknown Processor Type
|
||||
#endif
|
||||
|
||||
#define VENTOY_DEVICE_WARN 1
|
||||
#define VTOY_WARNING L"!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!"
|
||||
|
||||
typedef struct ventoy_sector_flag
|
||||
{
|
||||
UINT8 flag; // 0:init 1:mem 2:remap
|
||||
|
@ -199,6 +219,7 @@ typedef struct vtoy_block_data
|
|||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pDiskFs;
|
||||
EFI_DEVICE_PATH_PROTOCOL *pDiskFsDevPath;
|
||||
|
||||
EFI_HANDLE IsoDriverImage;
|
||||
}vtoy_block_data;
|
||||
|
||||
|
||||
|
@ -215,7 +236,9 @@ if (gDebugPrint) \
|
|||
gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &__Index);\
|
||||
}
|
||||
|
||||
typedef int (*grub_env_set_pf)(const char *name, const char *val);
|
||||
typedef const char * (*grub_env_get_pf)(const char *name);
|
||||
typedef int (*grub_env_printf_pf)(const char *fmt, ...);
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
|
@ -242,8 +265,9 @@ typedef struct 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;
|
||||
grub_env_printf_pf grub_env_printf;
|
||||
}ventoy_grub_param;
|
||||
|
||||
typedef struct ventoy_ram_disk
|
||||
|
@ -260,6 +284,32 @@ typedef struct ventoy_iso9660_override
|
|||
UINT32 size_be;
|
||||
}ventoy_iso9660_override;
|
||||
|
||||
typedef struct PART_TABLE
|
||||
{
|
||||
UINT8 Active; // 0x00 0x80
|
||||
|
||||
UINT8 StartHead;
|
||||
UINT16 StartSector : 6;
|
||||
UINT16 StartCylinder : 10;
|
||||
|
||||
UINT8 FsFlag;
|
||||
|
||||
UINT8 EndHead;
|
||||
UINT16 EndSector : 6;
|
||||
UINT16 EndCylinder : 10;
|
||||
|
||||
UINT32 StartSectorId;
|
||||
UINT32 SectorCount;
|
||||
}PART_TABLE;
|
||||
|
||||
typedef struct MBR_HEAD
|
||||
{
|
||||
UINT8 BootCode[446];
|
||||
PART_TABLE PartTbl[4];
|
||||
UINT8 Byte55;
|
||||
UINT8 ByteAA;
|
||||
}MBR_HEAD;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
|
||||
|
@ -279,8 +329,28 @@ typedef struct ventoy_system_wrapper
|
|||
|
||||
EFI_OPEN_PROTOCOL NewOpenProtocol;
|
||||
EFI_OPEN_PROTOCOL OriOpenProtocol;
|
||||
|
||||
EFI_LOCATE_HANDLE_BUFFER NewLocateHandleBuffer;
|
||||
EFI_LOCATE_HANDLE_BUFFER OriLocateHandleBuffer;
|
||||
|
||||
EFI_PROTOCOLS_PER_HANDLE NewProtocolsPerHandle;
|
||||
EFI_PROTOCOLS_PER_HANDLE OriProtocolsPerHandle;
|
||||
|
||||
EFI_LOCATE_HANDLE NewLocateHandle;
|
||||
EFI_LOCATE_HANDLE OriLocateHandle;
|
||||
|
||||
EFI_LOCATE_DEVICE_PATH NewLocateDevicePath;
|
||||
EFI_LOCATE_DEVICE_PATH OriLocateDevicePath;
|
||||
} ventoy_system_wrapper;
|
||||
|
||||
|
||||
#define MAX_DRIVER_BIND_WRAPPER 64
|
||||
typedef struct DriverBindWrapper
|
||||
{
|
||||
EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
|
||||
EFI_DRIVER_BINDING_SUPPORTED pfOldSupport;
|
||||
}DRIVER_BIND_WRAPPER;
|
||||
|
||||
#define ventoy_wrapper(bs, wrapper, func, newfunc) \
|
||||
{\
|
||||
wrapper.Ori##func = bs->func;\
|
||||
|
@ -288,6 +358,22 @@ typedef struct ventoy_system_wrapper
|
|||
bs->func = wrapper.New##func;\
|
||||
}
|
||||
|
||||
|
||||
#define VENTOY_GET_COMPONENT_NAME(Protocol, DriverName) \
|
||||
{\
|
||||
DriverName = NULL;\
|
||||
Status = Protocol->GetDriverName(Protocol, "en", &DriverName);\
|
||||
if (EFI_ERROR(Status) || NULL == DriverName) \
|
||||
{\
|
||||
DriverName = NULL;\
|
||||
Status = Protocol->GetDriverName(Protocol, "eng", &DriverName);\
|
||||
if (EFI_ERROR(Status) || NULL == DriverName) \
|
||||
{\
|
||||
continue;\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
|
||||
extern BOOLEAN gDebugPrint;
|
||||
VOID EFIAPI VtoyDebug(IN CONST CHAR8 *Format, ...);
|
||||
EFI_STATUS EFIAPI ventoy_wrapper_system(VOID);
|
||||
|
@ -313,10 +399,13 @@ extern ventoy_efi_file_replace g_efi_file_replace;
|
|||
extern ventoy_sector_flag *g_sector_flag;
|
||||
extern UINT32 g_sector_flag_num;
|
||||
extern BOOLEAN gMemdiskMode;
|
||||
extern BOOLEAN gSector512Mode;
|
||||
extern UINTN g_iso_buf_size;
|
||||
extern UINT8 *g_iso_data_buf;
|
||||
extern ventoy_grub_param_file_replace *g_file_replace_list;
|
||||
extern BOOLEAN g_fixup_iso9660_secover_enable;
|
||||
extern EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *g_con_simple_input_ex;
|
||||
extern BOOLEAN g_fix_windows_1st_cdrom_issue;
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_wrapper_open_volume
|
||||
(
|
||||
|
@ -327,6 +416,11 @@ EFI_STATUS EFIAPI ventoy_install_blockio(IN EFI_HANDLE ImageHandle, IN UINT64 Im
|
|||
EFI_STATUS EFIAPI ventoy_wrapper_push_openvolume(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume);
|
||||
EFI_STATUS ventoy_hook_keyboard_start(VOID);
|
||||
EFI_STATUS ventoy_hook_keyboard_stop(VOID);
|
||||
BOOLEAN ventoy_is_cdrom_dp_exist(VOID);
|
||||
EFI_STATUS ventoy_hook_1st_cdrom_start(VOID);
|
||||
EFI_STATUS ventoy_hook_1st_cdrom_stop(VOID);
|
||||
EFI_STATUS ventoy_disable_ex_filesystem(VOID);
|
||||
EFI_STATUS ventoy_enable_ex_filesystem(VOID);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,81 +1,81 @@
|
|||
#************************************************************************************
|
||||
# Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#************************************************************************************
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = Ventoy
|
||||
FILE_GUID = 1c3a0915-09dc-49c2-873d-0aaaa7733299
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = VentoyEfiMain
|
||||
|
||||
|
||||
[Sources]
|
||||
Ventoy.h
|
||||
Ventoy.c
|
||||
VentoyDebug.c
|
||||
VentoyProtocol.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
ShellPkg/ShellPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
UefiApplicationEntryPoint
|
||||
UefiLib
|
||||
DebugLib
|
||||
|
||||
[Guids]
|
||||
gShellVariableGuid
|
||||
gEfiVirtualCdGuid
|
||||
gEfiFileInfoGuid
|
||||
|
||||
[Protocols]
|
||||
gEfiLoadedImageProtocolGuid
|
||||
gEfiBlockIoProtocolGuid
|
||||
gEfiDevicePathProtocolGuid
|
||||
gEfiSimpleFileSystemProtocolGuid
|
||||
gEfiRamDiskProtocolGuid
|
||||
gEfiAbsolutePointerProtocolGuid
|
||||
gEfiAcpiTableProtocolGuid
|
||||
gEfiBlockIo2ProtocolGuid
|
||||
gEfiBusSpecificDriverOverrideProtocolGuid
|
||||
gEfiComponentNameProtocolGuid
|
||||
gEfiComponentName2ProtocolGuid
|
||||
gEfiDriverBindingProtocolGuid
|
||||
gEfiDiskIoProtocolGuid
|
||||
gEfiDiskIo2ProtocolGuid
|
||||
gEfiGraphicsOutputProtocolGuid
|
||||
gEfiHiiConfigAccessProtocolGuid
|
||||
gEfiHiiFontProtocolGuid
|
||||
gEfiLoadFileProtocolGuid
|
||||
gEfiLoadFile2ProtocolGuid
|
||||
gEfiLoadedImageProtocolGuid
|
||||
gEfiLoadedImageDevicePathProtocolGuid
|
||||
gEfiPciIoProtocolGuid
|
||||
gEfiSerialIoProtocolGuid
|
||||
gEfiSimpleTextInProtocolGuid
|
||||
gEfiSimpleTextInputExProtocolGuid
|
||||
gEfiSimpleTextOutProtocolGuid
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#************************************************************************************
|
||||
# Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#************************************************************************************
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = Ventoy
|
||||
FILE_GUID = 1c3a0915-09dc-49c2-873d-0aaaa7733299
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = VentoyEfiMain
|
||||
|
||||
|
||||
[Sources]
|
||||
Ventoy.h
|
||||
Ventoy.c
|
||||
VentoyDebug.c
|
||||
VentoyProtocol.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
ShellPkg/ShellPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
UefiApplicationEntryPoint
|
||||
UefiLib
|
||||
DebugLib
|
||||
|
||||
[Guids]
|
||||
gShellVariableGuid
|
||||
gEfiVirtualCdGuid
|
||||
gEfiFileInfoGuid
|
||||
|
||||
[Protocols]
|
||||
gEfiLoadedImageProtocolGuid
|
||||
gEfiBlockIoProtocolGuid
|
||||
gEfiDevicePathProtocolGuid
|
||||
gEfiSimpleFileSystemProtocolGuid
|
||||
gEfiRamDiskProtocolGuid
|
||||
gEfiAbsolutePointerProtocolGuid
|
||||
gEfiAcpiTableProtocolGuid
|
||||
gEfiBlockIo2ProtocolGuid
|
||||
gEfiBusSpecificDriverOverrideProtocolGuid
|
||||
gEfiComponentNameProtocolGuid
|
||||
gEfiComponentName2ProtocolGuid
|
||||
gEfiDriverBindingProtocolGuid
|
||||
gEfiDiskIoProtocolGuid
|
||||
gEfiDiskIo2ProtocolGuid
|
||||
gEfiGraphicsOutputProtocolGuid
|
||||
gEfiHiiConfigAccessProtocolGuid
|
||||
gEfiHiiFontProtocolGuid
|
||||
gEfiLoadFileProtocolGuid
|
||||
gEfiLoadFile2ProtocolGuid
|
||||
gEfiLoadedImageProtocolGuid
|
||||
gEfiLoadedImageDevicePathProtocolGuid
|
||||
gEfiPciIoProtocolGuid
|
||||
gEfiSerialIoProtocolGuid
|
||||
gEfiSimpleTextInProtocolGuid
|
||||
gEfiSimpleTextInputExProtocolGuid
|
||||
gEfiSimpleTextOutProtocolGuid
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -34,11 +34,12 @@
|
|||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/RamDisk.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <Protocol/DriverBinding.h>
|
||||
#include <Ventoy.h>
|
||||
|
||||
#define PROCOTOL_SLEEP_SECONDS 0
|
||||
#define PROCOTOL_SLEEP_MSECONDS 0
|
||||
|
||||
#define debug_sleep() if (PROCOTOL_SLEEP_SECONDS) sleep(PROCOTOL_SLEEP_SECONDS)
|
||||
#define debug_sleep() if (PROCOTOL_SLEEP_MSECONDS) gBS->Stall(1000 * PROCOTOL_SLEEP_MSECONDS)
|
||||
|
||||
STATIC ventoy_system_wrapper g_system_wrapper;
|
||||
|
||||
|
@ -126,7 +127,7 @@ STATIC EFI_STATUS EFIAPI ventoy_open_protocol
|
|||
IN UINT32 Attributes
|
||||
)
|
||||
{
|
||||
debug("ventoy_open_protocol:%a", ventoy_get_guid_name(Protocol)); debug_sleep();
|
||||
debug("ventoy_open_protocol:<%p> %a", Handle, ventoy_get_guid_name(Protocol)); debug_sleep();
|
||||
return g_system_wrapper.OriOpenProtocol(Handle, Protocol, Interface, AgentHandle, ControllerHandle, Attributes);
|
||||
}
|
||||
|
||||
|
@ -141,11 +142,87 @@ STATIC EFI_STATUS EFIAPI ventoy_locate_protocol
|
|||
return g_system_wrapper.OriLocateProtocol(Protocol, Registration, Interface);
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_locate_handle_buffer
|
||||
(
|
||||
IN EFI_LOCATE_SEARCH_TYPE SearchType,
|
||||
IN EFI_GUID *Protocol, OPTIONAL
|
||||
IN VOID *SearchKey, OPTIONAL
|
||||
IN OUT UINTN *NoHandles,
|
||||
OUT EFI_HANDLE **Buffer
|
||||
)
|
||||
{
|
||||
debug("ventoy_locate_handle_buffer:%a", ventoy_get_guid_name(Protocol)); debug_sleep();
|
||||
return g_system_wrapper.OriLocateHandleBuffer(SearchType, Protocol, SearchKey, NoHandles, Buffer);
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_protocol_per_handle
|
||||
(
|
||||
IN EFI_HANDLE Handle,
|
||||
OUT EFI_GUID ***ProtocolBuffer,
|
||||
OUT UINTN *ProtocolBufferCount
|
||||
)
|
||||
{
|
||||
debug("ventoy_protocol_per_handle:%p", Handle); debug_sleep();
|
||||
return g_system_wrapper.OriProtocolsPerHandle(Handle, ProtocolBuffer, ProtocolBufferCount);
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_locate_handle
|
||||
(
|
||||
IN EFI_LOCATE_SEARCH_TYPE SearchType,
|
||||
IN EFI_GUID *Protocol, OPTIONAL
|
||||
IN VOID *SearchKey, OPTIONAL
|
||||
IN OUT UINTN *BufferSize,
|
||||
OUT EFI_HANDLE *Buffer
|
||||
)
|
||||
{
|
||||
UINTN i;
|
||||
EFI_HANDLE Handle;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
||||
debug("ventoy_locate_handle: %d %a %p", SearchType, ventoy_get_guid_name(Protocol), SearchKey);
|
||||
Status = g_system_wrapper.OriLocateHandle(SearchType, Protocol, SearchKey, BufferSize, Buffer);
|
||||
debug("ventoy_locate_handle: %r Handle Count:%u", Status, *BufferSize/sizeof(EFI_HANDLE));
|
||||
|
||||
if (EFI_SUCCESS == Status)
|
||||
{
|
||||
for (i = 0; i < *BufferSize / sizeof(EFI_HANDLE); i++)
|
||||
{
|
||||
if (Buffer[i] == gBlockData.Handle)
|
||||
{
|
||||
Handle = Buffer[0];
|
||||
Buffer[0] = Buffer[i];
|
||||
Buffer[i] = Handle;
|
||||
debug("####### Handle at %u", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_sleep();
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_locate_device_path
|
||||
(
|
||||
IN EFI_GUID *Protocol,
|
||||
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
|
||||
OUT EFI_HANDLE *Device
|
||||
)
|
||||
{
|
||||
debug("ventoy_locate_device_path:%a", ventoy_get_guid_name(Protocol)); debug_sleep();
|
||||
return g_system_wrapper.OriLocateDevicePath(Protocol, DevicePath, Device);
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_wrapper_system(VOID)
|
||||
{
|
||||
ventoy_wrapper(gBS, g_system_wrapper, LocateProtocol, ventoy_locate_protocol);
|
||||
ventoy_wrapper(gBS, g_system_wrapper, HandleProtocol, ventoy_handle_protocol);
|
||||
ventoy_wrapper(gBS, g_system_wrapper, OpenProtocol, ventoy_open_protocol);
|
||||
ventoy_wrapper(gBS, g_system_wrapper, LocateProtocol, ventoy_locate_protocol);
|
||||
ventoy_wrapper(gBS, g_system_wrapper, HandleProtocol, ventoy_handle_protocol);
|
||||
ventoy_wrapper(gBS, g_system_wrapper, OpenProtocol, ventoy_open_protocol);
|
||||
ventoy_wrapper(gBS, g_system_wrapper, LocateHandleBuffer, ventoy_locate_handle_buffer);
|
||||
ventoy_wrapper(gBS, g_system_wrapper, ProtocolsPerHandle, ventoy_protocol_per_handle);
|
||||
ventoy_wrapper(gBS, g_system_wrapper, LocateHandle, ventoy_locate_handle);
|
||||
ventoy_wrapper(gBS, g_system_wrapper, LocateDevicePath, ventoy_locate_device_path);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -34,10 +34,13 @@
|
|||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/RamDisk.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <Protocol/DriverBinding.h>
|
||||
#include <Ventoy.h>
|
||||
|
||||
UINT8 *g_iso_data_buf = NULL;
|
||||
UINTN g_iso_buf_size = 0;
|
||||
BOOLEAN gMemdiskMode = FALSE;
|
||||
BOOLEAN gSector512Mode = FALSE;
|
||||
|
||||
ventoy_sector_flag *g_sector_flag = NULL;
|
||||
UINT32 g_sector_flag_num = 0;
|
||||
|
@ -65,6 +68,54 @@ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *g_con_simple_input_ex = NULL;
|
|||
STATIC EFI_INPUT_READ_KEY_EX g_org_read_key_ex = NULL;
|
||||
STATIC EFI_INPUT_READ_KEY g_org_read_key = NULL;
|
||||
|
||||
STATIC EFI_LOCATE_HANDLE g_org_locate_handle = NULL;
|
||||
|
||||
STATIC UINT8 g_sector_buf[2048];
|
||||
STATIC EFI_BLOCK_READ g_sector_2048_read = NULL;
|
||||
STATIC EFI_BLOCK_WRITE g_sector_2048_write = NULL;
|
||||
|
||||
STATIC UINTN g_DriverBindWrapperCnt = 0;
|
||||
STATIC DRIVER_BIND_WRAPPER g_DriverBindWrapperList[MAX_DRIVER_BIND_WRAPPER];
|
||||
|
||||
BOOLEAN ventoy_is_cdrom_dp_exist(VOID)
|
||||
{
|
||||
UINTN i = 0;
|
||||
UINTN Count = 0;
|
||||
EFI_HANDLE *Handles = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DevicePath = NULL;
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiDevicePathProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
while (!IsDevicePathEnd(DevicePath))
|
||||
{
|
||||
if (MEDIA_DEVICE_PATH == DevicePath->Type && MEDIA_CDROM_DP == DevicePath->SubType)
|
||||
{
|
||||
FreePool(Handles);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DevicePath = NextDevicePathNode(DevicePath);
|
||||
}
|
||||
}
|
||||
|
||||
FreePool(Handles);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Block IO procotol */
|
||||
#endif
|
||||
|
@ -101,7 +152,7 @@ STATIC EFI_STATUS EFIAPI ventoy_read_iso_sector
|
|||
ventoy_override_chunk *pOverride = g_override_chunk;
|
||||
EFI_BLOCK_IO_PROTOCOL *pRawBlockIo = gBlockData.pRawBlockIo;
|
||||
|
||||
debug("read iso sector %lu count %u", Sector, Count);
|
||||
debug("read iso sector %lu count %u Buffer:%p Align:%u", Sector, Count, Buffer, pRawBlockIo->Media->IoAlign);
|
||||
|
||||
ReadStart = Sector * 2048;
|
||||
ReadEnd = (Sector + Count) * 2048;
|
||||
|
@ -114,9 +165,17 @@ STATIC EFI_STATUS EFIAPI ventoy_read_iso_sector
|
|||
{
|
||||
MapLba = (Sector - pchunk->img_start_sector) * 4 + pchunk->disk_start_sector;
|
||||
}
|
||||
else
|
||||
else if (g_chain->disk_sector_size == 1024)
|
||||
{
|
||||
MapLba = (Sector - pchunk->img_start_sector) * 2048 / g_chain->disk_sector_size + pchunk->disk_start_sector;
|
||||
MapLba = (Sector - pchunk->img_start_sector) * 2 + pchunk->disk_start_sector;
|
||||
}
|
||||
else if (g_chain->disk_sector_size == 2048)
|
||||
{
|
||||
MapLba = (Sector - pchunk->img_start_sector) + pchunk->disk_start_sector;
|
||||
}
|
||||
else if (g_chain->disk_sector_size == 4096)
|
||||
{
|
||||
MapLba = ((Sector - pchunk->img_start_sector) >> 1) + pchunk->disk_start_sector;
|
||||
}
|
||||
|
||||
secLeft = pchunk->img_end_sector + 1 - Sector;
|
||||
|
@ -126,7 +185,7 @@ STATIC EFI_STATUS EFIAPI ventoy_read_iso_sector
|
|||
MapLba, secRead * 2048, pCurBuf);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
debug("Raw disk read block failed %r", Status);
|
||||
debug("Raw disk read block failed %r LBA:%lu Count:%u %p", Status, MapLba, secRead, pCurBuf);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -199,6 +258,96 @@ STATIC EFI_STATUS EFIAPI ventoy_read_iso_sector
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_write_iso_sector
|
||||
(
|
||||
IN UINT64 Sector,
|
||||
IN UINTN Count,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_LBA MapLba = 0;
|
||||
UINT32 i = 0;
|
||||
UINTN secLeft = 0;
|
||||
UINTN secRead = 0;
|
||||
UINT64 ReadStart = 0;
|
||||
UINT64 ReadEnd = 0;
|
||||
UINT8 *pCurBuf = (UINT8 *)Buffer;
|
||||
ventoy_img_chunk *pchunk = g_chunk;
|
||||
EFI_BLOCK_IO_PROTOCOL *pRawBlockIo = gBlockData.pRawBlockIo;
|
||||
|
||||
debug("write iso sector %lu count %u", Sector, Count);
|
||||
|
||||
ReadStart = Sector * 2048;
|
||||
ReadEnd = (Sector + Count) * 2048;
|
||||
|
||||
for (i = 0; Count > 0 && i < g_img_chunk_num; i++, pchunk++)
|
||||
{
|
||||
if (Sector >= pchunk->img_start_sector && Sector <= pchunk->img_end_sector)
|
||||
{
|
||||
if (g_chain->disk_sector_size == 512)
|
||||
{
|
||||
MapLba = (Sector - pchunk->img_start_sector) * 4 + pchunk->disk_start_sector;
|
||||
}
|
||||
else if (g_chain->disk_sector_size == 1024)
|
||||
{
|
||||
MapLba = (Sector - pchunk->img_start_sector) * 2 + pchunk->disk_start_sector;
|
||||
}
|
||||
else if (g_chain->disk_sector_size == 2048)
|
||||
{
|
||||
MapLba = (Sector - pchunk->img_start_sector) + pchunk->disk_start_sector;
|
||||
}
|
||||
else if (g_chain->disk_sector_size == 4096)
|
||||
{
|
||||
MapLba = ((Sector - pchunk->img_start_sector) >> 1) + pchunk->disk_start_sector;
|
||||
}
|
||||
|
||||
|
||||
secLeft = pchunk->img_end_sector + 1 - Sector;
|
||||
secRead = (Count < secLeft) ? Count : secLeft;
|
||||
|
||||
Status = pRawBlockIo->WriteBlocks(pRawBlockIo, pRawBlockIo->Media->MediaId,
|
||||
MapLba, secRead * 2048, pCurBuf);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
debug("Raw disk write block failed %r LBA:%lu Count:%u", Status, MapLba, secRead);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Count -= secRead;
|
||||
Sector += secRead;
|
||||
pCurBuf += secRead * 2048;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_block_io_ramdisk_write
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
(VOID)This;
|
||||
(VOID)MediaId;
|
||||
(VOID)Lba;
|
||||
(VOID)BufferSize;
|
||||
(VOID)Buffer;
|
||||
|
||||
if (!gSector512Mode)
|
||||
{
|
||||
return EFI_WRITE_PROTECTED;
|
||||
}
|
||||
|
||||
CopyMem(g_iso_data_buf + (Lba * 2048), Buffer, BufferSize);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_block_io_ramdisk_read
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
|
@ -213,7 +362,7 @@ EFI_STATUS EFIAPI ventoy_block_io_ramdisk_read
|
|||
(VOID)This;
|
||||
(VOID)MediaId;
|
||||
|
||||
CopyMem(Buffer, (char *)g_chain + (Lba * 2048), BufferSize);
|
||||
CopyMem(Buffer, g_iso_data_buf + (Lba * 2048), BufferSize);
|
||||
|
||||
if (g_blockio_start_record_bcd && FALSE == g_blockio_bcd_read_done)
|
||||
{
|
||||
|
@ -279,7 +428,7 @@ end:
|
|||
return Lba;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_block_io_read
|
||||
EFI_STATUS EFIAPI ventoy_block_io_read_real
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
|
@ -292,6 +441,8 @@ EFI_STATUS EFIAPI ventoy_block_io_read
|
|||
UINT32 j = 0;
|
||||
UINT32 lbacount = 0;
|
||||
UINT32 secNum = 0;
|
||||
UINT32 TmpNum = 0;
|
||||
UINT64 VirtSec = 0;
|
||||
UINT64 offset = 0;
|
||||
EFI_LBA curlba = 0;
|
||||
EFI_LBA lastlba = 0;
|
||||
|
@ -299,7 +450,7 @@ EFI_STATUS EFIAPI ventoy_block_io_read
|
|||
ventoy_sector_flag *cur_flag;
|
||||
ventoy_virt_chunk *node;
|
||||
|
||||
//debug("### ventoy_block_io_read sector:%u count:%u", (UINT32)Lba, (UINT32)BufferSize / 2048);
|
||||
debug("### block_io_read_real sector:%u count:%u Buffer:%p", (UINT32)Lba, (UINT32)BufferSize / 2048, Buffer);
|
||||
|
||||
secNum = BufferSize / 2048;
|
||||
|
||||
|
@ -315,6 +466,28 @@ EFI_STATUS EFIAPI ventoy_block_io_read
|
|||
{
|
||||
return ventoy_read_iso_sector(Lba, secNum, Buffer);
|
||||
}
|
||||
else if (offset < g_chain->real_img_size_in_bytes)
|
||||
{
|
||||
TmpNum = (g_chain->real_img_size_in_bytes - offset) / 2048;
|
||||
ventoy_read_iso_sector(Lba, TmpNum, Buffer);
|
||||
|
||||
Lba += TmpNum;
|
||||
secNum -= TmpNum;
|
||||
Buffer = (UINT8 *)Buffer + (g_chain->real_img_size_in_bytes - offset);
|
||||
offset = Lba * 2048;
|
||||
}
|
||||
|
||||
VirtSec = g_chain->virt_img_size_in_bytes / 2048;
|
||||
if (Lba >= VirtSec)
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
else if (Lba + secNum > VirtSec)
|
||||
{
|
||||
secNum = VirtSec - Lba;
|
||||
}
|
||||
|
||||
debug("XXX block_io_read_real sector:%u count:%u Buffer:%p", (UINT32)Lba, (UINT32)BufferSize / 2048, Buffer);
|
||||
|
||||
if (secNum > g_sector_flag_num)
|
||||
{
|
||||
|
@ -383,6 +556,42 @@ EFI_STATUS EFIAPI ventoy_block_io_read
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_block_io_read
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
UINT32 IoAlign = 0;
|
||||
VOID *NewBuf = NULL;
|
||||
EFI_STATUS Status = EFI_OUT_OF_RESOURCES;
|
||||
|
||||
if (gBlockData.pRawBlockIo && gBlockData.pRawBlockIo->Media)
|
||||
{
|
||||
IoAlign = gBlockData.pRawBlockIo->Media->IoAlign;
|
||||
}
|
||||
|
||||
if ((IoAlign == 0) || (((UINTN) Buffer & (IoAlign - 1)) == 0))
|
||||
{
|
||||
Status = ventoy_block_io_read_real(This, MediaId, Lba, BufferSize, Buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewBuf = AllocatePages(EFI_SIZE_TO_PAGES(BufferSize + IoAlign));
|
||||
if (NewBuf)
|
||||
{
|
||||
Status = ventoy_block_io_read_real(This, MediaId, Lba, BufferSize, NewBuf);
|
||||
CopyMem(Buffer, NewBuf, BufferSize);
|
||||
FreePages(NewBuf, EFI_SIZE_TO_PAGES(BufferSize + IoAlign));
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_block_io_write
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
|
@ -392,12 +601,21 @@ EFI_STATUS EFIAPI ventoy_block_io_write
|
|||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
UINT32 secNum = 0;
|
||||
UINT64 offset = 0;
|
||||
|
||||
(VOID)This;
|
||||
(VOID)MediaId;
|
||||
(VOID)Lba;
|
||||
(VOID)BufferSize;
|
||||
(VOID)Buffer;
|
||||
return EFI_WRITE_PROTECTED;
|
||||
|
||||
if (!gSector512Mode)
|
||||
{
|
||||
return EFI_WRITE_PROTECTED;
|
||||
}
|
||||
|
||||
secNum = BufferSize / 2048;
|
||||
offset = Lba * 2048;
|
||||
|
||||
return ventoy_write_iso_sector(Lba, secNum, Buffer);
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_block_io_flush(IN EFI_BLOCK_IO_PROTOCOL *This)
|
||||
|
@ -406,26 +624,74 @@ EFI_STATUS EFIAPI ventoy_block_io_flush(IN EFI_BLOCK_IO_PROTOCOL *This)
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC UINTN ventoy_get_current_device_path_id(VOID)
|
||||
{
|
||||
UINTN i = 0;
|
||||
UINTN Count = 0;
|
||||
UINTN MaxId = 0;
|
||||
UINTN CurId = 0;
|
||||
BOOLEAN Find = FALSE;
|
||||
EFI_HANDLE *Handles = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DevicePath = NULL;
|
||||
VENDOR_DEVICE_PATH *venPath = NULL;
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiDevicePathProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DevicePath->Type == HARDWARE_DEVICE_PATH && DevicePath->SubType == HW_VENDOR_DP)
|
||||
{
|
||||
venPath = (VENDOR_DEVICE_PATH *)DevicePath;
|
||||
if (CompareGuid(&venPath->Guid, &gVtoyBlockDevicePathGuid))
|
||||
{
|
||||
CurId = StrDecimalToUintn((CHAR16 *)(venPath + 1) + StrLen(L"ventoy_"));
|
||||
MaxId = MAX(MaxId, CurId);
|
||||
Find = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreePool(Handles);
|
||||
|
||||
return Find ? (MaxId + 1) : 0;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_fill_device_path(VOID)
|
||||
{
|
||||
UINTN CurVtoyDpId = 0;
|
||||
UINTN NameLen = 0;
|
||||
UINT8 TmpBuf[128] = {0};
|
||||
VENDOR_DEVICE_PATH *venPath = NULL;
|
||||
CHAR16 VtoyDpName[32];
|
||||
|
||||
CurVtoyDpId = ventoy_get_current_device_path_id();
|
||||
UnicodeSPrintAsciiFormat(VtoyDpName, sizeof(VtoyDpName), "ventoy_%03lu", CurVtoyDpId);
|
||||
|
||||
venPath = (VENDOR_DEVICE_PATH *)TmpBuf;
|
||||
NameLen = StrSize(VTOY_BLOCK_DEVICE_PATH_NAME);
|
||||
NameLen = StrSize(VtoyDpName);
|
||||
venPath->Header.Type = HARDWARE_DEVICE_PATH;
|
||||
venPath->Header.SubType = HW_VENDOR_DP;
|
||||
venPath->Header.Length[0] = sizeof(VENDOR_DEVICE_PATH) + NameLen;
|
||||
venPath->Header.Length[1] = 0;
|
||||
CopyMem(&venPath->Guid, &gVtoyBlockDevicePathGuid, sizeof(EFI_GUID));
|
||||
CopyMem(venPath + 1, VTOY_BLOCK_DEVICE_PATH_NAME, NameLen);
|
||||
CopyMem(venPath + 1, VtoyDpName, NameLen);
|
||||
|
||||
gBlockData.Path = AppendDevicePathNode(NULL, (EFI_DEVICE_PATH_PROTOCOL *)TmpBuf);
|
||||
gBlockData.DevicePathCompareLen = sizeof(VENDOR_DEVICE_PATH) + NameLen;
|
||||
|
||||
debug("gBlockData.Path=<%s>\n", ConvertDevicePathToText(gBlockData.Path, FALSE, FALSE));
|
||||
debug("gBlockData.Path=<%lu><%s>\n", CurVtoyDpId, ConvertDevicePathToText(gBlockData.Path, FALSE, FALSE));
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
@ -458,11 +724,7 @@ EFI_STATUS EFIAPI ventoy_connect_driver(IN EFI_HANDLE ControllerHandle, IN CONST
|
|||
continue;
|
||||
}
|
||||
|
||||
Status = Name2Protocol->GetDriverName(Name2Protocol, "en", &DriverName);
|
||||
if (EFI_ERROR(Status) || NULL == DriverName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
VENTOY_GET_COMPONENT_NAME(Name2Protocol, DriverName);
|
||||
|
||||
if (StrStr(DriverName, DrvName))
|
||||
{
|
||||
|
@ -475,7 +737,7 @@ EFI_STATUS EFIAPI ventoy_connect_driver(IN EFI_HANDLE ControllerHandle, IN CONST
|
|||
if (i < Count)
|
||||
{
|
||||
Status = gBS->ConnectController(ControllerHandle, DrvHandles, NULL, TRUE);
|
||||
debug("Connect partition driver:<%r>", Status);
|
||||
debug("ventoy_connect_driver:<%s> <%r>", DrvName, Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -500,11 +762,7 @@ EFI_STATUS EFIAPI ventoy_connect_driver(IN EFI_HANDLE ControllerHandle, IN CONST
|
|||
continue;
|
||||
}
|
||||
|
||||
Status = NameProtocol->GetDriverName(NameProtocol, "en", &DriverName);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
VENTOY_GET_COMPONENT_NAME(NameProtocol, DriverName);
|
||||
|
||||
if (StrStr(DriverName, DrvName))
|
||||
{
|
||||
|
@ -517,7 +775,7 @@ EFI_STATUS EFIAPI ventoy_connect_driver(IN EFI_HANDLE ControllerHandle, IN CONST
|
|||
if (i < Count)
|
||||
{
|
||||
Status = gBS->ConnectController(ControllerHandle, DrvHandles, NULL, TRUE);
|
||||
debug("Connect partition driver:<%r>", Status);
|
||||
debug("ventoy_connect_driver:<%s> <%r>", DrvName, Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -529,24 +787,386 @@ end:
|
|||
return Status;
|
||||
}
|
||||
|
||||
|
||||
STATIC BOOLEAN ventoy_filesystem_need_wrapper(IN CONST CHAR16 *DrvName)
|
||||
{
|
||||
UINTN i;
|
||||
CHAR16 UpperDrvName[256];
|
||||
|
||||
StrCpyS(UpperDrvName, 256, DrvName);
|
||||
|
||||
for (i = 0; i < 256 && UpperDrvName[i]; i++)
|
||||
{
|
||||
if (UpperDrvName[i] >= 'a' && UpperDrvName[i] <= 'z')
|
||||
{
|
||||
UpperDrvName[i] = 'A' + (UpperDrvName[i] - 'a');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* suppress some file system drivers
|
||||
* 1. rEFInd File System Driver
|
||||
*
|
||||
*/
|
||||
|
||||
if (StrStr(UpperDrvName, L"REFIND") && StrStr(UpperDrvName, L"FILE SYSTEM"))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
STATIC VOID ventoy_add_filesystem_wrapper
|
||||
(
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *DriverBindProtocol,
|
||||
IN CONST CHAR16 *DriverName
|
||||
)
|
||||
{
|
||||
UINTN j;
|
||||
|
||||
if (g_DriverBindWrapperCnt >= MAX_DRIVER_BIND_WRAPPER)
|
||||
{
|
||||
debug("driver binding wrapper overflow %lu", g_DriverBindWrapperCnt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ventoy_filesystem_need_wrapper(DriverName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (j = 0; j < g_DriverBindWrapperCnt; j++)
|
||||
{
|
||||
if (g_DriverBindWrapperList[j].DriverBinding == DriverBindProtocol)
|
||||
{
|
||||
debug("Duplicate driverbinding <%s> %p %lu %lu", DriverName, DriverBindProtocol, j, g_DriverBindWrapperCnt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j >= g_DriverBindWrapperCnt)
|
||||
{
|
||||
g_DriverBindWrapperList[g_DriverBindWrapperCnt].DriverBinding = DriverBindProtocol;
|
||||
g_DriverBindWrapperList[g_DriverBindWrapperCnt].pfOldSupport = DriverBindProtocol->Supported;
|
||||
g_DriverBindWrapperCnt++;
|
||||
debug("Add driverbinding <%s> %p %lu", DriverName, DriverBindProtocol, g_DriverBindWrapperCnt);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS ventoy_find_filesystem_driverbind(VOID)
|
||||
{
|
||||
UINTN i = 0;
|
||||
UINTN Count = 0;
|
||||
CHAR16 *DriverName = NULL;
|
||||
EFI_HANDLE *Handles = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_COMPONENT_NAME_PROTOCOL *NameProtocol = NULL;
|
||||
EFI_COMPONENT_NAME2_PROTOCOL *Name2Protocol = NULL;
|
||||
EFI_DRIVER_BINDING_PROTOCOL *DriverBindProtocol = NULL;
|
||||
|
||||
debug("ventoy_find_filesystem_driverbind...");
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentName2ProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiComponentName2ProtocolGuid, (VOID **)&Name2Protocol);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
VENTOY_GET_COMPONENT_NAME(Name2Protocol, DriverName);
|
||||
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiDriverBindingProtocolGuid, (VOID **)&DriverBindProtocol);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
debug("### 2 No DriverBind <%s> <%r>", DriverName, Status);
|
||||
continue;
|
||||
}
|
||||
|
||||
ventoy_add_filesystem_wrapper(DriverBindProtocol, DriverName);
|
||||
}
|
||||
|
||||
Count = 0;
|
||||
FreePool(Handles);
|
||||
Handles = NULL;
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentNameProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiComponentNameProtocolGuid, (VOID **)&NameProtocol);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
VENTOY_GET_COMPONENT_NAME(NameProtocol, DriverName);
|
||||
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiDriverBindingProtocolGuid, (VOID **)&DriverBindProtocol);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
debug("### 1 No DriverBind <%s> <%r>", DriverName, Status);
|
||||
continue;
|
||||
}
|
||||
|
||||
ventoy_add_filesystem_wrapper(DriverBindProtocol, DriverName);
|
||||
}
|
||||
|
||||
FreePool(Handles);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_wrapper_driver_bind_support
|
||||
(
|
||||
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
||||
IN EFI_HANDLE ControllerHandle,
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
|
||||
)
|
||||
{
|
||||
UINTN i;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DevicePath = NULL;
|
||||
EFI_DRIVER_BINDING_SUPPORTED pfOldSupport = NULL;
|
||||
|
||||
for (i = 0; i < g_DriverBindWrapperCnt; i++)
|
||||
{
|
||||
if (g_DriverBindWrapperList[i].DriverBinding == This)
|
||||
{
|
||||
pfOldSupport = g_DriverBindWrapperList[i].pfOldSupport;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug("ventoy_wrapper_driver_bind_support %lu %p", i, pfOldSupport);
|
||||
|
||||
if (!pfOldSupport)
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
Status = gBS->HandleProtocol(ControllerHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (0 == CompareMem(gBlockData.Path, DevicePath, gBlockData.DevicePathCompareLen))
|
||||
{
|
||||
debug("return EFI_UNSUPPORTED for ventoy");
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
out:
|
||||
return pfOldSupport(This, ControllerHandle, RemainingDevicePath);
|
||||
}
|
||||
|
||||
EFI_STATUS ventoy_disable_ex_filesystem(VOID)
|
||||
{
|
||||
UINTN i;
|
||||
|
||||
ventoy_find_filesystem_driverbind();
|
||||
|
||||
for (i = 0; i < g_DriverBindWrapperCnt; i++)
|
||||
{
|
||||
g_DriverBindWrapperList[i].DriverBinding->Supported = ventoy_wrapper_driver_bind_support;
|
||||
}
|
||||
|
||||
debug("Wrapper Ex Driver Binding %lu", g_DriverBindWrapperCnt);
|
||||
ventoy_debug_pause();
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS ventoy_enable_ex_filesystem(VOID)
|
||||
{
|
||||
UINTN i;
|
||||
|
||||
for (i = 0; i < g_DriverBindWrapperCnt; i++)
|
||||
{
|
||||
g_DriverBindWrapperList[i].DriverBinding->Supported = g_DriverBindWrapperList[i].pfOldSupport;
|
||||
}
|
||||
g_DriverBindWrapperCnt = 0;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_block_io_read_512
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
OUT VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_LBA Mod;
|
||||
UINTN ReadSize;
|
||||
UINT8 *CurBuf = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
||||
debug("ventoy_block_io_read_512 %lu %lu Buffer:%p\n", Lba, BufferSize / 512, Buffer);
|
||||
|
||||
CurBuf = (UINT8 *)Buffer;
|
||||
|
||||
Mod = Lba % 4;
|
||||
if (Mod > 0)
|
||||
{
|
||||
Status |= g_sector_2048_read(This, MediaId, Lba / 4, 2048, g_sector_buf);
|
||||
|
||||
if (BufferSize <= (4 - Mod) * 512)
|
||||
{
|
||||
CopyMem(CurBuf, g_sector_buf + Mod * 512, BufferSize);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadSize = (4 - Mod) * 512;
|
||||
CopyMem(CurBuf, g_sector_buf + Mod * 512, ReadSize);
|
||||
CurBuf += ReadSize;
|
||||
Lba += (4 - Mod);
|
||||
BufferSize -= ReadSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (BufferSize >= 2048)
|
||||
{
|
||||
ReadSize = BufferSize / 2048 * 2048;
|
||||
|
||||
Status |= g_sector_2048_read(This, MediaId, Lba / 4, ReadSize, CurBuf);
|
||||
CurBuf += ReadSize;
|
||||
|
||||
Lba += ReadSize / 512;
|
||||
BufferSize -= ReadSize;
|
||||
}
|
||||
|
||||
if (BufferSize > 0)
|
||||
{
|
||||
Status |= g_sector_2048_read(This, MediaId, Lba / 4, 2048, g_sector_buf);
|
||||
CopyMem(CurBuf, g_sector_buf, BufferSize);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_block_io_write_512
|
||||
(
|
||||
IN EFI_BLOCK_IO_PROTOCOL *This,
|
||||
IN UINT32 MediaId,
|
||||
IN EFI_LBA Lba,
|
||||
IN UINTN BufferSize,
|
||||
IN VOID *Buffer
|
||||
)
|
||||
{
|
||||
EFI_LBA Mod;
|
||||
UINTN ReadSize;
|
||||
UINT8 *CurBuf = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
||||
debug("ventoy_block_io_write_512 %lu %lu\n", Lba, BufferSize / 512);
|
||||
|
||||
CurBuf = (UINT8 *)Buffer;
|
||||
|
||||
Mod = Lba % 4;
|
||||
if (Mod > 0)
|
||||
{
|
||||
Status |= g_sector_2048_read(This, MediaId, Lba / 4, 2048, g_sector_buf);
|
||||
|
||||
if (BufferSize <= (4 - Mod) * 512)
|
||||
{
|
||||
CopyMem(g_sector_buf + Mod * 512, CurBuf, BufferSize);
|
||||
return g_sector_2048_write(This, MediaId, Lba / 4, 2048, g_sector_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadSize = (4 - Mod) * 512;
|
||||
CopyMem(g_sector_buf + Mod * 512, CurBuf, ReadSize);
|
||||
g_sector_2048_write(This, MediaId, Lba / 4, 2048, g_sector_buf);
|
||||
|
||||
CurBuf += ReadSize;
|
||||
Lba += (4 - Mod);
|
||||
BufferSize -= ReadSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (BufferSize >= 2048)
|
||||
{
|
||||
ReadSize = BufferSize / 2048 * 2048;
|
||||
|
||||
Status |= g_sector_2048_write(This, MediaId, Lba / 4, ReadSize, CurBuf);
|
||||
CurBuf += ReadSize;
|
||||
|
||||
Lba += ReadSize / 512;
|
||||
BufferSize -= ReadSize;
|
||||
}
|
||||
|
||||
if (BufferSize > 0)
|
||||
{
|
||||
Status |= g_sector_2048_read(This, MediaId, Lba / 4, 2048, g_sector_buf);
|
||||
|
||||
CopyMem(g_sector_buf, CurBuf, BufferSize);
|
||||
g_sector_2048_write(This, MediaId, Lba / 4, 2048, g_sector_buf);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI ventoy_install_blockio(IN EFI_HANDLE ImageHandle, IN UINT64 ImgSize)
|
||||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_BLOCK_IO_PROTOCOL *pBlockIo = &(gBlockData.BlockIo);
|
||||
|
||||
ventoy_fill_device_path();
|
||||
|
||||
debug("install block io protocol %p", ImageHandle);
|
||||
ventoy_debug_pause();
|
||||
|
||||
if (gSector512Mode)
|
||||
{
|
||||
gBlockData.Media.BlockSize = 512;
|
||||
gBlockData.Media.LastBlock = ImgSize / 512 - 1;
|
||||
gBlockData.Media.ReadOnly = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBlockData.Media.BlockSize = 2048;
|
||||
gBlockData.Media.LastBlock = ImgSize / 2048 - 1;
|
||||
gBlockData.Media.ReadOnly = TRUE;
|
||||
}
|
||||
|
||||
gBlockData.Media.BlockSize = 2048;
|
||||
gBlockData.Media.LastBlock = ImgSize / 2048 - 1;
|
||||
gBlockData.Media.ReadOnly = TRUE;
|
||||
gBlockData.Media.MediaPresent = 1;
|
||||
gBlockData.Media.LogicalBlocksPerPhysicalBlock = 1;
|
||||
|
||||
pBlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;
|
||||
pBlockIo->Media = &(gBlockData.Media);
|
||||
pBlockIo->Reset = ventoy_block_io_reset;
|
||||
pBlockIo->ReadBlocks = gMemdiskMode ? ventoy_block_io_ramdisk_read : ventoy_block_io_read;
|
||||
pBlockIo->WriteBlocks = ventoy_block_io_write;
|
||||
|
||||
if (gSector512Mode)
|
||||
{
|
||||
g_sector_2048_read = gMemdiskMode ? ventoy_block_io_ramdisk_read : ventoy_block_io_read;
|
||||
g_sector_2048_write = gMemdiskMode ? ventoy_block_io_ramdisk_write : ventoy_block_io_write;
|
||||
pBlockIo->ReadBlocks = ventoy_block_io_read_512;
|
||||
pBlockIo->WriteBlocks = ventoy_block_io_write_512;
|
||||
}
|
||||
else
|
||||
{
|
||||
pBlockIo->ReadBlocks = gMemdiskMode ? ventoy_block_io_ramdisk_read : ventoy_block_io_read;
|
||||
pBlockIo->WriteBlocks = ventoy_block_io_write;
|
||||
}
|
||||
|
||||
pBlockIo->FlushBlocks = ventoy_block_io_flush;
|
||||
|
||||
Status = gBS->InstallMultipleProtocolInterfaces(&gBlockData.Handle,
|
||||
|
@ -558,11 +1178,10 @@ EFI_STATUS EFIAPI ventoy_install_blockio(IN EFI_HANDLE ImageHandle, IN UINT64 Im
|
|||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
Status = ventoy_connect_driver(gBlockData.Handle, L"Disk I/O Driver");
|
||||
debug("Connect disk IO driver %r", Status);
|
||||
ventoy_debug_pause();
|
||||
|
||||
|
||||
Status = ventoy_connect_driver(gBlockData.Handle, L"Partition Driver");
|
||||
debug("Connect partition driver %r", Status);
|
||||
if (EFI_ERROR(Status))
|
||||
|
@ -656,8 +1275,16 @@ STATIC EFI_STATUS EFIAPI
|
|||
ventoy_wrapper_file_set_pos(EFI_FILE_HANDLE This, UINT64 Position)
|
||||
{
|
||||
(VOID)This;
|
||||
|
||||
if (Position <= g_efi_file_replace.FileSizeBytes)
|
||||
{
|
||||
g_efi_file_replace.CurPos = Position;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_efi_file_replace.CurPos = g_efi_file_replace.FileSizeBytes;
|
||||
}
|
||||
|
||||
g_efi_file_replace.CurPos = Position;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -772,6 +1399,18 @@ STATIC EFI_STATUS EFIAPI ventoy_wrapper_file_open
|
|||
CHAR8 TmpName[256];
|
||||
ventoy_virt_chunk *virt = NULL;
|
||||
|
||||
debug("## ventoy_wrapper_file_open <%s> ", Name);
|
||||
|
||||
if ((Mode & EFI_FILE_MODE_WRITE) > 0 && StrCmp(Name, L"\\loader\\random-seed") == 0)
|
||||
{
|
||||
if (gDebugPrint)
|
||||
{
|
||||
debug("## ventoy_wrapper_file_open return NOT_FOUND for random-seed %lx", Mode);
|
||||
sleep(3);
|
||||
}
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
Status = g_original_fopen(This, New, Name, Mode, Attributes);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
|
@ -807,6 +1446,11 @@ STATIC EFI_STATUS EFIAPI ventoy_wrapper_file_open
|
|||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
if (StrCmp(Name, L"\\EFI\\BOOT") == 0)
|
||||
{
|
||||
(*New)->Open = ventoy_wrapper_file_open;
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
|
@ -916,3 +1560,55 @@ EFI_STATUS ventoy_hook_keyboard_stop(VOID)
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Fixup the 1st cdrom influnce for Windows boot */
|
||||
#endif
|
||||
|
||||
STATIC EFI_STATUS EFIAPI ventoy_wrapper_locate_handle
|
||||
(
|
||||
IN EFI_LOCATE_SEARCH_TYPE SearchType,
|
||||
IN EFI_GUID *Protocol, OPTIONAL
|
||||
IN VOID *SearchKey, OPTIONAL
|
||||
IN OUT UINTN *BufferSize,
|
||||
OUT EFI_HANDLE *Buffer
|
||||
)
|
||||
{
|
||||
UINTN i;
|
||||
EFI_HANDLE Handle = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
|
||||
Status = g_org_locate_handle(SearchType, Protocol, SearchKey, BufferSize, Buffer);
|
||||
|
||||
if (EFI_SUCCESS == Status && Protocol && CompareGuid(&gEfiBlockIoProtocolGuid, Protocol))
|
||||
{
|
||||
for (i = 0; i < (*BufferSize) / sizeof(EFI_HANDLE); i++)
|
||||
{
|
||||
if (Buffer[i] == gBlockData.Handle)
|
||||
{
|
||||
Handle = Buffer[0];
|
||||
Buffer[0] = Buffer[i];
|
||||
Buffer[i] = Handle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
EFI_STATUS ventoy_hook_1st_cdrom_start(VOID)
|
||||
{
|
||||
g_org_locate_handle = gBS->LocateHandle;
|
||||
gBS->LocateHandle = ventoy_wrapper_locate_handle;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS ventoy_hook_1st_cdrom_stop(VOID)
|
||||
{
|
||||
gBS->LocateHandle = g_org_locate_handle;
|
||||
g_org_locate_handle = NULL;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
/******************************************************************************
|
||||
* Memhole.c
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/UefiApplicationEntryPoint.h>
|
||||
#include <Protocol/LoadedImage.h>
|
||||
#include <Guid/FileInfo.h>
|
||||
#include <Guid/FileSystemInfo.h>
|
||||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/RamDisk.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <VtoyUtil.h>
|
||||
|
||||
STATIC BOOLEAN IsMemContiguous
|
||||
(
|
||||
IN CONST EFI_MEMORY_DESCRIPTOR *Prev,
|
||||
IN CONST EFI_MEMORY_DESCRIPTOR *Curr,
|
||||
IN CONST EFI_MEMORY_DESCRIPTOR *Next
|
||||
)
|
||||
{
|
||||
UINTN Addr1 = 0;
|
||||
UINTN Addr2 = 0;
|
||||
|
||||
if (Prev == NULL || Curr == NULL || Next == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (Prev->Type == EfiBootServicesData &&
|
||||
Curr->Type == EfiConventionalMemory &&
|
||||
Next->Type == EfiBootServicesData)
|
||||
{
|
||||
Addr1 = Prev->PhysicalStart + MultU64x64(SIZE_4KB, Prev->NumberOfPages);
|
||||
Addr2 = Curr->PhysicalStart + MultU64x64(SIZE_4KB, Curr->NumberOfPages);
|
||||
|
||||
if (Addr1 == Curr->PhysicalStart && Addr2 == Next->PhysicalStart)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
STATIC EFI_MEMORY_DESCRIPTOR* GetMemDesc
|
||||
(
|
||||
OUT UINTN *pSize,
|
||||
OUT UINTN *pItemSize,
|
||||
OUT UINTN *pDescCount
|
||||
)
|
||||
{
|
||||
UINTN Size = 0;
|
||||
UINTN MapKey = 0;
|
||||
UINTN ItemSize = 0;
|
||||
UINTN DescCount = 0;
|
||||
UINT32 Version = 0;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_MEMORY_DESCRIPTOR *pDesc = NULL;
|
||||
EFI_MEMORY_DESCRIPTOR *Curr = NULL;
|
||||
|
||||
Status = gBS->GetMemoryMap(&Size, pDesc, &MapKey, &ItemSize, &Version);
|
||||
if (EFI_BUFFER_TOO_SMALL != Status)
|
||||
{
|
||||
debug("GetMemoryMap: %r", Status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Size += SIZE_1KB;
|
||||
pDesc = AllocatePool(Size);
|
||||
if (!pDesc)
|
||||
{
|
||||
debug("AllocatePool: %lu failed", Size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZeroMem(pDesc, Size);
|
||||
|
||||
Status = gBS->GetMemoryMap(&Size, pDesc, &MapKey, &ItemSize, &Version);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
debug("GetMemoryMap: %r", Status);
|
||||
FreePool(pDesc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Curr = pDesc;
|
||||
while (Curr && Curr < (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)pDesc + Size))
|
||||
{
|
||||
DescCount++;
|
||||
Curr = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)Curr + ItemSize);
|
||||
}
|
||||
|
||||
*pSize = Size;
|
||||
*pItemSize = ItemSize;
|
||||
*pDescCount = DescCount;
|
||||
|
||||
debug("GetMemoryMap: ItemSize:%lu Count:%lu", ItemSize, DescCount);
|
||||
|
||||
return pDesc;
|
||||
}
|
||||
|
||||
EFI_STATUS FixWindowsMemhole(IN EFI_HANDLE ImageHandle, IN CONST CHAR16 *CmdLine)
|
||||
{
|
||||
UINTN Size = 0;
|
||||
UINTN ItemSize = 0;
|
||||
UINTN DescCount = 0;
|
||||
UINTN TotalMem = 0;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_PHYSICAL_ADDRESS AllocAddr = 0;
|
||||
EFI_MEMORY_DESCRIPTOR *pDescs = NULL;
|
||||
EFI_MEMORY_DESCRIPTOR *Prev = NULL;
|
||||
EFI_MEMORY_DESCRIPTOR *Next = NULL;
|
||||
EFI_MEMORY_DESCRIPTOR *Curr = NULL;
|
||||
|
||||
(VOID)ImageHandle;
|
||||
(VOID)CmdLine;
|
||||
|
||||
pDescs = GetMemDesc(&Size, &ItemSize, &DescCount);
|
||||
if (!pDescs)
|
||||
{
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (DescCount < 500)
|
||||
{
|
||||
FreePool(pDescs);
|
||||
Printf("There is no need to fixup (%lu)\n", DescCount);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Curr = pDescs;
|
||||
while ((UINT8 *)Curr < (UINT8 *)pDescs + Size)
|
||||
{
|
||||
Next = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)Curr + ItemSize);
|
||||
|
||||
if (IsMemContiguous(Prev, Curr, Next))
|
||||
{
|
||||
AllocAddr = Curr->PhysicalStart;
|
||||
Status = gBS->AllocatePages(AllocateAddress, EfiBootServicesData, Curr->NumberOfPages, &AllocAddr);
|
||||
if (EFI_SUCCESS == Status)
|
||||
{
|
||||
TotalMem += MultU64x64(SIZE_4KB, Curr->NumberOfPages);
|
||||
}
|
||||
}
|
||||
|
||||
Prev = Curr;
|
||||
Curr = Next;
|
||||
}
|
||||
|
||||
Printf("Fixup Windows mmap issue OK (%lu)\n", TotalMem);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/******************************************************************************
|
||||
* VtoyDrv.c
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/UefiApplicationEntryPoint.h>
|
||||
#include <Protocol/LoadedImage.h>
|
||||
#include <Guid/FileInfo.h>
|
||||
#include <Guid/FileSystemInfo.h>
|
||||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/RamDisk.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <VtoyUtil.h>
|
||||
|
||||
STATIC UINTN g_EfiDriverNameCnt = 0;
|
||||
STATIC CHAR16 *g_EfiDriverNameList[1024] = { NULL };
|
||||
|
||||
STATIC EFI_STATUS AddEfiDriverName(IN CHAR16 *DriverName)
|
||||
{
|
||||
UINTN i = 0;
|
||||
|
||||
if (g_EfiDriverNameCnt >= 1024)
|
||||
{
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
for (i = 0; i < g_EfiDriverNameCnt; i++)
|
||||
{
|
||||
if (g_EfiDriverNameList[i] && StrCmp(g_EfiDriverNameList[i], DriverName) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= g_EfiDriverNameCnt)
|
||||
{
|
||||
g_EfiDriverNameList[g_EfiDriverNameCnt] = DriverName;
|
||||
g_EfiDriverNameCnt++;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS ShowEfiDrivers(IN EFI_HANDLE ImageHandle, IN CONST CHAR16 *CmdLine)
|
||||
{
|
||||
UINTN i = 0;
|
||||
UINTN Count = 0;
|
||||
CHAR16 *DriverName = NULL;
|
||||
EFI_HANDLE *Handles = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
EFI_COMPONENT_NAME_PROTOCOL *NameProtocol = NULL;
|
||||
EFI_COMPONENT_NAME2_PROTOCOL *Name2Protocol = NULL;
|
||||
|
||||
(VOID)ImageHandle;
|
||||
(VOID)CmdLine;
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentName2ProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiComponentName2ProtocolGuid, (VOID **)&Name2Protocol);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DriverName = NULL;
|
||||
Status = VtoyGetComponentName(2, Name2Protocol, &DriverName);
|
||||
if ((!EFI_ERROR(Status)) && (DriverName))
|
||||
{
|
||||
AddEfiDriverName(DriverName);
|
||||
}
|
||||
}
|
||||
|
||||
Count = 0;
|
||||
FreePool(Handles);
|
||||
Handles = NULL;
|
||||
|
||||
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentNameProtocolGuid,
|
||||
NULL, &Count, &Handles);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (i = 0; i < Count; i++)
|
||||
{
|
||||
Status = gBS->HandleProtocol(Handles[i], &gEfiComponentNameProtocolGuid, (VOID **)&NameProtocol);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DriverName = NULL;
|
||||
Status = VtoyGetComponentName(1, Name2Protocol, &DriverName);
|
||||
if ((!EFI_ERROR(Status)) && (DriverName))
|
||||
{
|
||||
AddEfiDriverName(DriverName);
|
||||
}
|
||||
}
|
||||
|
||||
FreePool(Handles);
|
||||
|
||||
for (i = 0; i < g_EfiDriverNameCnt; i++)
|
||||
{
|
||||
Printf("%2d %s\n", i, g_EfiDriverNameList[i]);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/******************************************************************************
|
||||
* VtoyUtil.c
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Uefi.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/UefiApplicationEntryPoint.h>
|
||||
#include <Protocol/LoadedImage.h>
|
||||
#include <Guid/FileInfo.h>
|
||||
#include <Guid/FileSystemInfo.h>
|
||||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/RamDisk.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <VtoyUtil.h>
|
||||
|
||||
BOOLEAN gVtoyDebugPrint = FALSE;
|
||||
STATIC CONST CHAR16 *gCurFeature= NULL;
|
||||
STATIC CHAR16 *gCmdLine = NULL;
|
||||
STATIC grub_env_printf_pf g_env_printf = NULL;
|
||||
|
||||
STATIC VtoyUtilFeature gFeatureList[] =
|
||||
{
|
||||
{ L"fix_windows_mmap", FixWindowsMemhole },
|
||||
{ L"show_efi_drivers", ShowEfiDrivers },
|
||||
};
|
||||
|
||||
EFI_STATUS VtoyGetComponentName(IN UINTN Ver, IN VOID *Protocol, OUT CHAR16 **DriverName)
|
||||
{
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
CHAR16 *DrvName = NULL;
|
||||
EFI_COMPONENT_NAME_PROTOCOL *NameProtocol = NULL;
|
||||
EFI_COMPONENT_NAME2_PROTOCOL *Name2Protocol = NULL;
|
||||
|
||||
if (1 == Ver)
|
||||
{
|
||||
NameProtocol = (EFI_COMPONENT_NAME_PROTOCOL *)Protocol;
|
||||
Status = NameProtocol->GetDriverName(Protocol, "en", &DrvName);
|
||||
if (EFI_ERROR(Status) || NULL == DrvName)
|
||||
{
|
||||
Status = NameProtocol->GetDriverName(Protocol, "eng", &DrvName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Name2Protocol = (EFI_COMPONENT_NAME2_PROTOCOL *)Protocol;
|
||||
Status = Name2Protocol->GetDriverName(Protocol, "en", &DrvName);
|
||||
if (EFI_ERROR(Status) || NULL == DrvName)
|
||||
{
|
||||
Status = Name2Protocol->GetDriverName(Protocol, "eng", &DrvName);
|
||||
}
|
||||
}
|
||||
|
||||
*DriverName = DrvName;
|
||||
return Status;
|
||||
}
|
||||
|
||||
VOID EFIAPI VtoyUtilDebug(IN CONST CHAR8 *Format, ...)
|
||||
{
|
||||
VA_LIST Marker;
|
||||
CHAR8 Buffer[512];
|
||||
|
||||
VA_START (Marker, Format);
|
||||
AsciiVSPrint(Buffer, sizeof(Buffer), Format, Marker);
|
||||
VA_END (Marker);
|
||||
|
||||
if (g_env_printf)
|
||||
{
|
||||
g_env_printf("%s", Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC EFI_STATUS ParseCmdline(IN EFI_HANDLE ImageHandle)
|
||||
{
|
||||
CHAR16 *pPos = NULL;
|
||||
CHAR16 *pCmdLine = NULL;
|
||||
EFI_STATUS Status = EFI_SUCCESS;
|
||||
ventoy_grub_param *pGrubParam = NULL;
|
||||
EFI_LOADED_IMAGE_PROTOCOL *pImageInfo = NULL;
|
||||
|
||||
Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&pImageInfo);
|
||||
if (EFI_ERROR(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
pCmdLine = (CHAR16 *)AllocatePool(pImageInfo->LoadOptionsSize + 4);
|
||||
SetMem(pCmdLine, pImageInfo->LoadOptionsSize + 4, 0);
|
||||
CopyMem(pCmdLine, pImageInfo->LoadOptions, pImageInfo->LoadOptionsSize);
|
||||
|
||||
if (StrStr(pCmdLine, L"vtoyefitest"))
|
||||
{
|
||||
gST->ConOut->OutputString(gST->ConOut, L"\r\n##########################");
|
||||
gST->ConOut->OutputString(gST->ConOut, L"\r\n######### VTOY #########");
|
||||
gST->ConOut->OutputString(gST->ConOut, L"\r\n##########################");
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
if (StrStr(pCmdLine, L"debug"))
|
||||
{
|
||||
gVtoyDebugPrint = TRUE;
|
||||
}
|
||||
|
||||
pPos = StrStr(pCmdLine, L"env_param=");
|
||||
if (!pPos)
|
||||
{
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
pGrubParam = (ventoy_grub_param *)StrHexToUintn(pPos + StrLen(L"env_param="));
|
||||
g_env_printf = pGrubParam->grub_env_printf;
|
||||
|
||||
pPos = StrStr(pCmdLine, L"feature=");
|
||||
if (!pPos)
|
||||
{
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
gCurFeature = pPos + StrLen(L"feature=");
|
||||
|
||||
gCmdLine = pCmdLine;
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS EFIAPI VtoyUtilEfiMain
|
||||
(
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
UINTN i;
|
||||
UINTN Len;
|
||||
|
||||
ParseCmdline(ImageHandle);
|
||||
|
||||
for (i = 0; gCurFeature && i < ARRAY_SIZE(gFeatureList); i++)
|
||||
{
|
||||
Len = StrLen(gFeatureList[i].Cmd);
|
||||
if (StrnCmp(gFeatureList[i].Cmd, gCurFeature, Len) == 0)
|
||||
{
|
||||
debug("Find main proc <%s>", gFeatureList[i].Cmd);
|
||||
gFeatureList[i].MainProc(ImageHandle, gCurFeature + Len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gCmdLine)
|
||||
{
|
||||
FreePool(gCmdLine);
|
||||
gCmdLine = NULL;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/******************************************************************************
|
||||
* VtoyUtil.h
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VTOYUTIL_H__
|
||||
#define __VTOYUTIL_H__
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef EFI_STATUS (*VTOY_UTIL_PROC_PF)(IN EFI_HANDLE ImageHandle, IN CONST CHAR16 *CmdLine);
|
||||
typedef int (*grub_env_set_pf)(const char *name, const char *val);
|
||||
typedef const char * (*grub_env_get_pf)(const char *name);
|
||||
typedef int (*grub_env_printf_pf)(const char *fmt, ...);
|
||||
|
||||
typedef struct ventoy_grub_param_file_replace
|
||||
{
|
||||
UINT32 magic;
|
||||
char old_file_name[4][256];
|
||||
UINT32 old_file_cnt;
|
||||
UINT32 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;
|
||||
grub_env_printf_pf grub_env_printf;
|
||||
}ventoy_grub_param;
|
||||
#pragma pack()
|
||||
|
||||
|
||||
typedef struct VtoyUtilFeature
|
||||
{
|
||||
CONST CHAR16 *Cmd;
|
||||
VTOY_UTIL_PROC_PF MainProc;
|
||||
}VtoyUtilFeature;
|
||||
|
||||
extern BOOLEAN gVtoyDebugPrint;
|
||||
VOID EFIAPI VtoyUtilDebug(IN CONST CHAR8 *Format, ...);
|
||||
#define debug(expr, ...) if (gVtoyDebugPrint) VtoyUtilDebug("[VTOY] "expr"\n", ##__VA_ARGS__)
|
||||
#define Printf VtoyUtilDebug
|
||||
|
||||
EFI_STATUS VtoyGetComponentName(IN UINTN Ver, IN VOID *Protocol, OUT CHAR16 **DriverName);
|
||||
EFI_STATUS FixWindowsMemhole(IN EFI_HANDLE ImageHandle, IN CONST CHAR16 *CmdLine);
|
||||
EFI_STATUS ShowEfiDrivers(IN EFI_HANDLE ImageHandle, IN CONST CHAR16 *CmdLine);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#************************************************************************************
|
||||
# Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#************************************************************************************
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = VtoyUtil
|
||||
FILE_GUID = a43466a0-68c6-469d-ba4b-678bbe90bc47
|
||||
MODULE_TYPE = UEFI_APPLICATION
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = VtoyUtilEfiMain
|
||||
|
||||
|
||||
[Sources]
|
||||
VtoyUtil.h
|
||||
VtoyUtil.c
|
||||
VtoyDrv.c
|
||||
Memhole.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
ShellPkg/ShellPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
UefiApplicationEntryPoint
|
||||
UefiLib
|
||||
DebugLib
|
||||
|
||||
[Guids]
|
||||
gShellVariableGuid
|
||||
gEfiVirtualCdGuid
|
||||
gEfiFileInfoGuid
|
||||
|
||||
[Protocols]
|
||||
gEfiLoadedImageProtocolGuid
|
||||
gEfiBlockIoProtocolGuid
|
||||
gEfiDevicePathProtocolGuid
|
||||
gEfiSimpleFileSystemProtocolGuid
|
||||
gEfiRamDiskProtocolGuid
|
||||
gEfiAbsolutePointerProtocolGuid
|
||||
gEfiAcpiTableProtocolGuid
|
||||
gEfiBlockIo2ProtocolGuid
|
||||
gEfiBusSpecificDriverOverrideProtocolGuid
|
||||
gEfiComponentNameProtocolGuid
|
||||
gEfiComponentName2ProtocolGuid
|
||||
gEfiDriverBindingProtocolGuid
|
||||
gEfiDiskIoProtocolGuid
|
||||
gEfiDiskIo2ProtocolGuid
|
||||
gEfiGraphicsOutputProtocolGuid
|
||||
gEfiHiiConfigAccessProtocolGuid
|
||||
gEfiHiiFontProtocolGuid
|
||||
gEfiLoadFileProtocolGuid
|
||||
gEfiLoadFile2ProtocolGuid
|
||||
gEfiLoadedImageProtocolGuid
|
||||
gEfiLoadedImageDevicePathProtocolGuid
|
||||
gEfiPciIoProtocolGuid
|
||||
gEfiSerialIoProtocolGuid
|
||||
gEfiSimpleTextInProtocolGuid
|
||||
gEfiSimpleTextInputExProtocolGuid
|
||||
gEfiSimpleTextOutProtocolGuid
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -204,6 +204,8 @@
|
|||
|
||||
[Components]
|
||||
MdeModulePkg/Application/Ventoy/Ventoy.inf
|
||||
MdeModulePkg/Application/VtoyUtil/VtoyUtil.inf
|
||||
MdeModulePkg/Application/VDiskChain/VDiskChain.inf
|
||||
MdeModulePkg/Application/HelloWorld/HelloWorld.inf
|
||||
MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
|
||||
MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
|
||||
|
|
|
@ -743,8 +743,8 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
if (!ctx.filename && dirent.namelen == 1 && name[0] == 1)
|
||||
ctx.filename = (char *) "..";
|
||||
|
||||
if (g_fs_name_nocase)
|
||||
ctx.type |= GRUB_FSHELP_CASE_INSENSITIVE;
|
||||
if (g_fs_name_nocase)
|
||||
ctx.type |= GRUB_FSHELP_CASE_INSENSITIVE;
|
||||
|
||||
/* The filename was not stored in a rock ridge entry. Read it
|
||||
from the iso9660 filesystem. */
|
||||
|
|
|
@ -70,10 +70,10 @@ SetLogging(VOID)
|
|||
CHAR16 LogVar[4];
|
||||
UINTN i, LogVarSize = sizeof(LogVar);
|
||||
|
||||
i = LogVarSize;
|
||||
i = LogVarSize;
|
||||
Status = RT->GetVariable(L"FS_NAME_NOCASE", &ShellVariable, NULL, &i, LogVar);
|
||||
if (Status == EFI_SUCCESS)
|
||||
g_fs_name_nocase = 1;
|
||||
if (Status == EFI_SUCCESS)
|
||||
g_fs_name_nocase = 1;
|
||||
|
||||
Status = RT->GetVariable(L"FS_LOGGING", &ShellVariable, NULL, &LogVarSize, LogVar);
|
||||
if (Status == EFI_SUCCESS)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
1
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
|
||||
rm -f ventoy_efiboot.img.*
|
||||
|
||||
cd ISO
|
||||
mkisofs -R -D -sysid VENTOY -V VENTOY -P "longpanda admin@ventoy.net" -p 'https://www.ventoy.net' -o ../ventoy_efiboot.img ./
|
||||
cd ..
|
||||
|
||||
xz --check=crc32 ventoy_efiboot.img
|
||||
|
||||
rm -f ../INSTALL/ventoy/ventoy_efiboot.img.xz
|
||||
cp -a ventoy_efiboot.img.xz ../INSTALL/ventoy/
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
|
||||
CUR="$PWD"
|
||||
|
||||
if ! [ -e LIBFUSE ]; then
|
||||
./buidlibfuse.sh
|
||||
fi
|
||||
|
||||
rm -f EXFAT/shared/*
|
||||
|
||||
|
||||
rm -rf exfat-1.3.0
|
||||
unzip exfat-1.3.0.zip
|
||||
sed "/printf.*VERSION/a\ if (access(\"/etc/initrd-release\", F_OK) >= 0) argv[0][0] = '@';" -i exfat-1.3.0/fuse/main.c
|
||||
|
||||
cd exfat-1.3.0
|
||||
autoreconf --install
|
||||
./configure --prefix="$CUR" CFLAGS='-O2 -D_FILE_OFFSET_BITS=64' FUSE_CFLAGS="-I$CUR/LIBFUSE/include/" FUSE_LIBS="$CUR/LIBFUSE/lib/libfuse.a -lpthread -ldl"
|
||||
make
|
||||
|
||||
strip --strip-all fuse/mount.exfat-fuse
|
||||
strip --strip-all mkfs/mkexfatfs
|
||||
|
||||
cp fuse/mount.exfat-fuse ../EXFAT/shared/mount.exfat-fuse
|
||||
cp mkfs/mkexfatfs ../EXFAT/shared/mkexfatfs
|
||||
|
||||
cd ..
|
||||
rm -rf exfat-1.3.0
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/bash
|
||||
|
||||
CUR="$PWD"
|
||||
|
||||
rm -rf libfuse
|
||||
rm -rf LIBFUSE
|
||||
|
||||
if [ -e mirrors-libfuse-fuse-2.9.9.zip ]; then
|
||||
unzip mirrors-libfuse-fuse-2.9.9.zip
|
||||
cd libfuse
|
||||
else
|
||||
unzip libfuse-fuse-2.9.9.zip
|
||||
cd libfuse-fuse-2.9.9
|
||||
fi
|
||||
|
||||
./makeconf.sh
|
||||
|
||||
./configure --prefix="$CUR/LIBFUSE"
|
||||
|
||||
sed '/#define *__u64/d' -i include/fuse_kernel.h
|
||||
sed '/#define *__s64/d' -i include/fuse_kernel.h
|
||||
|
||||
sed 's/__u64/uint64_t/g' -i include/fuse_kernel.h
|
||||
sed 's/__s64/int64_t/g' -i include/fuse_kernel.h
|
||||
|
||||
make -j 16
|
||||
make install
|
||||
cd ..
|
||||
rm -rf libfuse
|
|
@ -11,10 +11,16 @@ else
|
|||
opt=-lrt
|
||||
fi
|
||||
|
||||
#
|
||||
# use musl-c to build for x86_64
|
||||
#
|
||||
|
||||
export C_INCLUDE_PATH=$LIBFUSE_DIR/include
|
||||
|
||||
rm -f $name
|
||||
gcc -static -O2 -D_FILE_OFFSET_BITS=64 vtoy_fuse_iso.c -o $name $LIBFUSE_DIR/lib/libfuse.a -lpthread -ldl $opt
|
||||
gcc -specs "/usr/local/musl/lib/musl-gcc.specs" -static -O2 -D_FILE_OFFSET_BITS=64 vtoy_fuse_iso.c $LIBFUSE_DIR/lib/libfuse.a -o $name
|
||||
|
||||
strip --strip-all $name
|
||||
|
||||
if [ -e $name ]; then
|
||||
echo -e "\n############### SUCCESS $name ##################\n"
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
|
||||
CUR="$PWD"
|
||||
|
||||
LIBFUSE_DIR=$CUR/LIBFUSE
|
||||
|
||||
name=vtoy_fuse_iso_aa64
|
||||
|
||||
export C_INCLUDE_PATH=$LIBFUSE_DIR/include
|
||||
|
||||
rm -f $name
|
||||
aarch64-buildroot-linux-uclibc-gcc -static -O2 -D_FILE_OFFSET_BITS=64 vtoy_fuse_iso.c -o $name $LIBFUSE_DIR/lib/libfuse.a
|
||||
|
||||
if [ -e $name ]; then
|
||||
echo -e "\n############### SUCCESS $name ##################\n"
|
||||
else
|
||||
echo -e "\n############### FAILED $name ##################\n"
|
||||
fi
|
||||
|
||||
aarch64-buildroot-linux-uclibc-strip --strip-all $name
|
||||
|
|
@ -7,6 +7,8 @@
|
|||
#
|
||||
#
|
||||
|
||||
# use mini-native-x86_64 UCLIBC to build for x86_64
|
||||
|
||||
|
||||
CUR="$PWD"
|
||||
LIBFUSE_DIR=$CUR/LIBFUSE
|
||||
|
@ -31,7 +33,7 @@ fi
|
|||
|
||||
./makeconf.sh
|
||||
|
||||
./configure --prefix="$LIBFUSE_DIR"
|
||||
./configure --prefix="$LIBFUSE_DIR" CFLAGS='-specs /usr/local/musl/lib/musl-gcc.specs'
|
||||
make -j 16
|
||||
make install
|
||||
cd ..
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#!/bin/bash
|
||||
|
||||
#
|
||||
#
|
||||
# Package Dependency:
|
||||
# gcc automake autoconf gettext gettext-devel libtool unzip
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
CUR="$PWD"
|
||||
LIBFUSE_DIR=$CUR/LIBFUSE
|
||||
|
||||
rm -rf libfuse
|
||||
rm -rf $LIBFUSE_DIR
|
||||
|
||||
# please download https://codeload.github.com/libfuse/libfuse/zip/fuse-2.9.9
|
||||
if [ -e ../ExFAT/mirrors-libfuse-fuse-2.9.9.zip ]; then
|
||||
rm -rf libfuse
|
||||
unzip ../ExFAT/mirrors-libfuse-fuse-2.9.9.zip
|
||||
cd libfuse
|
||||
elif [ -e ../ExFAT/libfuse-fuse-2.9.9.zip ]; then
|
||||
rm -rf libfuse-fuse-2.9.9
|
||||
unzip ../ExFAT/libfuse-fuse-2.9.9.zip
|
||||
cd libfuse-fuse-2.9.9
|
||||
else
|
||||
echo "Please download mirrors-libfuse-fuse-2.9.9.zip first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
./makeconf.sh
|
||||
|
||||
sed '/#define *__u64/d' -i include/fuse_kernel.h
|
||||
sed '/#define *__s64/d' -i include/fuse_kernel.h
|
||||
|
||||
sed 's/__u64/uint64_t/g' -i include/fuse_kernel.h
|
||||
sed 's/__s64/int64_t/g' -i include/fuse_kernel.h
|
||||
|
||||
./configure --prefix="$LIBFUSE_DIR" --host=aarch64 CC=aarch64-buildroot-linux-uclibc-gcc
|
||||
|
||||
|
||||
make -j 16
|
||||
make install
|
||||
cd ..
|
||||
rm -rf libfuse
|
|
@ -114,11 +114,12 @@ static int ventoy_iso_open(const char *path, struct fuse_file_info *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ventoy_read_iso_sector(uint32_t sector, uint32_t num, void *buf)
|
||||
static int ventoy_read_iso_sector(uint32_t sector, uint32_t num, char *buf)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
uint32_t leftSec = 0;
|
||||
uint32_t readSec = 0;
|
||||
off_t offset = 0;
|
||||
dmtable_entry *entry = NULL;
|
||||
|
||||
for (i = 0; i < g_disk_entry_num && num > 0; i++)
|
||||
|
@ -127,14 +128,15 @@ static int ventoy_read_iso_sector(uint32_t sector, uint32_t num, void *buf)
|
|||
|
||||
if (sector >= entry->isoSector && sector < entry->isoSector + entry->sectorNum)
|
||||
{
|
||||
lseek(g_disk_fd, (entry->diskSector + (sector - entry->isoSector)) * 512, SEEK_SET);
|
||||
offset = (entry->diskSector + (sector - entry->isoSector)) * 512;
|
||||
|
||||
leftSec = entry->sectorNum - (sector - entry->isoSector);
|
||||
readSec = (leftSec > num) ? num : leftSec;
|
||||
|
||||
read(g_disk_fd, buf, readSec * 512);
|
||||
pread(g_disk_fd, buf, readSec * 512, offset);
|
||||
|
||||
sector += readSec;
|
||||
buf += readSec * 512;
|
||||
num -= readSec;
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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()
|
|
@ -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
|
|
@ -100,6 +100,10 @@ kernel = {
|
|||
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';
|
||||
|
||||
|
@ -114,6 +118,7 @@ kernel = {
|
|||
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;
|
||||
|
@ -310,6 +315,15 @@ kernel = {
|
|||
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;
|
||||
|
@ -809,6 +823,16 @@ module = {
|
|||
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;
|
||||
|
@ -818,6 +842,7 @@ module = {
|
|||
enable = sparc64_ieee1275;
|
||||
enable = powerpc_ieee1275;
|
||||
enable = mips_arc;
|
||||
enable = mips64_efi;
|
||||
enable = ia64_efi;
|
||||
enable = arm_efi;
|
||||
enable = arm64_efi;
|
||||
|
@ -986,6 +1011,7 @@ module = {
|
|||
module = {
|
||||
name = loadenv;
|
||||
common = commands/loadenv.c;
|
||||
common = commands/loadenv.h;
|
||||
common = lib/envblk.c;
|
||||
};
|
||||
|
||||
|
@ -1577,12 +1603,22 @@ module = {
|
|||
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/lzx.c;
|
||||
common = ventoy/xpress.c;
|
||||
common = ventoy/huffman.c;
|
||||
common = ventoy/miniz.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = setkey;
|
||||
common = term/setkey.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
@ -1647,6 +1683,8 @@ module = {
|
|||
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;
|
||||
|
@ -1659,6 +1697,7 @@ module = {
|
|||
extra_dist = kern/powerpc/cache_flush.S;
|
||||
|
||||
enable = mips;
|
||||
enable = mips64;
|
||||
enable = powerpc;
|
||||
enable = x86;
|
||||
enable = i386_xen_pvh;
|
||||
|
@ -1789,6 +1828,7 @@ module = {
|
|||
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;
|
||||
|
@ -1895,6 +1935,7 @@ module = {
|
|||
enable = riscv32_efi;
|
||||
enable = riscv64_efi;
|
||||
enable = mips;
|
||||
enable = mips64_efi;
|
||||
};
|
||||
|
||||
module = {
|
||||
|
|
|
@ -479,7 +479,7 @@ LOCAL(stop):
|
|||
jmp LOCAL(stop)
|
||||
|
||||
ventoy_uuid: .ascii "XXXXXXXXXXXXXXXX"
|
||||
notification_string: .asciz "GR"
|
||||
notification_string: .asciz "VT"
|
||||
geometry_error_string: .asciz "Ge"
|
||||
hd_probe_error_string: .asciz "HD"
|
||||
read_error_string: .asciz "Rd"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
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 %d%% ", (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 100%% \n\r\n");
|
||||
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;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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]);
|
||||
grub_printf (" %s\n", args[i]);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/script_sh.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/legacy_parse.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/auth.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/partition.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/partition.h>
|
||||
#include <grub/lib/envblk.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/normal.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/device.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/search.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/partition.h>
|
||||
|
||||
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 1;
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/disk.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -33,6 +33,7 @@
|
|||
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;
|
||||
|
@ -451,6 +452,7 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
|
||||
data->disk = disk;
|
||||
|
||||
g_ventoy_cur_joliet = 0;
|
||||
block = 16;
|
||||
do
|
||||
{
|
||||
|
@ -484,6 +486,7 @@ grub_iso9660_mount (grub_disk_t disk)
|
|||
if (0 == g_ventoy_no_joliet) {
|
||||
copy_voldesc = 1;
|
||||
data->joliet = 1;
|
||||
g_ventoy_cur_joliet = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -735,6 +738,8 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
@ -1116,6 +1121,11 @@ 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;
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
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;
|
||||
|
||||
static const char *align_options[] =
|
||||
|
@ -205,6 +207,12 @@ label_set_property (void *vself, const char *name, const char *value)
|
|||
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") : " ";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,839 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/video.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/bitmap.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
#include <grub/gfxmenu_view.h>
|
||||
#include <grub/gui.h>
|
||||
#include <grub/color.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
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 ("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
|
||||
{
|
||||
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)))
|
||||
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);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
grub_free (name);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* 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_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 + 4096);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -0,0 +1,647 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/normal.h>
|
||||
#include <grub/video.h>
|
||||
#include <grub/gfxterm.h>
|
||||
#include <grub/bitmap.h>
|
||||
#include <grub/bitmap_scale.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/gfxwidgets.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/menu.h>
|
||||
#include <grub/menu_viewer.h>
|
||||
#include <grub/gfxmenu_view.h>
|
||||
#include <grub/gui_string_util.h>
|
||||
#include <grub/icon_manager.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
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->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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
grub_gfxmenu_redraw_menu (grub_gfxmenu_view_t view)
|
||||
{
|
||||
update_menu_components (view);
|
||||
|
||||
grub_gui_iterate_recursively ((grub_gui_component_t) view->canvas,
|
||||
redraw_menu_visit, view);
|
||||
grub_video_swap_buffers ();
|
||||
if (view->double_repaint)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
|
@ -964,3 +964,20 @@ void * grub_efi_allocate_iso_buf(grub_uint64_t size)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,672 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/efi/api.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/cpu/efi/memory.h>
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
#include <grub/pci.h>
|
||||
#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;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* 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
|
|
@ -109,6 +109,52 @@ grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
|
|||
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)
|
||||
{
|
||||
|
@ -123,7 +169,7 @@ grub_set_prefix_and_root (void)
|
|||
if (header->type == OBJ_TYPE_PREFIX)
|
||||
prefix = (char *) header + sizeof (struct grub_module_header);
|
||||
|
||||
grub_register_variable_hook ("root", 0, grub_env_write_root);
|
||||
grub_register_variable_hook ("root", 0, ventoy_env_write_root);
|
||||
|
||||
grub_machine_get_bootlocation (&fwdevice, &fwpath);
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/symbol.h>
|
||||
|
||||
FUNCTION (grub_arch_sync_caches)
|
||||
jr.hb $ra
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/elf.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/cpu/types.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/env.h>
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/cpu/time.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/machine/loongson.h>
|
||||
|
||||
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 ();
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/cpu/time.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/machine/loongson.h>
|
||||
|
||||
void
|
||||
grub_efi_loongson_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
grub_efi_loongson_fini (void)
|
||||
{
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/symbol.h>
|
||||
|
||||
.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
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/cpu/mips.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/term.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/time.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/efi/api.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/acpi.h>
|
||||
#include <grub/loader.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/cache.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/cpu/efi/memory.h>
|
||||
#include <grub/cpu/memory.h>
|
||||
#include <grub/machine/loongson.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/symbol.h>
|
||||
|
||||
.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
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/cache.h>
|
||||
|
||||
#include <grub/mips64/relocator.h>
|
||||
#include <grub/relocator_private.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/symbol.h>
|
||||
|
||||
.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
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/mips64/asm.h>
|
||||
|
||||
.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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,852 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/charset.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/fdt.h>
|
||||
#include <grub/linux.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/cpu/linux.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/efi/fdtload.h>
|
||||
#include <grub/efi/memory.h>
|
||||
#include <grub/efi/pe32.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/lib/cmdline.h>
|
||||
#include <grub/verify.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/env.h>
|
||||
|
||||
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 (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[])
|
||||
{
|
||||
int newclen = 0;
|
||||
char *pos = NULL;
|
||||
char *end = NULL;
|
||||
char buf[256] = {0};
|
||||
|
||||
if (argc != 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
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", end + 1, argv[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_snprintf(buf, sizeof(buf), "newc:%s:%s", end + 1, argv[0]);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue