Binary release v4.0
This commit is contained in:
commit
576f87e4d2
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
limine-deploy
|
||||
limine-deploy.exe
|
||||
limine-version
|
||||
limine-version.exe
|
BIN
BOOTAA64.EFI
Executable file
BIN
BOOTAA64.EFI
Executable file
Binary file not shown.
BIN
BOOTIA32.EFI
Executable file
BIN
BOOTIA32.EFI
Executable file
Binary file not shown.
BIN
BOOTX64.EFI
Executable file
BIN
BOOTX64.EFI
Executable file
Binary file not shown.
9
LICENSE.md
Normal file
9
LICENSE.md
Normal file
@ -0,0 +1,9 @@
|
||||
Copyright 2019, 2020, 2021, 2022 mintsuki and contributors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
45
Makefile
Normal file
45
Makefile
Normal file
@ -0,0 +1,45 @@
|
||||
CC ?= cc
|
||||
INSTALL ?= ./install-sh
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
|
||||
CFLAGS ?= -g -O2 -pipe -Wall -Wextra
|
||||
|
||||
.PHONY: all
|
||||
all: limine-deploy limine-version
|
||||
|
||||
.PHONY: install-data
|
||||
install-data: all
|
||||
$(INSTALL) -d '$(DESTDIR)$(PREFIX)/share'
|
||||
$(INSTALL) -d '$(DESTDIR)$(PREFIX)/share/limine'
|
||||
$(INSTALL) -m 644 limine.sys '$(DESTDIR)$(PREFIX)/share/limine/'
|
||||
$(INSTALL) -m 644 limine-cd.bin '$(DESTDIR)$(PREFIX)/share/limine/'
|
||||
$(INSTALL) -m 644 limine-cd-efi.bin '$(DESTDIR)$(PREFIX)/share/limine/'
|
||||
$(INSTALL) -m 644 limine-pxe.bin '$(DESTDIR)$(PREFIX)/share/limine/'
|
||||
$(INSTALL) -m 644 BOOTX64.EFI '$(DESTDIR)$(PREFIX)/share/limine/'
|
||||
$(INSTALL) -m 644 BOOTIA32.EFI '$(DESTDIR)$(PREFIX)/share/limine/'
|
||||
$(INSTALL) -d '$(DESTDIR)$(PREFIX)/include'
|
||||
$(INSTALL) -m 644 limine.h '$(DESTDIR)$(PREFIX)/include/'
|
||||
|
||||
.PHONY: install
|
||||
install: install-data
|
||||
$(INSTALL) -d '$(DESTDIR)$(PREFIX)/bin'
|
||||
$(INSTALL) limine-deploy '$(DESTDIR)$(PREFIX)/bin/'
|
||||
$(INSTALL) limine-version '$(DESTDIR)$(PREFIX)/bin/'
|
||||
|
||||
.PHONY: install-strip
|
||||
install-strip: install-data
|
||||
$(INSTALL) -d '$(DESTDIR)$(PREFIX)/bin'
|
||||
$(INSTALL) -s limine-deploy '$(DESTDIR)$(PREFIX)/bin/'
|
||||
$(INSTALL) -s limine-version '$(DESTDIR)$(PREFIX)/bin/'
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f limine-deploy limine-deploy.exe
|
||||
rm -f limine-version limine-version.exe
|
||||
|
||||
limine-deploy: limine-deploy.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -std=c99 -D__USE_MINGW_ANSI_STDIO limine-deploy.c -o $@
|
||||
|
||||
limine-version: limine-version.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -std=c99 -D__USE_MINGW_ANSI_STDIO limine-version.c -o $@
|
541
install-sh
Executable file
541
install-sh
Executable file
@ -0,0 +1,541 @@
|
||||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2020-11-14.01; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
# Create dirs (including intermediate dirs) using mode 755.
|
||||
# This is like GNU 'install' as of coreutils 8.32 (2020).
|
||||
mkdir_umask=22
|
||||
|
||||
backupsuffix=
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-p pass -p to $cpprog.
|
||||
-s $stripprog installed files.
|
||||
-S SUFFIX attempt to back up existing files, with suffix SUFFIX.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
|
||||
By default, rm is invoked with -f; when overridden with RMPROG,
|
||||
it's up to you to specify -f if you want it.
|
||||
|
||||
If -S is not specified, no backups are attempted.
|
||||
|
||||
Email bug reports to bug-automake@gnu.org.
|
||||
Automake home page: https://www.gnu.org/software/automake/
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-p) cpprog="$cpprog -p";;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-S) backupsuffix="$2"
|
||||
shift;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
# Don't chown directories that already exist.
|
||||
if test $dstdir_status = 0; then
|
||||
chowncmd=""
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dstbase=`basename "$src"`
|
||||
case $dst in
|
||||
*/) dst=$dst$dstbase;;
|
||||
*) dst=$dst/$dstbase;;
|
||||
esac
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
case $dstdir in
|
||||
*/) dstdirslash=$dstdir;;
|
||||
*) dstdirslash=$dstdir/;;
|
||||
esac
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
# The $RANDOM variable is not portable (e.g., dash). Use it
|
||||
# here however when possible just to lower collision chance.
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
|
||||
trap '
|
||||
ret=$?
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
|
||||
exit $ret
|
||||
' 0
|
||||
|
||||
# Because "mkdir -p" follows existing symlinks and we likely work
|
||||
# directly in world-writeable /tmp, make sure that the '$tmpdir'
|
||||
# directory is successfully created first before we actually test
|
||||
# 'mkdir -p'.
|
||||
if (umask $mkdir_umask &&
|
||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
test_tmpdir="$tmpdir/a"
|
||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=${dstdirslash}_inst.$$_
|
||||
rmtmp=${dstdirslash}_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask &&
|
||||
{ test -z "$stripcmd" || {
|
||||
# Create $dsttmp read-write so that cp doesn't create it read-only,
|
||||
# which would cause strip to fail.
|
||||
if test -z "$doit"; then
|
||||
: >"$dsttmp" # No need to fork-exec 'touch'.
|
||||
else
|
||||
$doit touch "$dsttmp"
|
||||
fi
|
||||
}
|
||||
} &&
|
||||
$doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# If $backupsuffix is set, and the file being installed
|
||||
# already exists, attempt a backup. Don't worry if it fails,
|
||||
# e.g., if mv doesn't support -f.
|
||||
if test -n "$backupsuffix" && test -f "$dst"; then
|
||||
$doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
|
||||
fi
|
||||
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
BIN
limine-cd-efi.bin
Normal file
BIN
limine-cd-efi.bin
Normal file
Binary file not shown.
BIN
limine-cd.bin
Normal file
BIN
limine-cd.bin
Normal file
Binary file not shown.
929
limine-deploy.c
Normal file
929
limine-deploy.c
Normal file
@ -0,0 +1,929 @@
|
||||
#undef IS_WINDOWS
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
|
||||
#define IS_WINDOWS 1
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "limine-hdd.h"
|
||||
|
||||
static int set_pos(FILE *stream, uint64_t pos) {
|
||||
if (sizeof(long) >= 8) {
|
||||
return fseek(stream, (long)pos, SEEK_SET);
|
||||
}
|
||||
|
||||
long jump_size = (LONG_MAX / 2) + 1;
|
||||
long last_jump = pos % jump_size;
|
||||
uint64_t jumps = pos / jump_size;
|
||||
|
||||
rewind(stream);
|
||||
|
||||
for (uint64_t i = 0; i < jumps; i++) {
|
||||
if (fseek(stream, jump_size, SEEK_CUR) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (fseek(stream, last_jump, SEEK_CUR) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DIV_ROUNDUP(a, b) (((a) + ((b) - 1)) / (b))
|
||||
|
||||
struct gpt_table_header {
|
||||
// the head
|
||||
char signature[8];
|
||||
uint32_t revision;
|
||||
uint32_t header_size;
|
||||
uint32_t crc32;
|
||||
uint32_t _reserved0;
|
||||
|
||||
// the partitioning info
|
||||
uint64_t my_lba;
|
||||
uint64_t alternate_lba;
|
||||
uint64_t first_usable_lba;
|
||||
uint64_t last_usable_lba;
|
||||
|
||||
// the guid
|
||||
uint64_t disk_guid[2];
|
||||
|
||||
// entries related
|
||||
uint64_t partition_entry_lba;
|
||||
uint32_t number_of_partition_entries;
|
||||
uint32_t size_of_partition_entry;
|
||||
uint32_t partition_entry_array_crc32;
|
||||
};
|
||||
|
||||
struct gpt_entry {
|
||||
uint64_t partition_type_guid[2];
|
||||
|
||||
uint64_t unique_partition_guid[2];
|
||||
|
||||
uint64_t starting_lba;
|
||||
uint64_t ending_lba;
|
||||
|
||||
uint64_t attributes;
|
||||
|
||||
uint16_t partition_name[36];
|
||||
};
|
||||
|
||||
// This table from https://web.mit.edu/freebsd/head/sys/libkern/crc32.c
|
||||
static const uint32_t crc32_table[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
static uint32_t crc32(void *_stream, size_t len) {
|
||||
uint8_t *stream = _stream;
|
||||
uint32_t ret = 0xffffffff;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
ret = (ret >> 8) ^ crc32_table[(ret ^ stream[i]) & 0xff];
|
||||
}
|
||||
|
||||
ret ^= 0xffffffff;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool bigendian = false;
|
||||
|
||||
static uint16_t endswap16(uint16_t value) {
|
||||
uint16_t ret = 0;
|
||||
ret |= (value >> 8) & 0x00ff;
|
||||
ret |= (value << 8) & 0xff00;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t endswap32(uint32_t value) {
|
||||
uint32_t ret = 0;
|
||||
ret |= (value >> 24) & 0x000000ff;
|
||||
ret |= (value >> 8) & 0x0000ff00;
|
||||
ret |= (value << 8) & 0x00ff0000;
|
||||
ret |= (value << 24) & 0xff000000;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint64_t endswap64(uint64_t value) {
|
||||
uint64_t ret = 0;
|
||||
ret |= (value >> 56) & 0x00000000000000ff;
|
||||
ret |= (value >> 40) & 0x000000000000ff00;
|
||||
ret |= (value >> 24) & 0x0000000000ff0000;
|
||||
ret |= (value >> 8) & 0x00000000ff000000;
|
||||
ret |= (value << 8) & 0x000000ff00000000;
|
||||
ret |= (value << 24) & 0x0000ff0000000000;
|
||||
ret |= (value << 40) & 0x00ff000000000000;
|
||||
ret |= (value << 56) & 0xff00000000000000;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define ENDSWAP(VALUE) (bigendian ? ( \
|
||||
sizeof(VALUE) == 1 ? (VALUE) : \
|
||||
sizeof(VALUE) == 2 ? endswap16(VALUE) : \
|
||||
sizeof(VALUE) == 4 ? endswap32(VALUE) : \
|
||||
sizeof(VALUE) == 8 ? endswap64(VALUE) : (abort(), 1) \
|
||||
) : (VALUE))
|
||||
|
||||
static enum {
|
||||
CACHE_CLEAN,
|
||||
CACHE_DIRTY
|
||||
} cache_state;
|
||||
static uint64_t cached_block;
|
||||
static uint8_t *cache = NULL;
|
||||
static FILE *device = NULL;
|
||||
static size_t block_size;
|
||||
|
||||
static bool device_init(void) {
|
||||
size_t guesses[] = { 512, 2048, 4096 };
|
||||
|
||||
for (size_t i = 0; i < sizeof(guesses) / sizeof(size_t); i++) {
|
||||
void *tmp = realloc(cache, guesses[i]);
|
||||
if (tmp == NULL) {
|
||||
perror("ERROR");
|
||||
return false;
|
||||
}
|
||||
cache = tmp;
|
||||
|
||||
rewind(device);
|
||||
|
||||
size_t ret = fread(cache, guesses[i], 1, device);
|
||||
if (ret != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
block_size = guesses[i];
|
||||
|
||||
fprintf(stderr, "Physical block size of %zu bytes.\n", block_size);
|
||||
|
||||
cache_state = CACHE_CLEAN;
|
||||
cached_block = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
fprintf(stderr, "ERROR: Couldn't determine block size of device.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool device_flush_cache(void) {
|
||||
if (cache_state == CACHE_CLEAN)
|
||||
return true;
|
||||
|
||||
if (set_pos(device, cached_block * block_size) != 0) {
|
||||
perror("ERROR");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t ret = fwrite(cache, block_size, 1, device);
|
||||
if (ret != 1) {
|
||||
perror("ERROR");
|
||||
return false;
|
||||
}
|
||||
|
||||
cache_state = CACHE_CLEAN;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool device_cache_block(uint64_t block) {
|
||||
if (cached_block == block)
|
||||
return true;
|
||||
|
||||
if (cache_state == CACHE_DIRTY) {
|
||||
if (!device_flush_cache())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (set_pos(device, block * block_size) != 0) {
|
||||
perror("ERROR");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t ret = fread(cache, block_size, 1, device);
|
||||
if (ret != 1) {
|
||||
perror("ERROR");
|
||||
return false;
|
||||
}
|
||||
|
||||
cached_block = block;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct undeploy_data {
|
||||
void *data;
|
||||
uint64_t loc;
|
||||
uint64_t count;
|
||||
};
|
||||
|
||||
#define UNDEPLOY_DATA_MAX 256
|
||||
|
||||
static bool undeploying = false;
|
||||
static struct undeploy_data undeploy_data[UNDEPLOY_DATA_MAX];
|
||||
static struct undeploy_data undeploy_data_rev[UNDEPLOY_DATA_MAX];
|
||||
static uint64_t undeploy_data_i = 0;
|
||||
static const char *undeploy_file = NULL;
|
||||
|
||||
static void reverse_undeploy_data(void) {
|
||||
for (size_t i = 0, j = undeploy_data_i - 1; i < undeploy_data_i; i++, j--) {
|
||||
undeploy_data_rev[j] = undeploy_data[i];
|
||||
}
|
||||
|
||||
memcpy(undeploy_data, undeploy_data_rev, undeploy_data_i * sizeof(struct undeploy_data));
|
||||
}
|
||||
|
||||
static void free_undeploy_data(void) {
|
||||
for (size_t i = 0; i < undeploy_data_i; i++) {
|
||||
free(undeploy_data[i].data);
|
||||
}
|
||||
}
|
||||
|
||||
static bool store_undeploy_data(const char *filename) {
|
||||
fprintf(stderr, "Storing undeploy data to file: `%s`...\n", filename);
|
||||
|
||||
FILE *udfile = fopen(filename, "wb");
|
||||
if (udfile == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fwrite(&undeploy_data_i, sizeof(uint64_t), 1, udfile) != 1) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < undeploy_data_i; i++) {
|
||||
if (fwrite(&undeploy_data[i].loc, sizeof(uint64_t), 1, udfile) != 1) {
|
||||
goto error;
|
||||
}
|
||||
if (fwrite(&undeploy_data[i].count, sizeof(uint64_t), 1, udfile) != 1) {
|
||||
goto error;
|
||||
}
|
||||
if (fwrite(undeploy_data[i].data, undeploy_data[i].count, 1, udfile) != 1) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(udfile);
|
||||
return true;
|
||||
|
||||
error:
|
||||
perror("ERROR");
|
||||
if (udfile != NULL) {
|
||||
fclose(udfile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool load_undeploy_data(const char *filename) {
|
||||
fprintf(stderr, "Loading undeploy data from file: `%s`...\n", filename);
|
||||
|
||||
FILE *udfile = fopen(filename, "rb");
|
||||
if (udfile == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (fread(&undeploy_data_i, sizeof(uint64_t), 1, udfile) != 1) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < undeploy_data_i; i++) {
|
||||
if (fread(&undeploy_data[i].loc, sizeof(uint64_t), 1, udfile) != 1) {
|
||||
goto error;
|
||||
}
|
||||
if (fread(&undeploy_data[i].count, sizeof(uint64_t), 1, udfile) != 1) {
|
||||
goto error;
|
||||
}
|
||||
undeploy_data[i].data = malloc(undeploy_data[i].count);
|
||||
if (undeploy_data[i].data == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (fread(undeploy_data[i].data, undeploy_data[i].count, 1, udfile) != 1) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(udfile);
|
||||
return true;
|
||||
|
||||
error:
|
||||
perror("ERROR");
|
||||
if (udfile != NULL) {
|
||||
fclose(udfile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool _device_read(void *_buffer, uint64_t loc, size_t count) {
|
||||
uint8_t *buffer = _buffer;
|
||||
uint64_t progress = 0;
|
||||
while (progress < count) {
|
||||
uint64_t block = (loc + progress) / block_size;
|
||||
|
||||
if (!device_cache_block(block)) {
|
||||
fprintf(stderr, "ERROR: Read error.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t chunk = count - progress;
|
||||
uint64_t offset = (loc + progress) % block_size;
|
||||
if (chunk > block_size - offset)
|
||||
chunk = block_size - offset;
|
||||
|
||||
memcpy(buffer + progress, &cache[offset], chunk);
|
||||
progress += chunk;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool _device_write(const void *_buffer, uint64_t loc, size_t count) {
|
||||
if (undeploying) {
|
||||
goto skip_save;
|
||||
}
|
||||
|
||||
if (undeploy_data_i >= UNDEPLOY_DATA_MAX) {
|
||||
fprintf(stderr, "Internal error: Too many undeploy data entries!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct undeploy_data *ud = &undeploy_data[undeploy_data_i];
|
||||
|
||||
ud->data = malloc(count);
|
||||
if (ud->data == NULL) {
|
||||
fprintf(stderr, "ERROR: Memory allocation failure.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_device_read(ud->data, loc, count)) {
|
||||
fprintf(stderr, "ERROR: Device read failure.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ud->loc = loc;
|
||||
ud->count = count;
|
||||
|
||||
skip_save:;
|
||||
const uint8_t *buffer = _buffer;
|
||||
uint64_t progress = 0;
|
||||
while (progress < count) {
|
||||
uint64_t block = (loc + progress) / block_size;
|
||||
|
||||
if (!device_cache_block(block)) {
|
||||
fprintf(stderr, "ERROR: Write error.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t chunk = count - progress;
|
||||
uint64_t offset = (loc + progress) % block_size;
|
||||
if (chunk > block_size - offset)
|
||||
chunk = block_size - offset;
|
||||
|
||||
memcpy(&cache[offset], buffer + progress, chunk);
|
||||
cache_state = CACHE_DIRTY;
|
||||
progress += chunk;
|
||||
}
|
||||
|
||||
if (!undeploying) {
|
||||
undeploy_data_i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void undeploy(void) {
|
||||
undeploying = true;
|
||||
|
||||
cache_state = CACHE_CLEAN;
|
||||
cached_block = (uint64_t)-1;
|
||||
|
||||
for (size_t i = 0; i < undeploy_data_i; i++) {
|
||||
struct undeploy_data *ud = &undeploy_data[i];
|
||||
bool retry = false;
|
||||
while (!_device_write(ud->data, ud->loc, ud->count)) {
|
||||
if (retry) {
|
||||
fprintf(stderr, "ERROR: Undeploy data index %zu failed to write. Undeploy may be incomplete!\n", i);
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "Warning: Undeploy data index %zu failed to write, retrying...\n", i);
|
||||
if (!device_flush_cache()) {
|
||||
fprintf(stderr, "ERROR: Device cache flush failure. Undeploy may be incomplete!\n");
|
||||
}
|
||||
cache_state = CACHE_CLEAN;
|
||||
cached_block = (uint64_t)-1;
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device_flush_cache()) {
|
||||
fprintf(stderr, "ERROR: Device cache flush failure. Undeploy may be incomplete!\n");
|
||||
}
|
||||
|
||||
fprintf(stderr, "Undeploy data restored successfully. Limine undeployed!\n");
|
||||
}
|
||||
|
||||
#define device_read(BUFFER, LOC, COUNT) \
|
||||
do { \
|
||||
if (!_device_read(BUFFER, LOC, COUNT)) \
|
||||
goto cleanup; \
|
||||
} while (0)
|
||||
|
||||
#define device_write(BUFFER, LOC, COUNT) \
|
||||
do { \
|
||||
if (!_device_write(BUFFER, LOC, COUNT)) \
|
||||
goto cleanup; \
|
||||
} while (0)
|
||||
|
||||
static void usage(const char *name) {
|
||||
printf("Usage: %s <device> [GPT partition index]\n", name);
|
||||
printf("\n");
|
||||
printf(" --force-mbr Force MBR detection to work even if the\n");
|
||||
printf(" safety checks fail (DANGEROUS!)\n");
|
||||
printf("\n");
|
||||
printf(" --undeploy Reverse the entire deployment procedure\n");
|
||||
printf("\n");
|
||||
printf(" --undeploy-data-file=<filename>\n");
|
||||
printf(" Set the input (for --undeploy) or output file\n");
|
||||
printf(" name of the file which contains undeploy data\n");
|
||||
printf("\n");
|
||||
printf(" --help | -h Display this help message\n");
|
||||
printf("\n");
|
||||
#ifdef IS_WINDOWS
|
||||
system("pause");
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int ok = EXIT_FAILURE;
|
||||
int force_mbr = 0;
|
||||
bool undeploy_mode = false;
|
||||
const uint8_t *bootloader_img = binary_limine_hdd_bin_data;
|
||||
size_t bootloader_file_size = sizeof(binary_limine_hdd_bin_data);
|
||||
uint8_t orig_mbr[70], timestamp[6];
|
||||
const char *part_ndx = NULL;
|
||||
|
||||
uint32_t endcheck = 0x12345678;
|
||||
uint8_t endbyte = *((uint8_t *)&endcheck);
|
||||
bigendian = endbyte == 0x12;
|
||||
|
||||
if (argc < 2) {
|
||||
usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
|
||||
usage(argv[0]);
|
||||
return EXIT_SUCCESS;
|
||||
} else if (strcmp(argv[i], "--force-mbr") == 0) {
|
||||
if (force_mbr) {
|
||||
fprintf(stderr, "Warning: --force-mbr already set.\n");
|
||||
}
|
||||
force_mbr = 1;
|
||||
} else if (strcmp(argv[i], "--undeploy") == 0) {
|
||||
if (undeploy_mode) {
|
||||
fprintf(stderr, "Warning: --undeploy already set.\n");
|
||||
}
|
||||
undeploy_mode = true;
|
||||
} else if (memcmp(argv[i], "--undeploy-data-file=", 21) == 0) {
|
||||
if (undeploy_file != NULL) {
|
||||
fprintf(stderr, "Warning: --undeploy-data-file already set. Overriding...\n");
|
||||
}
|
||||
undeploy_file = argv[i] + 21;
|
||||
if (strlen(undeploy_file) == 0) {
|
||||
fprintf(stderr, "ERROR: Undeploy data file has a zero-length name!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} else {
|
||||
if (device != NULL) { // [GPT partition index]
|
||||
part_ndx = argv[i]; // TODO: Make this non-positional?
|
||||
} else if ((device = fopen(argv[i], "r+b")) == NULL) { // <device>
|
||||
perror("ERROR");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (device == NULL) {
|
||||
fprintf(stderr, "ERROR: No device specified\n");
|
||||
usage(argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!device_init()) {
|
||||
goto undeploy_mode_cleanup;
|
||||
}
|
||||
|
||||
if (undeploy_mode) {
|
||||
if (undeploy_file == NULL) {
|
||||
fprintf(stderr, "ERROR: Undeploy mode set but no --undeploy-data-file=... passed.\n");
|
||||
goto undeploy_mode_cleanup;
|
||||
}
|
||||
|
||||
if (!load_undeploy_data(undeploy_file)) {
|
||||
goto undeploy_mode_cleanup;
|
||||
}
|
||||
|
||||
undeploy();
|
||||
|
||||
ok = EXIT_SUCCESS;
|
||||
goto undeploy_mode_cleanup;
|
||||
}
|
||||
|
||||
// Probe for GPT and logical block size
|
||||
int gpt = 0;
|
||||
struct gpt_table_header gpt_header;
|
||||
uint64_t lb_guesses[] = { 512, 4096 };
|
||||
uint64_t lb_size = 0;
|
||||
for (size_t i = 0; i < sizeof(lb_guesses) / sizeof(uint64_t); i++) {
|
||||
device_read(&gpt_header, lb_guesses[i], sizeof(struct gpt_table_header));
|
||||
if (!strncmp(gpt_header.signature, "EFI PART", 8)) {
|
||||
lb_size = lb_guesses[i];
|
||||
if (!force_mbr) {
|
||||
gpt = 1;
|
||||
fprintf(stderr, "Deploying to GPT. Logical block size of %" PRIu64 " bytes.\n",
|
||||
lb_guesses[i]);
|
||||
} else {
|
||||
fprintf(stderr, "Device has a valid GPT, refusing to force MBR.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct gpt_table_header secondary_gpt_header;
|
||||
if (gpt) {
|
||||
fprintf(stderr, "Secondary header at LBA 0x%" PRIx64 ".\n",
|
||||
ENDSWAP(gpt_header.alternate_lba));
|
||||
device_read(&secondary_gpt_header, lb_size * ENDSWAP(gpt_header.alternate_lba),
|
||||
sizeof(struct gpt_table_header));
|
||||
if (!strncmp(secondary_gpt_header.signature, "EFI PART", 8)) {
|
||||
fprintf(stderr, "Secondary header valid.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Secondary header not valid, aborting.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
int mbr = 0;
|
||||
if (gpt == 0) {
|
||||
// Do all sanity checks on MBR
|
||||
mbr = 1;
|
||||
|
||||
uint8_t hint8 = 0;
|
||||
uint16_t hint16 = 0;
|
||||
|
||||
bool any_active = false;
|
||||
|
||||
device_read(&hint8, 446, sizeof(uint8_t));
|
||||
if (hint8 != 0x00 && hint8 != 0x80) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
hint8 = hint8 & 0x80 ? 0x80 : 0x00;
|
||||
device_write(&hint8, 446, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
any_active = any_active ? any_active : (hint8 & 0x80) != 0;
|
||||
device_read(&hint8, 462, sizeof(uint8_t));
|
||||
if (hint8 != 0x00 && hint8 != 0x80) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
hint8 = hint8 & 0x80 ? 0x80 : 0x00;
|
||||
device_write(&hint8, 462, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
any_active = any_active ? any_active : (hint8 & 0x80) != 0;
|
||||
device_read(&hint8, 478, sizeof(uint8_t));
|
||||
if (hint8 != 0x00 && hint8 != 0x80) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
hint8 = hint8 & 0x80 ? 0x80 : 0x00;
|
||||
device_write(&hint8, 478, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
any_active = any_active ? any_active : (hint8 & 0x80) != 0;
|
||||
device_read(&hint8, 494, sizeof(uint8_t));
|
||||
if (hint8 != 0x00 && hint8 != 0x80) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
hint8 = hint8 & 0x80 ? 0x80 : 0x00;
|
||||
device_write(&hint8, 494, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
any_active = any_active ? any_active : (hint8 & 0x80) != 0;
|
||||
|
||||
char hintc[64];
|
||||
device_read(hintc, 4, 8);
|
||||
if (memcmp(hintc, "_ECH_FS_", 8) == 0) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
memset(hintc, 0, 8);
|
||||
device_write(hintc, 4, 8);
|
||||
}
|
||||
}
|
||||
device_read(hintc, 3, 4);
|
||||
if (memcmp(hintc, "NTFS", 4) == 0) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
memset(hintc, 0, 4);
|
||||
device_write(hintc, 3, 4);
|
||||
}
|
||||
}
|
||||
device_read(hintc, 54, 3);
|
||||
if (memcmp(hintc, "FAT", 3) == 0) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
memset(hintc, 0, 5);
|
||||
device_write(hintc, 54, 5);
|
||||
}
|
||||
}
|
||||
device_read(hintc, 82, 3);
|
||||
if (memcmp(hintc, "FAT", 3) == 0) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
memset(hintc, 0, 5);
|
||||
device_write(hintc, 82, 5);
|
||||
}
|
||||
}
|
||||
device_read(hintc, 3, 5);
|
||||
if (memcmp(hintc, "FAT32", 5) == 0) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
memset(hintc, 0, 5);
|
||||
device_write(hintc, 3, 5);
|
||||
}
|
||||
}
|
||||
device_read(&hint16, 1080, sizeof(uint16_t));
|
||||
hint16 = ENDSWAP(hint16);
|
||||
if (hint16 == 0xef53) {
|
||||
if (!force_mbr) {
|
||||
mbr = 0;
|
||||
} else {
|
||||
hint16 = 0;
|
||||
hint16 = ENDSWAP(hint16);
|
||||
device_write(&hint16, 1080, sizeof(uint16_t));
|
||||
}
|
||||
}
|
||||
|
||||
if (mbr && !any_active) {
|
||||
fprintf(stderr, "No active partition found, some systems may not boot.\n");
|
||||
fprintf(stderr, "Setting partition 1 as active to work around the issue...\n");
|
||||
hint8 = 0x80;
|
||||
device_write(&hint8, 446, sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
|
||||
if (gpt == 0 && mbr == 0) {
|
||||
fprintf(stderr, "ERROR: Could not determine if the device has a valid partition table.\n");
|
||||
fprintf(stderr, " Please ensure the device has a valid MBR or GPT.\n");
|
||||
fprintf(stderr, " Alternatively, pass `--force-mbr` to override these checks.\n");
|
||||
fprintf(stderr, " **ONLY DO THIS AT YOUR OWN RISK, DATA LOSS MAY OCCUR!**\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
size_t stage2_size = bootloader_file_size - 512;
|
||||
|
||||
size_t stage2_sects = DIV_ROUNDUP(stage2_size, 512);
|
||||
|
||||
uint16_t stage2_size_a = (stage2_sects / 2) * 512 + (stage2_sects % 2 ? 512 : 0);
|
||||
uint16_t stage2_size_b = (stage2_sects / 2) * 512;
|
||||
|
||||
// Default split of stage2 for MBR (consecutive in post MBR gap)
|
||||
uint64_t stage2_loc_a = 512;
|
||||
uint64_t stage2_loc_b = stage2_loc_a + stage2_size_a;
|
||||
|
||||
if (gpt) {
|
||||
if (part_ndx != NULL) {
|
||||
uint32_t partition_num;
|
||||
sscanf(part_ndx, "%" SCNu32, &partition_num);
|
||||
partition_num--;
|
||||
if (partition_num > ENDSWAP(gpt_header.number_of_partition_entries)) {
|
||||
fprintf(stderr, "ERROR: Partition number is too large.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
struct gpt_entry gpt_entry;
|
||||
device_read(&gpt_entry,
|
||||
(ENDSWAP(gpt_header.partition_entry_lba) * lb_size)
|
||||
+ (partition_num * ENDSWAP(gpt_header.size_of_partition_entry)),
|
||||
sizeof(struct gpt_entry));
|
||||
|
||||
if (gpt_entry.unique_partition_guid[0] == 0 &&
|
||||
gpt_entry.unique_partition_guid[1] == 0) {
|
||||
fprintf(stderr, "ERROR: No such partition.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fprintf(stderr, "GPT partition specified. Deploying there instead of embedding.\n");
|
||||
|
||||
stage2_loc_a = ENDSWAP(gpt_entry.starting_lba) * lb_size;
|
||||
stage2_loc_b = stage2_loc_a + stage2_size_a;
|
||||
if (stage2_loc_b & (lb_size - 1))
|
||||
stage2_loc_b = (stage2_loc_b + lb_size) & ~(lb_size - 1);
|
||||
} else {
|
||||
fprintf(stderr, "GPT partition NOT specified. Attempting GPT embedding.\n");
|
||||
|
||||
int64_t max_partition_entry_used = -1;
|
||||
for (int64_t i = 0; i < (int64_t)ENDSWAP(gpt_header.number_of_partition_entries); i++) {
|
||||
struct gpt_entry gpt_entry;
|
||||
device_read(&gpt_entry,
|
||||
(ENDSWAP(gpt_header.partition_entry_lba) * lb_size)
|
||||
+ (i * ENDSWAP(gpt_header.size_of_partition_entry)),
|
||||
sizeof(struct gpt_entry));
|
||||
|
||||
if (gpt_entry.unique_partition_guid[0] != 0 ||
|
||||
gpt_entry.unique_partition_guid[1] != 0) {
|
||||
if (i > max_partition_entry_used)
|
||||
max_partition_entry_used = i;
|
||||
}
|
||||
}
|
||||
|
||||
stage2_loc_a = (ENDSWAP(gpt_header.partition_entry_lba) + 32) * lb_size;
|
||||
stage2_loc_a -= stage2_size_a;
|
||||
stage2_loc_a &= ~(lb_size - 1);
|
||||
stage2_loc_b = (ENDSWAP(secondary_gpt_header.partition_entry_lba) + 32) * lb_size;
|
||||
stage2_loc_b -= stage2_size_b;
|
||||
stage2_loc_b &= ~(lb_size - 1);
|
||||
|
||||
size_t partition_entries_per_lb =
|
||||
lb_size / ENDSWAP(gpt_header.size_of_partition_entry);
|
||||
size_t new_partition_array_lba_size =
|
||||
stage2_loc_a / lb_size - ENDSWAP(gpt_header.partition_entry_lba);
|
||||
size_t new_partition_entry_count =
|
||||
new_partition_array_lba_size * partition_entries_per_lb;
|
||||
|
||||
if ((int64_t)new_partition_entry_count <= max_partition_entry_used) {
|
||||
fprintf(stderr, "ERROR: Cannot embed because there are too many used partition entries.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fprintf(stderr, "New maximum count of partition entries: %zu.\n", new_partition_entry_count);
|
||||
|
||||
// Zero out unused partitions
|
||||
void *empty = calloc(1, ENDSWAP(gpt_header.size_of_partition_entry));
|
||||
for (size_t i = max_partition_entry_used + 1; i < new_partition_entry_count; i++) {
|
||||
device_write(empty,
|
||||
ENDSWAP(gpt_header.partition_entry_lba) * lb_size + i * ENDSWAP(gpt_header.size_of_partition_entry),
|
||||
ENDSWAP(gpt_header.size_of_partition_entry));
|
||||
}
|
||||
for (size_t i = max_partition_entry_used + 1; i < new_partition_entry_count; i++) {
|
||||
device_write(empty,
|
||||
ENDSWAP(secondary_gpt_header.partition_entry_lba) * lb_size + i * ENDSWAP(secondary_gpt_header.size_of_partition_entry),
|
||||
ENDSWAP(secondary_gpt_header.size_of_partition_entry));
|
||||
}
|
||||
free(empty);
|
||||
|
||||
uint8_t *partition_array =
|
||||
malloc(new_partition_entry_count * ENDSWAP(gpt_header.size_of_partition_entry));
|
||||
if (partition_array == NULL) {
|
||||
perror("ERROR");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
device_read(partition_array,
|
||||
ENDSWAP(gpt_header.partition_entry_lba) * lb_size,
|
||||
new_partition_entry_count * ENDSWAP(gpt_header.size_of_partition_entry));
|
||||
|
||||
uint32_t crc32_partition_array =
|
||||
crc32(partition_array,
|
||||
new_partition_entry_count * ENDSWAP(gpt_header.size_of_partition_entry));
|
||||
|
||||
free(partition_array);
|
||||
|
||||
gpt_header.partition_entry_array_crc32 = ENDSWAP(crc32_partition_array);
|
||||
gpt_header.number_of_partition_entries = ENDSWAP(new_partition_entry_count);
|
||||
gpt_header.crc32 = 0;
|
||||
gpt_header.crc32 = crc32(&gpt_header, 92);
|
||||
gpt_header.crc32 = ENDSWAP(gpt_header.crc32);
|
||||
device_write(&gpt_header,
|
||||
lb_size,
|
||||
sizeof(struct gpt_table_header));
|
||||
|
||||
secondary_gpt_header.partition_entry_array_crc32 = ENDSWAP(crc32_partition_array);
|
||||
secondary_gpt_header.number_of_partition_entries =
|
||||
ENDSWAP(new_partition_entry_count);
|
||||
secondary_gpt_header.crc32 = 0;
|
||||
secondary_gpt_header.crc32 = crc32(&secondary_gpt_header, 92);
|
||||
secondary_gpt_header.crc32 = ENDSWAP(secondary_gpt_header.crc32);
|
||||
device_write(&secondary_gpt_header,
|
||||
lb_size * ENDSWAP(gpt_header.alternate_lba),
|
||||
sizeof(struct gpt_table_header));
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Deploying to MBR.\n");
|
||||
}
|
||||
|
||||
fprintf(stderr, "Stage 2 to be located at 0x%" PRIx64 " and 0x%" PRIx64 ".\n",
|
||||
stage2_loc_a, stage2_loc_b);
|
||||
|
||||
// Save original timestamp
|
||||
device_read(timestamp, 218, 6);
|
||||
|
||||
// Save the original partition table of the device
|
||||
device_read(orig_mbr, 440, 70);
|
||||
|
||||
// Write the bootsector from the bootloader to the device
|
||||
device_write(&bootloader_img[0], 0, 512);
|
||||
|
||||
// Write the rest of stage 2 to the device
|
||||
device_write(&bootloader_img[512], stage2_loc_a, stage2_size_a);
|
||||
device_write(&bootloader_img[512 + stage2_size_a],
|
||||
stage2_loc_b, stage2_size - stage2_size_a);
|
||||
|
||||
// Hardcode in the bootsector the location of stage 2 halves
|
||||
stage2_size_a = ENDSWAP(stage2_size_a);
|
||||
device_write(&stage2_size_a, 0x1a4 + 0, sizeof(uint16_t));
|
||||
stage2_size_b = ENDSWAP(stage2_size_b);
|
||||
device_write(&stage2_size_b, 0x1a4 + 2, sizeof(uint16_t));
|
||||
stage2_loc_a = ENDSWAP(stage2_loc_a);
|
||||
device_write(&stage2_loc_a, 0x1a4 + 4, sizeof(uint64_t));
|
||||
stage2_loc_b = ENDSWAP(stage2_loc_b);
|
||||
device_write(&stage2_loc_b, 0x1a4 + 12, sizeof(uint64_t));
|
||||
|
||||
// Write back timestamp
|
||||
device_write(timestamp, 218, 6);
|
||||
|
||||
// Write back the saved partition table to the device
|
||||
device_write(orig_mbr, 440, 70);
|
||||
|
||||
if (!device_flush_cache())
|
||||
goto cleanup;
|
||||
|
||||
fprintf(stderr, "Reminder: Remember to copy the limine.sys file in either\n"
|
||||
" the root or /boot directories of one of the partitions\n"
|
||||
" on the device, or boot will fail!\n");
|
||||
|
||||
fprintf(stderr, "Limine deployed successfully!\n");
|
||||
|
||||
ok = EXIT_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
reverse_undeploy_data();
|
||||
if (ok != EXIT_SUCCESS) {
|
||||
// If we failed, attempt to reverse deploy process
|
||||
undeploy();
|
||||
} else if (undeploy_file != NULL) {
|
||||
store_undeploy_data(undeploy_file);
|
||||
}
|
||||
undeploy_mode_cleanup:
|
||||
free_undeploy_data();
|
||||
if (cache)
|
||||
free(cache);
|
||||
if (device != NULL)
|
||||
fclose(device);
|
||||
|
||||
return ok;
|
||||
}
|
BIN
limine-deploy.exe
Executable file
BIN
limine-deploy.exe
Executable file
Binary file not shown.
1379
limine-hdd.h
Normal file
1379
limine-hdd.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
limine-pxe.bin
Normal file
BIN
limine-pxe.bin
Normal file
Binary file not shown.
7
limine-version.c
Normal file
7
limine-version.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define LIMINE_VERSION "4.0"
|
||||
|
||||
int main(void) {
|
||||
puts(LIMINE_VERSION);
|
||||
}
|
420
limine.h
Normal file
420
limine.h
Normal file
@ -0,0 +1,420 @@
|
||||
#ifndef _LIMINE_H
|
||||
#define _LIMINE_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Misc */
|
||||
|
||||
#ifdef LIMINE_NO_POINTERS
|
||||
# define LIMINE_PTR(TYPE) uint64_t
|
||||
#else
|
||||
# define LIMINE_PTR(TYPE) TYPE
|
||||
#endif
|
||||
|
||||
#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b
|
||||
|
||||
struct limine_uuid {
|
||||
uint32_t a;
|
||||
uint16_t b;
|
||||
uint16_t c;
|
||||
uint8_t d[8];
|
||||
};
|
||||
|
||||
#define LIMINE_MEDIA_TYPE_GENERIC 0
|
||||
#define LIMINE_MEDIA_TYPE_OPTICAL 1
|
||||
#define LIMINE_MEDIA_TYPE_TFTP 2
|
||||
|
||||
struct limine_file {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) address;
|
||||
uint64_t size;
|
||||
LIMINE_PTR(char *) path;
|
||||
LIMINE_PTR(char *) cmdline;
|
||||
uint32_t media_type;
|
||||
uint32_t unused;
|
||||
uint32_t tftp_ip;
|
||||
uint32_t tftp_port;
|
||||
uint32_t partition_index;
|
||||
uint32_t mbr_disk_id;
|
||||
struct limine_uuid gpt_disk_uuid;
|
||||
struct limine_uuid gpt_part_uuid;
|
||||
struct limine_uuid part_uuid;
|
||||
};
|
||||
|
||||
/* Boot info */
|
||||
|
||||
#define LIMINE_BOOTLOADER_INFO_REQUEST { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 }
|
||||
|
||||
struct limine_bootloader_info_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(char *) name;
|
||||
LIMINE_PTR(char *) version;
|
||||
};
|
||||
|
||||
struct limine_bootloader_info_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_bootloader_info_response *) response;
|
||||
};
|
||||
|
||||
/* Stack size */
|
||||
|
||||
#define LIMINE_STACK_SIZE_REQUEST { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d }
|
||||
|
||||
struct limine_stack_size_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct limine_stack_size_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_stack_size_response *) response;
|
||||
uint64_t stack_size;
|
||||
};
|
||||
|
||||
/* HHDM */
|
||||
|
||||
#define LIMINE_HHDM_REQUEST { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b }
|
||||
|
||||
struct limine_hhdm_response {
|
||||
uint64_t revision;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct limine_hhdm_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_hhdm_response *) response;
|
||||
};
|
||||
|
||||
/* Framebuffer */
|
||||
|
||||
#define LIMINE_FRAMEBUFFER_REQUEST { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b }
|
||||
|
||||
#define LIMINE_FRAMEBUFFER_RGB 1
|
||||
|
||||
struct limine_framebuffer {
|
||||
LIMINE_PTR(void *) address;
|
||||
uint64_t width;
|
||||
uint64_t height;
|
||||
uint64_t pitch;
|
||||
uint16_t bpp;
|
||||
uint8_t memory_model;
|
||||
uint8_t red_mask_size;
|
||||
uint8_t red_mask_shift;
|
||||
uint8_t green_mask_size;
|
||||
uint8_t green_mask_shift;
|
||||
uint8_t blue_mask_size;
|
||||
uint8_t blue_mask_shift;
|
||||
uint8_t unused[7];
|
||||
uint64_t edid_size;
|
||||
LIMINE_PTR(void *) edid;
|
||||
};
|
||||
|
||||
struct limine_framebuffer_response {
|
||||
uint64_t revision;
|
||||
uint64_t framebuffer_count;
|
||||
LIMINE_PTR(struct limine_framebuffer **) framebuffers;
|
||||
};
|
||||
|
||||
struct limine_framebuffer_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_framebuffer_response *) response;
|
||||
};
|
||||
|
||||
/* Terminal */
|
||||
|
||||
#define LIMINE_TERMINAL_REQUEST { LIMINE_COMMON_MAGIC, 0xc8ac59310c2b0844, 0xa68d0c7265d38878 }
|
||||
|
||||
#define LIMINE_TERMINAL_CB_DEC 10
|
||||
#define LIMINE_TERMINAL_CB_BELL 20
|
||||
#define LIMINE_TERMINAL_CB_PRIVATE_ID 30
|
||||
#define LIMINE_TERMINAL_CB_STATUS_REPORT 40
|
||||
#define LIMINE_TERMINAL_CB_POS_REPORT 50
|
||||
#define LIMINE_TERMINAL_CB_KBD_LEDS 60
|
||||
#define LIMINE_TERMINAL_CB_MODE 70
|
||||
#define LIMINE_TERMINAL_CB_LINUX 80
|
||||
|
||||
#define LIMINE_TERMINAL_CTX_SIZE ((uint64_t)(-1))
|
||||
#define LIMINE_TERMINAL_CTX_SAVE ((uint64_t)(-2))
|
||||
#define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3))
|
||||
#define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4))
|
||||
|
||||
struct limine_terminal;
|
||||
|
||||
typedef void (*limine_terminal_write)(struct limine_terminal *, const char *, uint64_t);
|
||||
typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t);
|
||||
|
||||
struct limine_terminal {
|
||||
uint64_t columns;
|
||||
uint64_t rows;
|
||||
LIMINE_PTR(struct limine_framebuffer *) framebuffer;
|
||||
};
|
||||
|
||||
struct limine_terminal_response {
|
||||
uint64_t revision;
|
||||
uint64_t terminal_count;
|
||||
LIMINE_PTR(struct limine_terminal **) terminals;
|
||||
LIMINE_PTR(limine_terminal_write) write;
|
||||
};
|
||||
|
||||
struct limine_terminal_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_terminal_response *) response;
|
||||
LIMINE_PTR(limine_terminal_callback) callback;
|
||||
};
|
||||
|
||||
/* 5-level paging */
|
||||
|
||||
#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 }
|
||||
|
||||
struct limine_5_level_paging_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct limine_5_level_paging_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_5_level_paging_response *) response;
|
||||
};
|
||||
|
||||
/* SMP */
|
||||
|
||||
#define LIMINE_SMP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 }
|
||||
|
||||
struct limine_smp_info;
|
||||
|
||||
typedef void (*limine_goto_address)(struct limine_smp_info *);
|
||||
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
|
||||
#define LIMINE_SMP_X2APIC (1 << 0)
|
||||
|
||||
struct limine_smp_info {
|
||||
uint32_t processor_id;
|
||||
uint32_t lapic_id;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct limine_smp_response {
|
||||
uint64_t revision;
|
||||
uint32_t flags;
|
||||
uint32_t bsp_lapic_id;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct limine_smp_info **) cpus;
|
||||
};
|
||||
|
||||
#elif defined (__aarch64__)
|
||||
|
||||
struct limine_smp_info {
|
||||
uint32_t processor_id;
|
||||
uint32_t gic_iface_no;
|
||||
uint64_t mpidr;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct limine_smp_response {
|
||||
uint64_t revision;
|
||||
uint32_t flags;
|
||||
uint64_t bsp_mpidr;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct limine_smp_info **) cpus;
|
||||
};
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
struct limine_smp_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_smp_response *) response;
|
||||
uint64_t flags;
|
||||
};
|
||||
|
||||
/* Memory map */
|
||||
|
||||
#define LIMINE_MEMMAP_REQUEST { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 }
|
||||
|
||||
#define LIMINE_MEMMAP_USABLE 0
|
||||
#define LIMINE_MEMMAP_RESERVED 1
|
||||
#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2
|
||||
#define LIMINE_MEMMAP_ACPI_NVS 3
|
||||
#define LIMINE_MEMMAP_BAD_MEMORY 4
|
||||
#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5
|
||||
#define LIMINE_MEMMAP_KERNEL_AND_MODULES 6
|
||||
#define LIMINE_MEMMAP_FRAMEBUFFER 7
|
||||
|
||||
struct limine_memmap_entry {
|
||||
uint64_t base;
|
||||
uint64_t length;
|
||||
uint64_t type;
|
||||
};
|
||||
|
||||
struct limine_memmap_response {
|
||||
uint64_t revision;
|
||||
uint64_t entry_count;
|
||||
LIMINE_PTR(struct limine_memmap_entry **) entries;
|
||||
};
|
||||
|
||||
struct limine_memmap_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_memmap_response *) response;
|
||||
};
|
||||
|
||||
/* Entry point */
|
||||
|
||||
#define LIMINE_ENTRY_POINT_REQUEST { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a }
|
||||
|
||||
typedef void (*limine_entry_point)(void);
|
||||
|
||||
struct limine_entry_point_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct limine_entry_point_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_entry_point_response *) response;
|
||||
LIMINE_PTR(limine_entry_point) entry;
|
||||
};
|
||||
|
||||
/* Kernel File */
|
||||
|
||||
#define LIMINE_KERNEL_FILE_REQUEST { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 }
|
||||
|
||||
struct limine_kernel_file_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_file *) kernel_file;
|
||||
};
|
||||
|
||||
struct limine_kernel_file_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_kernel_file_response *) response;
|
||||
};
|
||||
|
||||
/* Module */
|
||||
|
||||
#define LIMINE_MODULE_REQUEST { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee }
|
||||
|
||||
struct limine_module_response {
|
||||
uint64_t revision;
|
||||
uint64_t module_count;
|
||||
LIMINE_PTR(struct limine_file **) modules;
|
||||
};
|
||||
|
||||
struct limine_module_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_module_response *) response;
|
||||
};
|
||||
|
||||
/* RSDP */
|
||||
|
||||
#define LIMINE_RSDP_REQUEST { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c }
|
||||
|
||||
struct limine_rsdp_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) address;
|
||||
};
|
||||
|
||||
struct limine_rsdp_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_rsdp_response *) response;
|
||||
};
|
||||
|
||||
/* SMBIOS */
|
||||
|
||||
#define LIMINE_SMBIOS_REQUEST { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee }
|
||||
|
||||
struct limine_smbios_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) entry_32;
|
||||
LIMINE_PTR(void *) entry_64;
|
||||
};
|
||||
|
||||
struct limine_smbios_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_smbios_response *) response;
|
||||
};
|
||||
|
||||
/* EFI system table */
|
||||
|
||||
#define LIMINE_EFI_SYSTEM_TABLE_REQUEST { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc }
|
||||
|
||||
struct limine_efi_system_table_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) address;
|
||||
};
|
||||
|
||||
struct limine_efi_system_table_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_efi_system_table_response *) response;
|
||||
};
|
||||
|
||||
/* Boot time */
|
||||
|
||||
#define LIMINE_BOOT_TIME_REQUEST { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 }
|
||||
|
||||
struct limine_boot_time_response {
|
||||
uint64_t revision;
|
||||
int64_t boot_time;
|
||||
};
|
||||
|
||||
struct limine_boot_time_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_boot_time_response *) response;
|
||||
};
|
||||
|
||||
/* Kernel address */
|
||||
|
||||
#define LIMINE_KERNEL_ADDRESS_REQUEST { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 }
|
||||
|
||||
struct limine_kernel_address_response {
|
||||
uint64_t revision;
|
||||
uint64_t physical_base;
|
||||
uint64_t virtual_base;
|
||||
};
|
||||
|
||||
struct limine_kernel_address_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_kernel_address_response *) response;
|
||||
};
|
||||
|
||||
/* Device Tree Blob */
|
||||
|
||||
#define LIMINE_DTB_REQUEST { LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7 }
|
||||
|
||||
struct limine_dtb_response {
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(void *) dtb_ptr;
|
||||
};
|
||||
|
||||
struct limine_dtb_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_dtb_response *) response;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
BIN
limine.sys
Executable file
BIN
limine.sys
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user