mirror of https://github.com/ventoy/Ventoy
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
|
@ -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
|
||||
|
@ -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; }
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
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
|
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,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
|
@ -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
|
@ -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