mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-26 10:52:57 +02:00
16088 lines
430 KiB
Diff
16088 lines
430 KiB
Diff
diff -Nur grub-0.97/acinclude.m4 grub-0.97-patched/acinclude.m4
|
||
--- grub-0.97/acinclude.m4 2004-04-27 22:48:06.000000000 +0200
|
||
+++ grub-0.97-patched/acinclude.m4 2012-11-11 17:07:12.710729053 +0100
|
||
@@ -57,7 +57,7 @@
|
||
fi
|
||
grub_cv_prog_objcopy_absolute=yes
|
||
for link_addr in 2000 8000 7C00; do
|
||
- if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -nostdlib -Wl,-N -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then :
|
||
+ if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} ${LDFLAGS} -nostdlib -Wl,-N -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then :
|
||
else
|
||
AC_MSG_ERROR([${CC-cc} cannot link at address $link_addr])
|
||
fi
|
||
diff -Nur grub-0.97/ChangeLog grub-0.97-patched/ChangeLog
|
||
--- grub-0.97/ChangeLog 2005-05-08 04:47:02.000000000 +0200
|
||
+++ grub-0.97-patched/ChangeLog 2012-11-11 17:07:12.708728989 +0100
|
||
@@ -1,3 +1,127 @@
|
||
+2008-05-20 Robert Millan <rmh@aybabtu.com>
|
||
+
|
||
+ * netboot/cs89x0.c: Fix license violation.
|
||
+ * netboot/cs89x0.h: Likewise.
|
||
+
|
||
+2008-04-10 Pavel Roskin <proski@gnu.org>
|
||
+
|
||
+ * configure.ac: Always use "_cv_" in cache variables for
|
||
+ compatibility with Autoconf 2.62.
|
||
+
|
||
+2008-03-28 Robert Millan <rmh@aybabtu.com>
|
||
+
|
||
+ Surpass 1 TiB disk addressing limit. Note: there are no plans to handle
|
||
+ the 2 TiB disk limit in GRUB Legacy, since that would need considerable
|
||
+ rework. If you have >2TiB disks, use GRUB 2 instead.
|
||
+
|
||
+ * grub/asmstub.c (biosdisk): Add unsigned qualifier to `sector'.
|
||
+ * stage2/bios.c (biosdisk): Likewise.
|
||
+ * stage2/disk_io.c (rawread, devread, rawwrite, devwrite): Likewise.
|
||
+ * stage2/shared.h (rawread, devread, rawwrite, devwrite): Likewise.
|
||
+ * lib/device.c (get_drive_geometry): Replace BLKGETSIZE with
|
||
+ BLKGETSIZE64.
|
||
+
|
||
+2007-10-29 Pavel Roskin <proski@gnu.org>
|
||
+
|
||
+ * configure.ac: Test if '--build-id=none' is supported by the
|
||
+ linker and add it to LDFLAGS if possible. Build ID causes
|
||
+ objcopy to generate huge binary files.
|
||
+ * aclocal.m4 (grub_PROG_OBJCOPY_ABSOLUTE): Use LDFLAGS when
|
||
+ linking, so that build ID doesn't break the test.
|
||
+ * stage1/Makefile.am: Preserve LDFLAGS, use stage1_exec_LDFLAGS.
|
||
+
|
||
+2007-02-22 Pavel Roskin <proski@gnu.org>
|
||
+
|
||
+ * stage2/iso9660.h: Remove unnecessary packed attributes.
|
||
+
|
||
+2007-02-22 Robert Millan <rmh@aybabtu.com>
|
||
+
|
||
+ * util/mkbimage: Update my email address, and remove my name from
|
||
+ some places where unnecessary credit is given.
|
||
+
|
||
+2006-09-10 Pavel Roskin <proski@gnu.org>
|
||
+
|
||
+ * netboot/natsemi.c: Fix compile error with gcc 4.1.1. Cast
|
||
+ cannot make a variable volatile - it should be declared as such.
|
||
+ * netboot/sis900.c: Likewise.
|
||
+
|
||
+2006-09-08 Pavel Roskin <proski@gnu.org>
|
||
+
|
||
+ * netboot/etherboot.h: Remove incorrect extern declarations of
|
||
+ the variables later declared static. Move BOOTP_DATA_ADDR ...
|
||
+ * netboot/main.c: ... here. Eliminate end_of_rfc1533 - it's
|
||
+ write-only.
|
||
+
|
||
+2006-06-24 Yoshinori K. Okuji <okuji@enbug.org>
|
||
+
|
||
+ * docs/grub.texi: Changed the license term to the GNU Free
|
||
+ Documentation License 1.2.
|
||
+
|
||
+ * docs/multiboot.texi: Reformatted to show the license term
|
||
+ and the version number explicitly.
|
||
+
|
||
+ * docs/fdl.texi: New file.
|
||
+
|
||
+ * docs/Makefile.am (grub_TEXINFOS): Added fdl.texi.
|
||
+
|
||
+2006-06-24 Robert Millan <robertmh@gnu.org>
|
||
+
|
||
+ * lib/device.c (write_to_partition): /dev/ataraid/ and /dev/rd/
|
||
+ partitions have a "p" prefix. Add it.
|
||
+
|
||
+2006-06-24 Robert Millan <robertmh@gnu.org>
|
||
+
|
||
+ * lib/device.c (get_i2o_disk_name): New function.
|
||
+ (init_device_map) [__linux__]: Add support for I2O devices.
|
||
+
|
||
+2006-05-02 Pavel Roskin <proski@gnu.org>
|
||
+
|
||
+ * stage2/stage2.c (run_menu): Fix "savedefault" to save only top
|
||
+ level menu positions. Remember current position when calling a
|
||
+ submenu. Don't recalculate it when booting from a submenu.
|
||
+
|
||
+ * grub/main.c (main): Make sure the boot drive number doesn't
|
||
+ exceed 255.
|
||
+
|
||
+2006-05-02 Vesa Jaaskelainen <chaac@nic.fi>
|
||
+
|
||
+ * stage2/shared.h (vbe_mode): Back ported aligment fix from GRUB 2
|
||
+ to GRUB Legacy. Problem reported by Gerardo Richarte.
|
||
+
|
||
+2006-04-23 Robert Millan <robertmh@gnu.org>
|
||
+
|
||
+ * grub/asmstub.c (get_diskinfo): Optimize sysctl routine.
|
||
+
|
||
+2006-04-20 Robert Millan <robertmh@gnu.org>
|
||
+
|
||
+ Fixes for kernel of FreeBSD:
|
||
+ * grub/asmstub.c (get_diskinfo): Toggle "kern.geom.debugflags" sysctl
|
||
+ before opening a device for writing.
|
||
+ * util/grub-install.in: Devices don't have this "r" prefix anymore.
|
||
+
|
||
+2006-04-16 Yoshinori K. Okuji <okuji@enbug.org>
|
||
+
|
||
+ * docs/multiboot.texi: Correct the offset of address
|
||
+ fields. Reported by Jeroen Dekkers.
|
||
+
|
||
+2006-03-21 Yoshinori K. Okuji <okuji@enbug.org>
|
||
+
|
||
+ * stage2/builtins.c (setup_func): Specify the size of DEVICE to
|
||
+ grub_strncat instead of a strange number 256. Reported by Vitaly
|
||
+ Fertman <vitaly@namesys.com>.
|
||
+
|
||
+2005-09-29 Yoshinori K. Okuji <okuji@enbug.org>
|
||
+
|
||
+ * docs/multiboot.texi: Fix a bug in the byte order of
|
||
+ boot_device. I hope this won't affect any OS image.
|
||
+ Increased the version number to 0.6.94.
|
||
+
|
||
+2005-09-28 Yoshinori K. Okuji <okuji@enbug.org>
|
||
+
|
||
+ * stage2/boot.c (load_image): Even if an OS image is an ELF
|
||
+ object, use the a.out kludge if MULTIBOOT_AOUT_KLUDGE is
|
||
+ specified.
|
||
+
|
||
2005-05-08 Yoshinori K. Okuji <okuji@enbug.org>
|
||
|
||
* configure.ac (AC_INIT): Upgraded to 0.97.
|
||
diff -Nur grub-0.97/configure.ac grub-0.97-patched/configure.ac
|
||
--- grub-0.97/configure.ac 2005-05-08 04:36:03.000000000 +0200
|
||
+++ grub-0.97-patched/configure.ac 2012-11-11 17:07:12.752730394 +0100
|
||
@@ -21,8 +21,12 @@
|
||
AC_CANONICAL_HOST
|
||
|
||
case "$host_cpu" in
|
||
-i[[3456]]86) host_cpu=i386 ;;
|
||
-x86_64) host_cpu=x86_64 ;;
|
||
+i[[3456]]86)
|
||
+ STAGE_MARCH="-march=$host_cpu"
|
||
+ host_cpu=i386 ;;
|
||
+x86_64)
|
||
+ STAGE_MARCH="-march=i686"
|
||
+ host_cpu=x86_64 ;;
|
||
*) AC_MSG_ERROR([unsupported CPU type]) ;;
|
||
esac
|
||
|
||
@@ -56,12 +60,7 @@
|
||
|
||
AC_CHECK_TOOL(CC, gcc)
|
||
AC_PROG_CC
|
||
-# We need this for older versions of Autoconf.
|
||
-_AM_DEPENDENCIES(CC)
|
||
-
|
||
-dnl Because recent automake complains about AS, set it here.
|
||
-CCAS="$CC"
|
||
-AC_SUBST(CCAS)
|
||
+AM_PROG_AS
|
||
|
||
AC_ARG_WITH(binutils,
|
||
[ --with-binutils=DIR search the directory DIR to find binutils])
|
||
@@ -86,13 +85,13 @@
|
||
fi
|
||
STAGE1_CFLAGS="-O2"
|
||
GRUB_CFLAGS="-O2"
|
||
- AC_CACHE_CHECK([whether optimization for size works], size_flag, [
|
||
+ AC_CACHE_CHECK([whether optimization for size works], grub_cv_cc_Os, [
|
||
saved_CFLAGS=$CFLAGS
|
||
CFLAGS="-Os -g"
|
||
- AC_TRY_COMPILE(, , size_flag=yes, size_flag=no)
|
||
+ AC_TRY_COMPILE(, , grub_cv_cc_Os=yes, grub_cv_cc_Os=no)
|
||
CFLAGS=$saved_CFLAGS
|
||
])
|
||
- if test "x$size_flag" = xyes; then
|
||
+ if test "x$grub_cv_cc_Os" = xyes; then
|
||
STAGE2_CFLAGS="-Os"
|
||
else
|
||
STAGE2_CFLAGS="-O2 -fno-strength-reduce -fno-unroll-loops"
|
||
@@ -100,21 +99,38 @@
|
||
# OpenBSD has a GCC extension for protecting applications from
|
||
# stack smashing attacks, but GRUB doesn't want this feature.
|
||
AC_CACHE_CHECK([whether gcc has -fno-stack-protector],
|
||
- no_stack_protector_flag, [
|
||
+ grub_cv_cc_no_stack_protector, [
|
||
saved_CFLAGS=$CFLAGS
|
||
CFLAGS="-fno-stack-protector"
|
||
AC_TRY_COMPILE(,
|
||
,
|
||
- no_stack_protector_flag=yes,
|
||
- no_stack_protector_flag=no)
|
||
+ grub_cv_cc_no_stack_protector=yes,
|
||
+ grub_cv_cc_no_stack_protector=no)
|
||
CFLAGS=$saved_CFLAGS
|
||
])
|
||
- if test "x$no_stack_protector_flag" = xyes; then
|
||
+ if test "x$grub_cv_cc_no_stack_protector" = xyes; then
|
||
STAGE2_CFLAGS="$STAGE2_CFLAGS -fno-stack-protector"
|
||
fi
|
||
+ # Position Independent Executables, but GRUB doesn't want this feature.
|
||
+ AC_CACHE_CHECK([whether gcc has -fPIE on as default], grub_cv_cc_fpie, [
|
||
+ AC_TRY_COMPILE(,[
|
||
+ #if ! defined (__PIC__) || ! defined (__PIE__)
|
||
+ #error
|
||
+ #endif
|
||
+ ],
|
||
+ grub_cv_cc_fpie=yes,
|
||
+ grub_cv_cc_fpie=no)
|
||
+ ])
|
||
+ if test "x$grub_cv_cc_fpie" = xyes; then
|
||
+ STAGE1_CFLAGS="$STAGE1_CFLAGS -nopie"
|
||
+ STAGE2_CFLAGS="$STAGE2_CFLAGS -nopie"
|
||
+ fi
|
||
fi
|
||
fi
|
||
|
||
+STAGE1_CFLAGS="$STAGE1_CFLAGS -fno-strict-aliasing $STAGE_MARCH"
|
||
+STAGE2_CFLAGS="$STAGE2_CFLAGS -fno-strict-aliasing $STAGE_MARCH"
|
||
+GRUB_CFLAGS="$GRUB_CFLAGS -fno-strict-aliasing"
|
||
AC_SUBST(STAGE1_CFLAGS)
|
||
AC_SUBST(STAGE2_CFLAGS)
|
||
AC_SUBST(GRUB_CFLAGS)
|
||
@@ -123,33 +139,44 @@
|
||
CPPFLAGS="$CPPFLAGS -Wall -Wmissing-prototypes -Wunused -Wshadow"
|
||
CPPFLAGS="$CPPFLAGS -Wpointer-arith"
|
||
|
||
-AC_CACHE_CHECK([whether -Wundef works], undef_flag, [
|
||
+AC_CACHE_CHECK([whether -Wundef works], grub_cv_cc_Wundef, [
|
||
saved_CPPFLAGS="$CPPFLAGS"
|
||
CPPFLAGS="-Wundef"
|
||
- AC_TRY_COMPILE(, , undef_flag=yes, undef_flag=no)
|
||
+ AC_TRY_COMPILE(, , grub_cv_cc_Wundef=yes, grub_cv_cc_Wundef=no)
|
||
CPPFLAGS="$saved_CPPFLAGS"
|
||
])
|
||
|
||
# The options `-falign-*' are supported by gcc 3.0 or later.
|
||
# Probably it is sufficient to only check for -falign-loops.
|
||
-AC_CACHE_CHECK([whether -falign-loops works], [falign_loop_flag], [
|
||
+AC_CACHE_CHECK([whether -falign-loops works], [grub_cv_cc_falign_loop], [
|
||
saved_CPPFLAGS="$CPPFLAGS"
|
||
CPPFLAGS="-falign-loops=1"
|
||
- AC_TRY_COMPILE(, , [falign_loop_flag=yes], [falign_loop_flag=no])
|
||
+ AC_TRY_COMPILE(, , [grub_cv_cc_falign_loop=yes], [grub_cv_cc_falign_loop=no])
|
||
CPPFLAGS="$saved_CPPFLAGS"
|
||
])
|
||
|
||
# Force no alignment to save space.
|
||
-if test "x$falign_loop_flag" = xyes; then
|
||
+if test "x$grub_cv_cc_falign_loop" = xyes; then
|
||
CPPFLAGS="$CPPFLAGS -falign-jumps=1 -falign-loops=1 -falign-functions=1"
|
||
else
|
||
CPPFLAGS="$CPPFLAGS -malign-jumps=1 -malign-loops=1 -malign-functions=1"
|
||
fi
|
||
|
||
-if test "x$undef_flag" = xyes; then
|
||
+if test "x$grub_cv_cc_Wundef" = xyes; then
|
||
CPPFLAGS="$CPPFLAGS -Wundef"
|
||
fi
|
||
|
||
+# Check if build ID can be disabled in the linker
|
||
+AC_MSG_CHECKING([whether linker accepts `--build-id=none'])
|
||
+save_LDFLAGS="$LDFLAGS"
|
||
+LDFLAGS="$LDFLAGS -Wl,--build-id=none"
|
||
+AC_TRY_LINK(, , build_id_flag=yes, build_id_flag=no)
|
||
+AC_MSG_RESULT([$build_id_flag])
|
||
+LDFLAGS="$save_LDFLAGS"
|
||
+if test "x$build_id_flag" = xyes; then
|
||
+ LDFLAGS="$LDFLAGS -Wl,--build-id=none"
|
||
+fi
|
||
+
|
||
if test "x$with_binutils" != x; then
|
||
dnl AC_PATH_TOOL(OBJCOPY, objcopy, , "$with_binutils:$PATH")
|
||
AC_PATH_PROG(OBJCOPY, objcopy, , "$with_binutils:$PATH")
|
||
@@ -595,6 +622,11 @@
|
||
[ --enable-diskless enable diskless support])
|
||
AM_CONDITIONAL(DISKLESS_SUPPORT, test "x$enable_diskless" = xyes)
|
||
|
||
+dnl Graphical splashscreen support
|
||
+AC_ARG_ENABLE(graphics,
|
||
+ [ --disable-graphics disable graphics terminal support])
|
||
+AM_CONDITIONAL(GRAPHICS_SUPPORT, test "x$enable_graphics" != xno)
|
||
+
|
||
dnl Hercules terminal
|
||
AC_ARG_ENABLE(hercules,
|
||
[ --disable-hercules disable hercules terminal support])
|
||
diff -Nur grub-0.97/docs/fdl.texi grub-0.97-patched/docs/fdl.texi
|
||
--- grub-0.97/docs/fdl.texi 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/docs/fdl.texi 2012-11-11 17:07:12.712729117 +0100
|
||
@@ -0,0 +1,452 @@
|
||
+
|
||
+@node GNU Free Documentation License
|
||
+@appendixsec GNU Free Documentation License
|
||
+
|
||
+@cindex FDL, GNU Free Documentation License
|
||
+@center Version 1.2, November 2002
|
||
+
|
||
+@display
|
||
+Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc.
|
||
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||
+
|
||
+Everyone is permitted to copy and distribute verbatim copies
|
||
+of this license document, but changing it is not allowed.
|
||
+@end display
|
||
+
|
||
+@enumerate 0
|
||
+@item
|
||
+PREAMBLE
|
||
+
|
||
+The purpose of this License is to make a manual, textbook, or other
|
||
+functional and useful document @dfn{free} in the sense of freedom: to
|
||
+assure everyone the effective freedom to copy and redistribute it,
|
||
+with or without modifying it, either commercially or noncommercially.
|
||
+Secondarily, this License preserves for the author and publisher a way
|
||
+to get credit for their work, while not being considered responsible
|
||
+for modifications made by others.
|
||
+
|
||
+This License is a kind of ``copyleft'', which means that derivative
|
||
+works of the document must themselves be free in the same sense. It
|
||
+complements the GNU General Public License, which is a copyleft
|
||
+license designed for free software.
|
||
+
|
||
+We have designed this License in order to use it for manuals for free
|
||
+software, because free software needs free documentation: a free
|
||
+program should come with manuals providing the same freedoms that the
|
||
+software does. But this License is not limited to software manuals;
|
||
+it can be used for any textual work, regardless of subject matter or
|
||
+whether it is published as a printed book. We recommend this License
|
||
+principally for works whose purpose is instruction or reference.
|
||
+
|
||
+@item
|
||
+APPLICABILITY AND DEFINITIONS
|
||
+
|
||
+This License applies to any manual or other work, in any medium, that
|
||
+contains a notice placed by the copyright holder saying it can be
|
||
+distributed under the terms of this License. Such a notice grants a
|
||
+world-wide, royalty-free license, unlimited in duration, to use that
|
||
+work under the conditions stated herein. The ``Document'', below,
|
||
+refers to any such manual or work. Any member of the public is a
|
||
+licensee, and is addressed as ``you''. You accept the license if you
|
||
+copy, modify or distribute the work in a way requiring permission
|
||
+under copyright law.
|
||
+
|
||
+A ``Modified Version'' of the Document means any work containing the
|
||
+Document or a portion of it, either copied verbatim, or with
|
||
+modifications and/or translated into another language.
|
||
+
|
||
+A ``Secondary Section'' is a named appendix or a front-matter section
|
||
+of the Document that deals exclusively with the relationship of the
|
||
+publishers or authors of the Document to the Document's overall
|
||
+subject (or to related matters) and contains nothing that could fall
|
||
+directly within that overall subject. (Thus, if the Document is in
|
||
+part a textbook of mathematics, a Secondary Section may not explain
|
||
+any mathematics.) The relationship could be a matter of historical
|
||
+connection with the subject or with related matters, or of legal,
|
||
+commercial, philosophical, ethical or political position regarding
|
||
+them.
|
||
+
|
||
+The ``Invariant Sections'' are certain Secondary Sections whose titles
|
||
+are designated, as being those of Invariant Sections, in the notice
|
||
+that says that the Document is released under this License. If a
|
||
+section does not fit the above definition of Secondary then it is not
|
||
+allowed to be designated as Invariant. The Document may contain zero
|
||
+Invariant Sections. If the Document does not identify any Invariant
|
||
+Sections then there are none.
|
||
+
|
||
+The ``Cover Texts'' are certain short passages of text that are listed,
|
||
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
|
||
+the Document is released under this License. A Front-Cover Text may
|
||
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
|
||
+
|
||
+A ``Transparent'' copy of the Document means a machine-readable copy,
|
||
+represented in a format whose specification is available to the
|
||
+general public, that is suitable for revising the document
|
||
+straightforwardly with generic text editors or (for images composed of
|
||
+pixels) generic paint programs or (for drawings) some widely available
|
||
+drawing editor, and that is suitable for input to text formatters or
|
||
+for automatic translation to a variety of formats suitable for input
|
||
+to text formatters. A copy made in an otherwise Transparent file
|
||
+format whose markup, or absence of markup, has been arranged to thwart
|
||
+or discourage subsequent modification by readers is not Transparent.
|
||
+An image format is not Transparent if used for any substantial amount
|
||
+of text. A copy that is not ``Transparent'' is called ``Opaque''.
|
||
+
|
||
+Examples of suitable formats for Transparent copies include plain
|
||
+@sc{ascii} without markup, Texinfo input format, La@TeX{} input
|
||
+format, @acronym{SGML} or @acronym{XML} using a publicly available
|
||
+@acronym{DTD}, and standard-conforming simple @acronym{HTML},
|
||
+PostScript or @acronym{PDF} designed for human modification. Examples
|
||
+of transparent image formats include @acronym{PNG}, @acronym{XCF} and
|
||
+@acronym{JPG}. Opaque formats include proprietary formats that can be
|
||
+read and edited only by proprietary word processors, @acronym{SGML} or
|
||
+@acronym{XML} for which the @acronym{DTD} and/or processing tools are
|
||
+not generally available, and the machine-generated @acronym{HTML},
|
||
+PostScript or @acronym{PDF} produced by some word processors for
|
||
+output purposes only.
|
||
+
|
||
+The ``Title Page'' means, for a printed book, the title page itself,
|
||
+plus such following pages as are needed to hold, legibly, the material
|
||
+this License requires to appear in the title page. For works in
|
||
+formats which do not have any title page as such, ``Title Page'' means
|
||
+the text near the most prominent appearance of the work's title,
|
||
+preceding the beginning of the body of the text.
|
||
+
|
||
+A section ``Entitled XYZ'' means a named subunit of the Document whose
|
||
+title either is precisely XYZ or contains XYZ in parentheses following
|
||
+text that translates XYZ in another language. (Here XYZ stands for a
|
||
+specific section name mentioned below, such as ``Acknowledgements'',
|
||
+``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title''
|
||
+of such a section when you modify the Document means that it remains a
|
||
+section ``Entitled XYZ'' according to this definition.
|
||
+
|
||
+The Document may include Warranty Disclaimers next to the notice which
|
||
+states that this License applies to the Document. These Warranty
|
||
+Disclaimers are considered to be included by reference in this
|
||
+License, but only as regards disclaiming warranties: any other
|
||
+implication that these Warranty Disclaimers may have is void and has
|
||
+no effect on the meaning of this License.
|
||
+
|
||
+@item
|
||
+VERBATIM COPYING
|
||
+
|
||
+You may copy and distribute the Document in any medium, either
|
||
+commercially or noncommercially, provided that this License, the
|
||
+copyright notices, and the license notice saying this License applies
|
||
+to the Document are reproduced in all copies, and that you add no other
|
||
+conditions whatsoever to those of this License. You may not use
|
||
+technical measures to obstruct or control the reading or further
|
||
+copying of the copies you make or distribute. However, you may accept
|
||
+compensation in exchange for copies. If you distribute a large enough
|
||
+number of copies you must also follow the conditions in section 3.
|
||
+
|
||
+You may also lend copies, under the same conditions stated above, and
|
||
+you may publicly display copies.
|
||
+
|
||
+@item
|
||
+COPYING IN QUANTITY
|
||
+
|
||
+If you publish printed copies (or copies in media that commonly have
|
||
+printed covers) of the Document, numbering more than 100, and the
|
||
+Document's license notice requires Cover Texts, you must enclose the
|
||
+copies in covers that carry, clearly and legibly, all these Cover
|
||
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
|
||
+the back cover. Both covers must also clearly and legibly identify
|
||
+you as the publisher of these copies. The front cover must present
|
||
+the full title with all words of the title equally prominent and
|
||
+visible. You may add other material on the covers in addition.
|
||
+Copying with changes limited to the covers, as long as they preserve
|
||
+the title of the Document and satisfy these conditions, can be treated
|
||
+as verbatim copying in other respects.
|
||
+
|
||
+If the required texts for either cover are too voluminous to fit
|
||
+legibly, you should put the first ones listed (as many as fit
|
||
+reasonably) on the actual cover, and continue the rest onto adjacent
|
||
+pages.
|
||
+
|
||
+If you publish or distribute Opaque copies of the Document numbering
|
||
+more than 100, you must either include a machine-readable Transparent
|
||
+copy along with each Opaque copy, or state in or with each Opaque copy
|
||
+a computer-network location from which the general network-using
|
||
+public has access to download using public-standard network protocols
|
||
+a complete Transparent copy of the Document, free of added material.
|
||
+If you use the latter option, you must take reasonably prudent steps,
|
||
+when you begin distribution of Opaque copies in quantity, to ensure
|
||
+that this Transparent copy will remain thus accessible at the stated
|
||
+location until at least one year after the last time you distribute an
|
||
+Opaque copy (directly or through your agents or retailers) of that
|
||
+edition to the public.
|
||
+
|
||
+It is requested, but not required, that you contact the authors of the
|
||
+Document well before redistributing any large number of copies, to give
|
||
+them a chance to provide you with an updated version of the Document.
|
||
+
|
||
+@item
|
||
+MODIFICATIONS
|
||
+
|
||
+You may copy and distribute a Modified Version of the Document under
|
||
+the conditions of sections 2 and 3 above, provided that you release
|
||
+the Modified Version under precisely this License, with the Modified
|
||
+Version filling the role of the Document, thus licensing distribution
|
||
+and modification of the Modified Version to whoever possesses a copy
|
||
+of it. In addition, you must do these things in the Modified Version:
|
||
+
|
||
+@enumerate A
|
||
+@item
|
||
+Use in the Title Page (and on the covers, if any) a title distinct
|
||
+from that of the Document, and from those of previous versions
|
||
+(which should, if there were any, be listed in the History section
|
||
+of the Document). You may use the same title as a previous version
|
||
+if the original publisher of that version gives permission.
|
||
+
|
||
+@item
|
||
+List on the Title Page, as authors, one or more persons or entities
|
||
+responsible for authorship of the modifications in the Modified
|
||
+Version, together with at least five of the principal authors of the
|
||
+Document (all of its principal authors, if it has fewer than five),
|
||
+unless they release you from this requirement.
|
||
+
|
||
+@item
|
||
+State on the Title page the name of the publisher of the
|
||
+Modified Version, as the publisher.
|
||
+
|
||
+@item
|
||
+Preserve all the copyright notices of the Document.
|
||
+
|
||
+@item
|
||
+Add an appropriate copyright notice for your modifications
|
||
+adjacent to the other copyright notices.
|
||
+
|
||
+@item
|
||
+Include, immediately after the copyright notices, a license notice
|
||
+giving the public permission to use the Modified Version under the
|
||
+terms of this License, in the form shown in the Addendum below.
|
||
+
|
||
+@item
|
||
+Preserve in that license notice the full lists of Invariant Sections
|
||
+and required Cover Texts given in the Document's license notice.
|
||
+
|
||
+@item
|
||
+Include an unaltered copy of this License.
|
||
+
|
||
+@item
|
||
+Preserve the section Entitled ``History'', Preserve its Title, and add
|
||
+to it an item stating at least the title, year, new authors, and
|
||
+publisher of the Modified Version as given on the Title Page. If
|
||
+there is no section Entitled ``History'' in the Document, create one
|
||
+stating the title, year, authors, and publisher of the Document as
|
||
+given on its Title Page, then add an item describing the Modified
|
||
+Version as stated in the previous sentence.
|
||
+
|
||
+@item
|
||
+Preserve the network location, if any, given in the Document for
|
||
+public access to a Transparent copy of the Document, and likewise
|
||
+the network locations given in the Document for previous versions
|
||
+it was based on. These may be placed in the ``History'' section.
|
||
+You may omit a network location for a work that was published at
|
||
+least four years before the Document itself, or if the original
|
||
+publisher of the version it refers to gives permission.
|
||
+
|
||
+@item
|
||
+For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
|
||
+the Title of the section, and preserve in the section all the
|
||
+substance and tone of each of the contributor acknowledgements and/or
|
||
+dedications given therein.
|
||
+
|
||
+@item
|
||
+Preserve all the Invariant Sections of the Document,
|
||
+unaltered in their text and in their titles. Section numbers
|
||
+or the equivalent are not considered part of the section titles.
|
||
+
|
||
+@item
|
||
+Delete any section Entitled ``Endorsements''. Such a section
|
||
+may not be included in the Modified Version.
|
||
+
|
||
+@item
|
||
+Do not retitle any existing section to be Entitled ``Endorsements'' or
|
||
+to conflict in title with any Invariant Section.
|
||
+
|
||
+@item
|
||
+Preserve any Warranty Disclaimers.
|
||
+@end enumerate
|
||
+
|
||
+If the Modified Version includes new front-matter sections or
|
||
+appendices that qualify as Secondary Sections and contain no material
|
||
+copied from the Document, you may at your option designate some or all
|
||
+of these sections as invariant. To do this, add their titles to the
|
||
+list of Invariant Sections in the Modified Version's license notice.
|
||
+These titles must be distinct from any other section titles.
|
||
+
|
||
+You may add a section Entitled ``Endorsements'', provided it contains
|
||
+nothing but endorsements of your Modified Version by various
|
||
+parties---for example, statements of peer review or that the text has
|
||
+been approved by an organization as the authoritative definition of a
|
||
+standard.
|
||
+
|
||
+You may add a passage of up to five words as a Front-Cover Text, and a
|
||
+passage of up to 25 words as a Back-Cover Text, to the end of the list
|
||
+of Cover Texts in the Modified Version. Only one passage of
|
||
+Front-Cover Text and one of Back-Cover Text may be added by (or
|
||
+through arrangements made by) any one entity. If the Document already
|
||
+includes a cover text for the same cover, previously added by you or
|
||
+by arrangement made by the same entity you are acting on behalf of,
|
||
+you may not add another; but you may replace the old one, on explicit
|
||
+permission from the previous publisher that added the old one.
|
||
+
|
||
+The author(s) and publisher(s) of the Document do not by this License
|
||
+give permission to use their names for publicity for or to assert or
|
||
+imply endorsement of any Modified Version.
|
||
+
|
||
+@item
|
||
+COMBINING DOCUMENTS
|
||
+
|
||
+You may combine the Document with other documents released under this
|
||
+License, under the terms defined in section 4 above for modified
|
||
+versions, provided that you include in the combination all of the
|
||
+Invariant Sections of all of the original documents, unmodified, and
|
||
+list them all as Invariant Sections of your combined work in its
|
||
+license notice, and that you preserve all their Warranty Disclaimers.
|
||
+
|
||
+The combined work need only contain one copy of this License, and
|
||
+multiple identical Invariant Sections may be replaced with a single
|
||
+copy. If there are multiple Invariant Sections with the same name but
|
||
+different contents, make the title of each such section unique by
|
||
+adding at the end of it, in parentheses, the name of the original
|
||
+author or publisher of that section if known, or else a unique number.
|
||
+Make the same adjustment to the section titles in the list of
|
||
+Invariant Sections in the license notice of the combined work.
|
||
+
|
||
+In the combination, you must combine any sections Entitled ``History''
|
||
+in the various original documents, forming one section Entitled
|
||
+``History''; likewise combine any sections Entitled ``Acknowledgements'',
|
||
+and any sections Entitled ``Dedications''. You must delete all
|
||
+sections Entitled ``Endorsements.''
|
||
+
|
||
+@item
|
||
+COLLECTIONS OF DOCUMENTS
|
||
+
|
||
+You may make a collection consisting of the Document and other documents
|
||
+released under this License, and replace the individual copies of this
|
||
+License in the various documents with a single copy that is included in
|
||
+the collection, provided that you follow the rules of this License for
|
||
+verbatim copying of each of the documents in all other respects.
|
||
+
|
||
+You may extract a single document from such a collection, and distribute
|
||
+it individually under this License, provided you insert a copy of this
|
||
+License into the extracted document, and follow this License in all
|
||
+other respects regarding verbatim copying of that document.
|
||
+
|
||
+@item
|
||
+AGGREGATION WITH INDEPENDENT WORKS
|
||
+
|
||
+A compilation of the Document or its derivatives with other separate
|
||
+and independent documents or works, in or on a volume of a storage or
|
||
+distribution medium, is called an ``aggregate'' if the copyright
|
||
+resulting from the compilation is not used to limit the legal rights
|
||
+of the compilation's users beyond what the individual works permit.
|
||
+When the Document is included in an aggregate, this License does not
|
||
+apply to the other works in the aggregate which are not themselves
|
||
+derivative works of the Document.
|
||
+
|
||
+If the Cover Text requirement of section 3 is applicable to these
|
||
+copies of the Document, then if the Document is less than one half of
|
||
+the entire aggregate, the Document's Cover Texts may be placed on
|
||
+covers that bracket the Document within the aggregate, or the
|
||
+electronic equivalent of covers if the Document is in electronic form.
|
||
+Otherwise they must appear on printed covers that bracket the whole
|
||
+aggregate.
|
||
+
|
||
+@item
|
||
+TRANSLATION
|
||
+
|
||
+Translation is considered a kind of modification, so you may
|
||
+distribute translations of the Document under the terms of section 4.
|
||
+Replacing Invariant Sections with translations requires special
|
||
+permission from their copyright holders, but you may include
|
||
+translations of some or all Invariant Sections in addition to the
|
||
+original versions of these Invariant Sections. You may include a
|
||
+translation of this License, and all the license notices in the
|
||
+Document, and any Warranty Disclaimers, provided that you also include
|
||
+the original English version of this License and the original versions
|
||
+of those notices and disclaimers. In case of a disagreement between
|
||
+the translation and the original version of this License or a notice
|
||
+or disclaimer, the original version will prevail.
|
||
+
|
||
+If a section in the Document is Entitled ``Acknowledgements'',
|
||
+``Dedications'', or ``History'', the requirement (section 4) to Preserve
|
||
+its Title (section 1) will typically require changing the actual
|
||
+title.
|
||
+
|
||
+@item
|
||
+TERMINATION
|
||
+
|
||
+You may not copy, modify, sublicense, or distribute the Document except
|
||
+as expressly provided for under this License. Any other attempt to
|
||
+copy, modify, sublicense or distribute the Document is void, and will
|
||
+automatically terminate your rights under this License. However,
|
||
+parties who have received copies, or rights, from you under this
|
||
+License will not have their licenses terminated so long as such
|
||
+parties remain in full compliance.
|
||
+
|
||
+@item
|
||
+FUTURE REVISIONS OF THIS LICENSE
|
||
+
|
||
+The Free Software Foundation may publish new, revised versions
|
||
+of the GNU Free Documentation License from time to time. Such new
|
||
+versions will be similar in spirit to the present version, but may
|
||
+differ in detail to address new problems or concerns. See
|
||
+@uref{http://www.gnu.org/copyleft/}.
|
||
+
|
||
+Each version of the License is given a distinguishing version number.
|
||
+If the Document specifies that a particular numbered version of this
|
||
+License ``or any later version'' applies to it, you have the option of
|
||
+following the terms and conditions either of that specified version or
|
||
+of any later version that has been published (not as a draft) by the
|
||
+Free Software Foundation. If the Document does not specify a version
|
||
+number of this License, you may choose any version ever published (not
|
||
+as a draft) by the Free Software Foundation.
|
||
+@end enumerate
|
||
+
|
||
+@page
|
||
+@appendixsubsec ADDENDUM: How to use this License for your documents
|
||
+
|
||
+To use this License in a document you have written, include a copy of
|
||
+the License in the document and put the following copyright and
|
||
+license notices just after the title page:
|
||
+
|
||
+@smallexample
|
||
+@group
|
||
+ Copyright (C) @var{year} @var{your name}.
|
||
+ Permission is granted to copy, distribute and/or modify this document
|
||
+ under the terms of the GNU Free Documentation License, Version 1.2
|
||
+ or any later version published by the Free Software Foundation;
|
||
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
|
||
+ Texts. A copy of the license is included in the section entitled ``GNU
|
||
+ Free Documentation License''.
|
||
+@end group
|
||
+@end smallexample
|
||
+
|
||
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
|
||
+replace the ``with...Texts.'' line with this:
|
||
+
|
||
+@smallexample
|
||
+@group
|
||
+ with the Invariant Sections being @var{list their titles}, with
|
||
+ the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
|
||
+ being @var{list}.
|
||
+@end group
|
||
+@end smallexample
|
||
+
|
||
+If you have Invariant Sections without Cover Texts, or some other
|
||
+combination of the three, merge those two alternatives to suit the
|
||
+situation.
|
||
+
|
||
+If your document contains nontrivial examples of program code, we
|
||
+recommend releasing these examples in parallel under your choice of
|
||
+free software license, such as the GNU General Public License,
|
||
+to permit their use in free software.
|
||
+
|
||
+@c Local Variables:
|
||
+@c ispell-local-pdict: "ispell-dict"
|
||
+@c End:
|
||
+
|
||
diff -Nur grub-0.97/docs/grub.8 grub-0.97-patched/docs/grub.8
|
||
--- grub-0.97/docs/grub.8 2005-05-08 04:48:56.000000000 +0200
|
||
+++ grub-0.97-patched/docs/grub.8 2012-11-11 17:07:12.715729211 +0100
|
||
@@ -1,5 +1,5 @@
|
||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23.
|
||
-.TH GRUB "8" "May 2005" "grub (GNU GRUB 0.97)" FSF
|
||
+.TH GRUB "8" "June 2006" "grub (GNU GRUB 0.97)" FSF
|
||
.SH NAME
|
||
grub \- the grub shell
|
||
.SH SYNOPSIS
|
||
diff -Nur grub-0.97/docs/grub.8.additions grub-0.97-patched/docs/grub.8.additions
|
||
--- grub-0.97/docs/grub.8.additions 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/docs/grub.8.additions 2012-11-11 17:07:12.702728798 +0100
|
||
@@ -0,0 +1,3 @@
|
||
+[SEE ALSO]
|
||
+.BR update-grub (8),
|
||
+.BR grub-install (8).
|
||
diff -Nur grub-0.97/docs/grub-install.8 grub-0.97-patched/docs/grub-install.8
|
||
--- grub-0.97/docs/grub-install.8 2005-05-08 04:48:56.000000000 +0200
|
||
+++ grub-0.97-patched/docs/grub-install.8 2012-11-11 17:07:12.713729149 +0100
|
||
@@ -1,5 +1,5 @@
|
||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23.
|
||
-.TH GRUB-INSTALL "8" "May 2005" "grub-install (GNU GRUB 0.97)" FSF
|
||
+.TH GRUB-INSTALL "8" "June 2006" "grub-install (GNU GRUB 0.97)" FSF
|
||
.SH NAME
|
||
grub-install \- install GRUB on your drive
|
||
.SH SYNOPSIS
|
||
diff -Nur grub-0.97/docs/grub-install.8.additions grub-0.97-patched/docs/grub-install.8.additions
|
||
--- grub-0.97/docs/grub-install.8.additions 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/docs/grub-install.8.additions 2012-11-11 17:07:12.703728829 +0100
|
||
@@ -0,0 +1,3 @@
|
||
+[SEE ALSO]
|
||
+.BR grub (8),
|
||
+.BR update-grub (8).
|
||
diff -Nur grub-0.97/docs/grub-md5-crypt.8 grub-0.97-patched/docs/grub-md5-crypt.8
|
||
--- grub-0.97/docs/grub-md5-crypt.8 2005-05-08 04:48:56.000000000 +0200
|
||
+++ grub-0.97-patched/docs/grub-md5-crypt.8 2012-11-11 17:07:12.713729149 +0100
|
||
@@ -1,5 +1,5 @@
|
||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23.
|
||
-.TH GRUB-MD5-CRYPT "8" "May 2005" "grub-md5-crypt (GNU GRUB )" FSF
|
||
+.TH GRUB-MD5-CRYPT "8" "June 2006" "grub-md5-crypt (GNU GRUB )" FSF
|
||
.SH NAME
|
||
grub-md5-crypt \- Encrypt a password in MD5 format
|
||
.SH SYNOPSIS
|
||
diff -Nur grub-0.97/docs/grub-terminfo.8 grub-0.97-patched/docs/grub-terminfo.8
|
||
--- grub-0.97/docs/grub-terminfo.8 2005-05-08 04:48:56.000000000 +0200
|
||
+++ grub-0.97-patched/docs/grub-terminfo.8 2012-11-11 17:07:12.714729180 +0100
|
||
@@ -1,5 +1,5 @@
|
||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23.
|
||
-.TH GRUB-TERMINFO "8" "May 2005" "grub-terminfo (GNU GRUB 0.97)" FSF
|
||
+.TH GRUB-TERMINFO "8" "June 2006" "grub-terminfo (GNU GRUB 0.97)" FSF
|
||
.SH NAME
|
||
grub-terminfo \- Generate a terminfo command from a terminfo name
|
||
.SH SYNOPSIS
|
||
diff -Nur grub-0.97/docs/grub.texi grub-0.97-patched/docs/grub.texi
|
||
--- grub-0.97/docs/grub.texi 2005-05-08 04:59:59.000000000 +0200
|
||
+++ grub-0.97-patched/docs/grub.texi 2012-11-11 17:07:12.717729276 +0100
|
||
@@ -2,22 +2,41 @@
|
||
@c -*-texinfo-*-
|
||
@c %**start of header
|
||
@setfilename grub.info
|
||
-@settitle GRUB Manual
|
||
-@c %**end of header
|
||
-
|
||
@include version.texi
|
||
-
|
||
+@settitle GNU GRUB Manual @value{VERSION}
|
||
@c Unify all our little indices for now.
|
||
@syncodeindex fn cp
|
||
@syncodeindex vr cp
|
||
@syncodeindex ky cp
|
||
@syncodeindex pg cp
|
||
@syncodeindex tp cp
|
||
+@c %**end of header
|
||
|
||
@footnotestyle separate
|
||
@paragraphindent 3
|
||
@finalout
|
||
|
||
+@copying
|
||
+This manual is for GNU GRUB (version @value{VERSION},
|
||
+@value{UPDATED}).
|
||
+
|
||
+Copyright @copyright{} 1999,2000,2001,2002,2004,2006 Free Software Foundation, Inc.
|
||
+
|
||
+@quotation
|
||
+Permission is granted to copy, distribute and/or modify this document
|
||
+under the terms of the GNU Free Documentation License, Version 1.2 or
|
||
+any later version published by the Free Software Foundation; with no
|
||
+Invariant Sections, with the Front-Cover Texts being ``A GNU Manual,''
|
||
+and with the Back-Cover Texts as in (a) below. A copy of the
|
||
+license is included in the section entitled ``GNU Free Documentation
|
||
+License.''
|
||
+
|
||
+(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify
|
||
+this GNU Manual, like GNU software. Copies published by the Free
|
||
+Software Foundation raise funds for GNU development.''
|
||
+@end quotation
|
||
+@end copying
|
||
+
|
||
@dircategory Kernel
|
||
@direntry
|
||
* GRUB: (grub). The GRand Unified Bootloader
|
||
@@ -34,53 +53,16 @@
|
||
|
||
@setchapternewpage odd
|
||
|
||
-@ifinfo
|
||
-Copyright @copyright{} 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
|
||
-
|
||
-Permission is granted to make and distribute verbatim copies of
|
||
-this manual provided the copyright notice and this permission notice
|
||
-are preserved on all copies.
|
||
-
|
||
-@ignore
|
||
-Permission is granted to process this file through TeX and print the
|
||
-results, provided the printed document carries a copying permission
|
||
-notice identical to this one except for the removal of this paragraph
|
||
-(this paragraph not being relevant to the printed manual).
|
||
-
|
||
-@end ignore
|
||
-
|
||
-Permission is granted to copy and distribute modified versions of this
|
||
-manual under the conditions for verbatim copying, provided also that
|
||
-the entire resulting derived work is distributed under the terms of a
|
||
-permission notice identical to this one.
|
||
-
|
||
-Permission is granted to copy and distribute translations of this manual
|
||
-into another language, under the above conditions for modified versions.
|
||
-@end ifinfo
|
||
-
|
||
@titlepage
|
||
@sp 10
|
||
-@title the GRUB manual
|
||
+@title the GNU GRUB manual
|
||
@subtitle The GRand Unified Bootloader, version @value{VERSION}, @value{UPDATED}.
|
||
@author Gordon Matzigkeit
|
||
@author Yoshinori K. Okuji
|
||
@c The following two commands start the copyright page.
|
||
@page
|
||
@vskip 0pt plus 1filll
|
||
-Copyright @copyright{} 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
|
||
-
|
||
-Permission is granted to make and distribute verbatim copies of
|
||
-this manual provided the copyright notice and this permission notice
|
||
-are preserved on all copies.
|
||
-Permission is granted to copy and distribute modified versions of this
|
||
-manual under the conditions for verbatim copying, provided that the entire
|
||
-resulting derived work is distributed under the terms of a permission
|
||
-notice identical to this one.
|
||
-
|
||
-Permission is granted to copy and distribute translations of this manual
|
||
-into another language, under the above conditions for modified versions,
|
||
-except that this permission notice may be stated in a translation approved
|
||
-by Free Software Foundation.
|
||
+@insertcopying
|
||
@end titlepage
|
||
|
||
@c Output the table of contents at the beginning.
|
||
@@ -91,12 +73,14 @@
|
||
|
||
@ifnottex
|
||
@node Top
|
||
-@top GRUB manual
|
||
+@top GNU GRUB manual
|
||
|
||
This is the documentation of GNU GRUB, the GRand Unified Bootloader,
|
||
a flexible and powerful boot loader program for @sc{pc}s.
|
||
|
||
This edition documents version @value{VERSION}.
|
||
+
|
||
+@insertcopying
|
||
@end ifnottex
|
||
|
||
@menu
|
||
@@ -124,6 +108,7 @@
|
||
* Reporting bugs:: Where you should send a bug report
|
||
* Future:: Some future plans on GRUB
|
||
* Internals:: Hacking GRUB
|
||
+* Copying This Manual:: Copying This Manual
|
||
* Index::
|
||
@end menu
|
||
|
||
@@ -3965,6 +3950,16 @@
|
||
@include internals.texi
|
||
|
||
|
||
+@node Copying This Manual
|
||
+@appendix Copying This Manual
|
||
+
|
||
+@menu
|
||
+* GNU Free Documentation License:: License for copying this manual.
|
||
+@end menu
|
||
+
|
||
+@include fdl.texi
|
||
+
|
||
+
|
||
@node Index
|
||
@unnumbered Index
|
||
|
||
diff -Nur grub-0.97/docs/help2man grub-0.97-patched/docs/help2man
|
||
--- grub-0.97/docs/help2man 2003-07-09 13:45:36.000000000 +0200
|
||
+++ grub-0.97-patched/docs/help2man 2012-11-11 17:07:12.701728766 +0100
|
||
@@ -455,7 +455,9 @@
|
||
$include{$sect} .= <<EOT;
|
||
The full documentation for
|
||
.B $program
|
||
-is maintained as a Texinfo manual. If the
|
||
+is maintained as a Texinfo manual in the
|
||
+.B grub-doc
|
||
+package. If the
|
||
.B info
|
||
and
|
||
.B $program
|
||
diff -Nur grub-0.97/docs/Makefile.am grub-0.97-patched/docs/Makefile.am
|
||
--- grub-0.97/docs/Makefile.am 2003-07-09 13:45:35.000000000 +0200
|
||
+++ grub-0.97-patched/docs/Makefile.am 2012-11-11 17:07:12.711729085 +0100
|
||
@@ -1,5 +1,5 @@
|
||
info_TEXINFOS = grub.texi multiboot.texi
|
||
-grub_TEXINFOS = internals.texi
|
||
+grub_TEXINFOS = internals.texi fdl.texi
|
||
EXAMPLES = boot.S kernel.c multiboot.h
|
||
multiboot_TEXINFOS = boot.S.texi kernel.c.texi multiboot.h.texi
|
||
man_MANS = grub.8 mbchk.1 grub-install.8 grub-md5-crypt.8 grub-terminfo.8
|
||
@@ -37,14 +37,14 @@
|
||
$(SHELL) $(srcdir)/$(SRC2TEXI) $(srcdir) $< $@
|
||
|
||
if MAINTAINER_MODE
|
||
-$(srcdir)/grub.8: ../grub/grub $(srcdir)/$(HELP2MAN)
|
||
+$(srcdir)/grub.8: ../grub/grub $(srcdir)/$(HELP2MAN) $(srcdir)/grub.8.additions
|
||
$(PERL) $(srcdir)/$(HELP2MAN) --name="the grub shell" \
|
||
- --section=8 --output=$@ $<
|
||
+ --section=8 --include=$@.additions --output=$@ $<
|
||
|
||
-$(srcdir)/grub-install.8: ../util/grub-install $(srcdir)/$(HELP2MAN)
|
||
+$(srcdir)/grub-install.8: ../util/grub-install $(srcdir)/$(HELP2MAN) $(srcdir)/grub-install.8.additions
|
||
chmod 755 $<
|
||
$(PERL) $(srcdir)/$(HELP2MAN) --name="install GRUB on your drive" \
|
||
- --section=8 --output=$@ $<
|
||
+ --section=8 --include=$@.additions --output=$@ $<
|
||
|
||
$(srcdir)/mbchk.1: ../util/mbchk $(srcdir)/$(HELP2MAN)
|
||
$(PERL) $(srcdir)/$(HELP2MAN) \
|
||
diff -Nur grub-0.97/docs/mbchk.1 grub-0.97-patched/docs/mbchk.1
|
||
--- grub-0.97/docs/mbchk.1 2005-05-08 04:48:56.000000000 +0200
|
||
+++ grub-0.97-patched/docs/mbchk.1 2012-11-11 17:07:12.717729276 +0100
|
||
@@ -1,5 +1,5 @@
|
||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.23.
|
||
-.TH MBCHK "1" "May 2005" "mbchk (GNU GRUB 0.97)" FSF
|
||
+.TH MBCHK "1" "June 2006" "mbchk (GNU GRUB 0.97)" FSF
|
||
.SH NAME
|
||
mbchk \- check the format of a Multiboot kernel
|
||
.SH SYNOPSIS
|
||
diff -Nur grub-0.97/docs/menu.lst grub-0.97-patched/docs/menu.lst
|
||
--- grub-0.97/docs/menu.lst 2004-05-11 14:11:17.000000000 +0200
|
||
+++ grub-0.97-patched/docs/menu.lst 2012-11-11 17:07:07.225553829 +0100
|
||
@@ -11,6 +11,9 @@
|
||
# Fallback to the second entry.
|
||
fallback 1
|
||
|
||
+# Splash image to show behind grub.
|
||
+splashimage=(hd0,0)/boot/grub/splash.xpm.gz
|
||
+
|
||
# For booting GNU/Hurd
|
||
title GNU/Hurd
|
||
root (hd0,0)
|
||
@@ -23,6 +26,11 @@
|
||
kernel /vmlinuz root=/dev/hdb1
|
||
#initrd /initrd.img
|
||
|
||
+# For booting Gentoo with the static rescue shell
|
||
+title Gentoo (rescue shell)
|
||
+root (hd1,0)
|
||
+kernel /vmlinuz root=/dev/hdb1 init=/bin/bb
|
||
+
|
||
# For booting GNU/kFreeBSD
|
||
title GNU/kFreeBSD
|
||
root (hd0,2,a)
|
||
diff -Nur grub-0.97/docs/menu.lst.orig grub-0.97-patched/docs/menu.lst.orig
|
||
--- grub-0.97/docs/menu.lst.orig 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/docs/menu.lst.orig 2004-05-11 14:11:17.000000000 +0200
|
||
@@ -0,0 +1,82 @@
|
||
+#
|
||
+# Sample boot menu configuration file
|
||
+#
|
||
+
|
||
+# Boot automatically after 30 secs.
|
||
+timeout 30
|
||
+
|
||
+# By default, boot the first entry.
|
||
+default 0
|
||
+
|
||
+# Fallback to the second entry.
|
||
+fallback 1
|
||
+
|
||
+# For booting GNU/Hurd
|
||
+title GNU/Hurd
|
||
+root (hd0,0)
|
||
+kernel /boot/gnumach.gz root=hd0s1
|
||
+module /boot/serverboot.gz
|
||
+
|
||
+# For booting GNU/Linux
|
||
+title GNU/Linux
|
||
+root (hd1,0)
|
||
+kernel /vmlinuz root=/dev/hdb1
|
||
+#initrd /initrd.img
|
||
+
|
||
+# For booting GNU/kFreeBSD
|
||
+title GNU/kFreeBSD
|
||
+root (hd0,2,a)
|
||
+kernel /boot/loader.gz
|
||
+
|
||
+# For booting GNU/kNetBSD
|
||
+title GNU/kNetBSD
|
||
+root (hd0,2,a)
|
||
+kernel --type=netbsd /boot/knetbsd.gz
|
||
+
|
||
+# For booting Mach (getting kernel from floppy)
|
||
+title Utah Mach4 multiboot
|
||
+root (hd0,2)
|
||
+pause Insert the diskette now!!
|
||
+kernel (fd0)/boot/kernel root=hd0s3
|
||
+module (fd0)/boot/bootstrap
|
||
+
|
||
+# For booting FreeBSD
|
||
+title FreeBSD
|
||
+root (hd0,2,a)
|
||
+kernel /boot/loader
|
||
+
|
||
+# For booting NetBSD
|
||
+title NetBSD
|
||
+root (hd0,2,a)
|
||
+kernel --type=netbsd /netbsd
|
||
+
|
||
+# For booting OpenBSD
|
||
+title OpenBSD
|
||
+root (hd0,2,a)
|
||
+kernel --type=netbsd /bsd
|
||
+
|
||
+# For booting OS/2
|
||
+title OS/2
|
||
+root (hd0,1)
|
||
+makeactive
|
||
+# chainload OS/2 bootloader from the first sector
|
||
+chainloader +1
|
||
+# This is similar to "chainload", but loads a specific file
|
||
+#chainloader /boot/chain.os2
|
||
+
|
||
+# For booting Windows NT or Windows95
|
||
+title Windows NT / Windows 95 boot menu
|
||
+rootnoverify (hd0,0)
|
||
+makeactive
|
||
+chainloader +1
|
||
+# For loading DOS if Windows NT is installed
|
||
+# chainload /bootsect.dos
|
||
+
|
||
+# For installing GRUB into the hard disk
|
||
+title Install GRUB into the hard disk
|
||
+root (hd0,0)
|
||
+setup (hd0)
|
||
+
|
||
+# Change the colors.
|
||
+title Change the colors
|
||
+color light-green/brown blink-red/blue
|
||
diff -Nur grub-0.97/docs/multiboot.texi grub-0.97-patched/docs/multiboot.texi
|
||
--- grub-0.97/docs/multiboot.texi 2003-07-09 13:45:36.000000000 +0200
|
||
+++ grub-0.97-patched/docs/multiboot.texi 2012-11-11 17:07:12.718729309 +0100
|
||
@@ -1,32 +1,28 @@
|
||
\input texinfo @c -*-texinfo-*-
|
||
-@c -*-texinfo-*-
|
||
@c %**start of header
|
||
@setfilename multiboot.info
|
||
-@settitle Multiboot Specification
|
||
-@c %**end of header
|
||
-
|
||
+@set VERSION 0.6.95
|
||
+@settitle Multiboot Specification version @value{VERSION}
|
||
@c Unify all our little indices for now.
|
||
@syncodeindex fn cp
|
||
@syncodeindex vr cp
|
||
@syncodeindex ky cp
|
||
@syncodeindex pg cp
|
||
@syncodeindex tp cp
|
||
+@c %**end of header
|
||
|
||
@footnotestyle separate
|
||
@paragraphindent 3
|
||
@finalout
|
||
|
||
+@copying
|
||
+Copyright @copyright{} 1995,96 Bryan Ford <baford@@cs.utah.edu>
|
||
|
||
-@dircategory Kernel
|
||
-@direntry
|
||
-* Multiboot Specification: (multiboot). Multiboot Specification.
|
||
-@end direntry
|
||
+Copyright @copyright{} 1995,96 Erich Stefan Boleyn <erich@@uruk.org>
|
||
|
||
-@ifinfo
|
||
-Copyright @copyright{} 1995, 96 Bryan Ford <baford@@cs.utah.edu>
|
||
-Copyright @copyright{} 1995, 96 Erich Stefan Boleyn <erich@@uruk.org>
|
||
-Copyright @copyright{} 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||
+Copyright @copyright{} 1999,2000,2001,2002,2005,2006 Free Software Foundation, Inc.
|
||
|
||
+@quotation
|
||
Permission is granted to make and distribute verbatim copies of
|
||
this manual provided the copyright notice and this permission notice
|
||
are preserved on all copies.
|
||
@@ -36,7 +32,6 @@
|
||
results, provided the printed document carries a copying permission
|
||
notice identical to this one except for the removal of this paragraph
|
||
(this paragraph not being relevant to the printed manual).
|
||
-
|
||
@end ignore
|
||
|
||
Permission is granted to copy and distribute modified versions of this
|
||
@@ -45,31 +40,23 @@
|
||
permission notice identical to this one.
|
||
|
||
Permission is granted to copy and distribute translations of this manual
|
||
-into another language, under the above conditions for modified versions.
|
||
-@end ifinfo
|
||
+into another language, under the above conditions for modified
|
||
+versions.
|
||
+@end quotation
|
||
+@end copying
|
||
+
|
||
+@dircategory Kernel
|
||
+@direntry
|
||
+* Multiboot Specification: (multiboot). Multiboot Specification.
|
||
+@end direntry
|
||
|
||
@titlepage
|
||
@sp 10
|
||
-@title The Multiboot Specification
|
||
+@title The Multiboot Specification version @value{VERSION}
|
||
@author Yoshinori K. Okuji, Bryan Ford, Erich Stefan Boleyn, Kunihiro Ishiguro
|
||
@page
|
||
-
|
||
@vskip 0pt plus 1filll
|
||
-Copyright @copyright{} 1995, 96 Bryan Ford <baford@@cs.utah.edu>
|
||
-Copyright @copyright{} 1995, 96 Erich Stefan Boleyn <erich@@uruk.org>
|
||
-Copyright @copyright{} 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||
-
|
||
-Permission is granted to make and distribute verbatim copies of
|
||
-this manual provided the copyright notice and this permission notice
|
||
-are preserved on all copies.
|
||
-
|
||
-Permission is granted to copy and distribute modified versions of this
|
||
-manual under the conditions for verbatim copying, provided also that
|
||
-the entire resulting derived work is distributed under the terms of a
|
||
-permission notice identical to this one.
|
||
-
|
||
-Permission is granted to copy and distribute translations of this manual
|
||
-into another language, under the above conditions for modified versions.
|
||
+@insertcopying
|
||
@end titlepage
|
||
|
||
@finalout
|
||
@@ -80,7 +67,9 @@
|
||
@top Multiboot Specification
|
||
|
||
This file documents Multiboot Specification, the proposal for the boot
|
||
-sequence standard. This edition documents version 0.6.93.
|
||
+sequence standard. This edition documents version @value{VERSION}.
|
||
+
|
||
+@insertcopying
|
||
@end ifnottex
|
||
|
||
@menu
|
||
@@ -426,7 +415,7 @@
|
||
kernel.
|
||
|
||
If bit 16 in the @samp{flags} word is set, then the fields at offsets
|
||
-8-24 in the Multiboot header are valid, and the boot loader should use
|
||
+12-28 in the Multiboot header are valid, and the boot loader should use
|
||
them instead of the fields in the actual executable header to calculate
|
||
where to load the OS image. This information does not need to be
|
||
provided if the kernel image is in @sc{elf} format, but it @emph{must}
|
||
@@ -677,7 +666,7 @@
|
||
@example
|
||
@group
|
||
+-------+-------+-------+-------+
|
||
-| drive | part1 | part2 | part3 |
|
||
+| part3 | part2 | part1 | drive |
|
||
+-------+-------+-------+-------+
|
||
@end group
|
||
@end example
|
||
@@ -1197,6 +1186,17 @@
|
||
@item
|
||
The maintainer changes to the GNU GRUB maintainer team
|
||
@email{bug-grub@@gnu.org}, from Bryan Ford and Erich Stefan Boleyn.
|
||
+
|
||
+@item
|
||
+The byte order of the @samp{boot_device} in Multiboot information is
|
||
+reversed. This was a mistake.
|
||
+
|
||
+@item
|
||
+The offset of the address fields were wrong.
|
||
+
|
||
+@item
|
||
+The format is adapted to a newer Texinfo, and the version number is
|
||
+specified more explicitly in the title.
|
||
@end itemize
|
||
|
||
@item 0.6
|
||
diff -Nur grub-0.97/grub/asmstub.c grub-0.97-patched/grub/asmstub.c
|
||
--- grub-0.97/grub/asmstub.c 2005-02-16 21:45:14.000000000 +0100
|
||
+++ grub-0.97-patched/grub/asmstub.c 2012-11-11 17:07:12.719729342 +0100
|
||
@@ -42,6 +42,7 @@
|
||
#include <sys/time.h>
|
||
#include <termios.h>
|
||
#include <signal.h>
|
||
+#include <sys/mman.h>
|
||
|
||
#ifdef __linux__
|
||
# include <sys/ioctl.h> /* ioctl */
|
||
@@ -55,6 +56,10 @@
|
||
# endif /* ! BLKFLSBUF */
|
||
#endif /* __linux__ */
|
||
|
||
+#if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
|
||
+# include <sys/sysctl.h>
|
||
+#endif
|
||
+
|
||
/* We want to prevent any circularararity in our stubs, as well as
|
||
libc name clashes. */
|
||
#define WITHOUT_LIBC_STUBS 1
|
||
@@ -79,7 +84,7 @@
|
||
struct apm_info apm_bios_info;
|
||
|
||
/* Emulation requirements. */
|
||
-char *grub_scratch_mem = 0;
|
||
+void *grub_scratch_mem = 0;
|
||
|
||
struct geometry *disks = 0;
|
||
|
||
@@ -103,14 +108,62 @@
|
||
static unsigned int serial_speed;
|
||
#endif /* SIMULATE_SLOWNESS_OF_SERIAL */
|
||
|
||
+/* This allocates page-aligned storage of the specified size, which must be
|
||
+ * a multiple of the page size as determined by calling sysconf(_SC_PAGESIZE)
|
||
+ */
|
||
+#ifdef __linux__
|
||
+static void *
|
||
+grub_mmap_alloc(size_t len)
|
||
+{
|
||
+ int mmap_flags = MAP_ANONYMOUS|MAP_PRIVATE;
|
||
+
|
||
+#ifdef MAP_32BIT
|
||
+ mmap_flags |= MAP_32BIT;
|
||
+#endif
|
||
+ /* Mark the simulated stack executable, as GCC uses stack trampolines
|
||
+ * to implement nested functions. */
|
||
+ return mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC, mmap_flags, -1, 0);
|
||
+}
|
||
+#else /* !defined(__linux__) */
|
||
+static void *
|
||
+grub_mmap_alloc(size_t len)
|
||
+{
|
||
+ int fd = 0, offset = 0, ret = 0;
|
||
+ void *pa = MAP_FAILED;
|
||
+ char template[] = "/tmp/grub_mmap_alloc_XXXXXX";
|
||
+ int e;
|
||
+
|
||
+ fd = mkstemp(template);
|
||
+ if (fd < 0)
|
||
+ return pa;
|
||
+
|
||
+ unlink(template);
|
||
+
|
||
+ ret = ftruncate(fd, len);
|
||
+ if (ret < 0)
|
||
+ return pa;
|
||
+
|
||
+ /* Mark the simulated stack executable, as GCC uses stack trampolines
|
||
+ * to implement nested functions. */
|
||
+ pa = mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC,
|
||
+ MAP_PRIVATE, fd, offset);
|
||
+
|
||
+ e = errno;
|
||
+ close(fd);
|
||
+ errno = e;
|
||
+ return pa;
|
||
+}
|
||
+#endif /* defined(__linux__) */
|
||
+
|
||
/* The main entry point into this mess. */
|
||
int
|
||
grub_stage2 (void)
|
||
{
|
||
/* These need to be static, because they survive our stack transitions. */
|
||
static int status = 0;
|
||
- static char *realstack;
|
||
- char *scratch, *simstack;
|
||
+ static void *realstack;
|
||
+ void *simstack_alloc_base, *simstack;
|
||
+ size_t simstack_size, page_size;
|
||
int i;
|
||
|
||
auto void doit (void);
|
||
@@ -142,9 +195,35 @@
|
||
}
|
||
|
||
assert (grub_scratch_mem == 0);
|
||
- scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15);
|
||
- assert (scratch);
|
||
- grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4);
|
||
+
|
||
+ /* Allocate enough pages for 0x100000 + EXTENDED_SIZE + 15, and
|
||
+ * make sure the memory is aligned to a multiple of the system's
|
||
+ * page size */
|
||
+ page_size = sysconf (_SC_PAGESIZE);
|
||
+ simstack_size = ( 0x100000 + EXTENDED_MEMSIZE + 15);
|
||
+ if (simstack_size % page_size)
|
||
+ {
|
||
+ /* If we're not on a page_size boundary, round up to the next one */
|
||
+ simstack_size &= ~(page_size-1);
|
||
+ simstack_size += page_size;
|
||
+ }
|
||
+
|
||
+ /* Add one for a PROT_NONE boundary page at each end. */
|
||
+ simstack_size += 2 * page_size;
|
||
+
|
||
+ simstack_alloc_base = grub_mmap_alloc(simstack_size);
|
||
+ assert (simstack_alloc_base != MAP_FAILED);
|
||
+
|
||
+ /* mark pages above and below our simstack area as innaccessable.
|
||
+ * If the implementation we're using doesn't support that, then the
|
||
+ * new protection modes are undefined. It's safe to just ignore
|
||
+ * them, though. It'd be nice if we knew that we'd get a SEGV for
|
||
+ * touching the area, but that's all. it'd be nice to have. */
|
||
+ mprotect (simstack_alloc_base, page_size, PROT_NONE);
|
||
+ mprotect ((void *)((unsigned long)simstack_alloc_base +
|
||
+ simstack_size - page_size), page_size, PROT_NONE);
|
||
+
|
||
+ grub_scratch_mem = (void *)((unsigned long)simstack_alloc_base + page_size);
|
||
|
||
/* FIXME: simulate the memory holes using mprot, if available. */
|
||
|
||
@@ -217,7 +296,7 @@
|
||
device_map = 0;
|
||
free (disks);
|
||
disks = 0;
|
||
- free (scratch);
|
||
+ munmap(simstack_alloc_base, simstack_size);
|
||
grub_scratch_mem = 0;
|
||
|
||
if (serial_device)
|
||
@@ -777,7 +856,39 @@
|
||
|
||
/* Open read/write, or read-only if that failed. */
|
||
if (! read_only)
|
||
- disks[drive].flags = open (devname, O_RDWR);
|
||
+ {
|
||
+/* By default, kernel of FreeBSD does not allow overwriting MBR */
|
||
+#if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
|
||
+#define GEOM_SYSCTL "kern.geom.debugflags"
|
||
+ int old_flags, flags;
|
||
+ size_t sizeof_int = sizeof (int);
|
||
+
|
||
+ if (sysctlbyname (GEOM_SYSCTL, &old_flags, &sizeof_int, NULL, 0) != 0)
|
||
+ grub_printf ("failed to get " GEOM_SYSCTL "sysctl: %s\n", strerror (errno));
|
||
+
|
||
+ if ((old_flags & 0x10) == 0)
|
||
+ {
|
||
+ /* "allow foot shooting", see geom(4) */
|
||
+ flags = old_flags | 0x10;
|
||
+
|
||
+ if (sysctlbyname (GEOM_SYSCTL, NULL, NULL, &flags, sizeof (int)) != 0)
|
||
+ {
|
||
+ flags = old_flags;
|
||
+ grub_printf ("failed to set " GEOM_SYSCTL "sysctl: %s\n", strerror (errno));
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ flags = old_flags;
|
||
+#endif
|
||
+ disks[drive].flags = open (devname, O_RDWR);
|
||
+#if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
|
||
+ if (flags != old_flags)
|
||
+ {
|
||
+ if (sysctlbyname (GEOM_SYSCTL, NULL, NULL, &old_flags, sizeof (int)) != 0)
|
||
+ grub_printf ("failed to set " GEOM_SYSCTL "sysctl: %s\n", strerror (errno));
|
||
+ }
|
||
+#endif
|
||
+ }
|
||
|
||
if (disks[drive].flags == -1)
|
||
{
|
||
@@ -926,7 +1037,7 @@
|
||
|
||
int
|
||
biosdisk (int subfunc, int drive, struct geometry *geometry,
|
||
- int sector, int nsec, int segment)
|
||
+ unsigned int sector, int nsec, int segment)
|
||
{
|
||
char *buf;
|
||
int fd = geometry->flags;
|
||
diff -Nur grub-0.97/grub/asmstub.c.orig grub-0.97-patched/grub/asmstub.c.orig
|
||
--- grub-0.97/grub/asmstub.c.orig 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/grub/asmstub.c.orig 2005-02-16 21:45:14.000000000 +0100
|
||
@@ -0,0 +1,1275 @@
|
||
+/* asmstub.c - a version of shared_src/asm.S that works under Unix */
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License as published by
|
||
+ * the Free Software Foundation; either version 2 of the License, or
|
||
+ * (at your option) any later version.
|
||
+ *
|
||
+ * This program is distributed in the hope that it will be useful,
|
||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ * GNU General Public License for more details.
|
||
+ *
|
||
+ * You should have received a copy of the GNU General Public License
|
||
+ * along with this program; if not, write to the Free Software
|
||
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
+ */
|
||
+
|
||
+/* Try to use glibc's transparant LFS support. */
|
||
+#define _LARGEFILE_SOURCE 1
|
||
+/* lseek becomes synonymous with lseek64. */
|
||
+#define _FILE_OFFSET_BITS 64
|
||
+
|
||
+/* Simulator entry point. */
|
||
+int grub_stage2 (void);
|
||
+
|
||
+#include <stdlib.h>
|
||
+#include <string.h>
|
||
+#include <ctype.h>
|
||
+#include <assert.h>
|
||
+#include <stdio.h>
|
||
+#include <sys/types.h>
|
||
+#include <sys/stat.h>
|
||
+#include <fcntl.h>
|
||
+#include <time.h>
|
||
+#include <errno.h>
|
||
+#include <string.h>
|
||
+#include <unistd.h>
|
||
+#include <setjmp.h>
|
||
+#include <sys/time.h>
|
||
+#include <termios.h>
|
||
+#include <signal.h>
|
||
+
|
||
+#ifdef __linux__
|
||
+# include <sys/ioctl.h> /* ioctl */
|
||
+# if !defined(__GLIBC__) || \
|
||
+ ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
|
||
+/* Maybe libc doesn't have large file support. */
|
||
+# include <linux/unistd.h> /* _llseek */
|
||
+# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
|
||
+# ifndef BLKFLSBUF
|
||
+# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
|
||
+# endif /* ! BLKFLSBUF */
|
||
+#endif /* __linux__ */
|
||
+
|
||
+/* We want to prevent any circularararity in our stubs, as well as
|
||
+ libc name clashes. */
|
||
+#define WITHOUT_LIBC_STUBS 1
|
||
+#include <shared.h>
|
||
+#include <device.h>
|
||
+#include <serial.h>
|
||
+#include <term.h>
|
||
+
|
||
+/* Simulated memory sizes. */
|
||
+#define EXTENDED_MEMSIZE (3 * 1024 * 1024) /* 3MB */
|
||
+#define CONVENTIONAL_MEMSIZE (640 * 1024) /* 640kB */
|
||
+
|
||
+unsigned long install_partition = 0x20000;
|
||
+unsigned long boot_drive = 0;
|
||
+int saved_entryno = 0;
|
||
+char version_string[] = VERSION;
|
||
+char config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */
|
||
+unsigned long linux_text_len = 0;
|
||
+char *linux_data_tmp_addr = 0;
|
||
+char *linux_data_real_addr = 0;
|
||
+unsigned short io_map[IO_MAP_SIZE];
|
||
+struct apm_info apm_bios_info;
|
||
+
|
||
+/* Emulation requirements. */
|
||
+char *grub_scratch_mem = 0;
|
||
+
|
||
+struct geometry *disks = 0;
|
||
+
|
||
+/* The map between BIOS drives and UNIX device file names. */
|
||
+char **device_map = 0;
|
||
+
|
||
+/* The jump buffer for exiting correctly. */
|
||
+static jmp_buf env_for_exit;
|
||
+
|
||
+/* The current color for console. */
|
||
+int console_current_color = A_NORMAL;
|
||
+
|
||
+/* The file descriptor for a serial device. */
|
||
+static int serial_fd = -1;
|
||
+
|
||
+/* The file name of a serial device. */
|
||
+static char *serial_device = 0;
|
||
+
|
||
+#ifdef SIMULATE_SLOWNESS_OF_SERIAL
|
||
+/* The speed of a serial device. */
|
||
+static unsigned int serial_speed;
|
||
+#endif /* SIMULATE_SLOWNESS_OF_SERIAL */
|
||
+
|
||
+/* The main entry point into this mess. */
|
||
+int
|
||
+grub_stage2 (void)
|
||
+{
|
||
+ /* These need to be static, because they survive our stack transitions. */
|
||
+ static int status = 0;
|
||
+ static char *realstack;
|
||
+ char *scratch, *simstack;
|
||
+ int i;
|
||
+
|
||
+ auto void doit (void);
|
||
+
|
||
+ /* We need a nested function so that we get a clean stack frame,
|
||
+ regardless of how the code is optimized. */
|
||
+ void doit (void)
|
||
+ {
|
||
+ /* Make sure our stack lives in the simulated memory area. */
|
||
+ asm volatile ("movl %%esp, %0\n\tmovl %1, %%esp\n"
|
||
+ : "=&r" (realstack) : "r" (simstack));
|
||
+
|
||
+ /* Do a setjmp here for the stop command. */
|
||
+ if (! setjmp (env_for_exit))
|
||
+ {
|
||
+ /* Actually enter the generic stage2 code. */
|
||
+ status = 0;
|
||
+ init_bios_info ();
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* If ERRNUM is non-zero, then set STATUS to non-zero. */
|
||
+ if (errnum)
|
||
+ status = 1;
|
||
+ }
|
||
+
|
||
+ /* Replace our stack before we use any local variables. */
|
||
+ asm volatile ("movl %0, %%esp\n" : : "r" (realstack));
|
||
+ }
|
||
+
|
||
+ assert (grub_scratch_mem == 0);
|
||
+ scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15);
|
||
+ assert (scratch);
|
||
+ grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4);
|
||
+
|
||
+ /* FIXME: simulate the memory holes using mprot, if available. */
|
||
+
|
||
+ assert (disks == 0);
|
||
+ disks = malloc (NUM_DISKS * sizeof (*disks));
|
||
+ assert (disks);
|
||
+ /* Initialize DISKS. */
|
||
+ for (i = 0; i < NUM_DISKS; i++)
|
||
+ disks[i].flags = -1;
|
||
+
|
||
+ if (! init_device_map (&device_map, device_map_file, floppy_disks))
|
||
+ return 1;
|
||
+
|
||
+ /* Check some invariants. */
|
||
+ assert ((SCRATCHSEG << 4) == SCRATCHADDR);
|
||
+ assert ((BUFFERSEG << 4) == BUFFERADDR);
|
||
+ assert (BUFFERADDR + BUFFERLEN == SCRATCHADDR);
|
||
+ assert (FSYS_BUF % 16 == 0);
|
||
+ assert (FSYS_BUF + FSYS_BUFLEN == BUFFERADDR);
|
||
+
|
||
+#ifdef HAVE_LIBCURSES
|
||
+ /* Get into char-at-a-time mode. */
|
||
+ if (use_curses)
|
||
+ {
|
||
+ initscr ();
|
||
+ cbreak ();
|
||
+ noecho ();
|
||
+ nonl ();
|
||
+ scrollok (stdscr, TRUE);
|
||
+ keypad (stdscr, TRUE);
|
||
+ wtimeout (stdscr, 100);
|
||
+ signal (SIGWINCH, SIG_IGN);
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ /* Make sure that actual writing is done. */
|
||
+ sync ();
|
||
+
|
||
+ /* Set our stack, and go for it. */
|
||
+ simstack = (char *) PROTSTACKINIT;
|
||
+ doit ();
|
||
+
|
||
+ /* I don't know if this is necessary really. */
|
||
+ sync ();
|
||
+
|
||
+#ifdef HAVE_LIBCURSES
|
||
+ if (use_curses)
|
||
+ endwin ();
|
||
+#endif
|
||
+
|
||
+ /* Close off the file descriptors we used. */
|
||
+ for (i = 0; i < NUM_DISKS; i ++)
|
||
+ if (disks[i].flags != -1)
|
||
+ {
|
||
+#ifdef __linux__
|
||
+ /* In Linux, invalidate the buffer cache. In other OSes, reboot
|
||
+ is one of the solutions... */
|
||
+ ioctl (disks[i].flags, BLKFLSBUF, 0);
|
||
+#else
|
||
+# warning "In your operating system, the buffer cache will not be flushed."
|
||
+#endif
|
||
+ close (disks[i].flags);
|
||
+ }
|
||
+
|
||
+ if (serial_fd >= 0)
|
||
+ close (serial_fd);
|
||
+
|
||
+ /* Release memory. */
|
||
+ restore_device_map (device_map);
|
||
+ device_map = 0;
|
||
+ free (disks);
|
||
+ disks = 0;
|
||
+ free (scratch);
|
||
+ grub_scratch_mem = 0;
|
||
+
|
||
+ if (serial_device)
|
||
+ free (serial_device);
|
||
+ serial_device = 0;
|
||
+
|
||
+ /* Ahh... at last we're ready to return to caller. */
|
||
+ return status;
|
||
+}
|
||
+
|
||
+/* Assign DRIVE to a device name DEVICE. */
|
||
+void
|
||
+assign_device_name (int drive, const char *device)
|
||
+{
|
||
+ /* If DRIVE is already assigned, free it. */
|
||
+ if (device_map[drive])
|
||
+ free (device_map[drive]);
|
||
+
|
||
+ /* If the old one is already opened, close it. */
|
||
+ if (disks[drive].flags != -1)
|
||
+ {
|
||
+ close (disks[drive].flags);
|
||
+ disks[drive].flags = -1;
|
||
+ }
|
||
+
|
||
+ /* Assign DRIVE to DEVICE. */
|
||
+ if (! device)
|
||
+ device_map[drive] = 0;
|
||
+ else
|
||
+ device_map[drive] = strdup (device);
|
||
+}
|
||
+
|
||
+void
|
||
+stop (void)
|
||
+{
|
||
+#ifdef HAVE_LIBCURSES
|
||
+ if (use_curses)
|
||
+ endwin ();
|
||
+#endif
|
||
+
|
||
+ /* Jump to doit. */
|
||
+ longjmp (env_for_exit, 1);
|
||
+}
|
||
+
|
||
+void
|
||
+grub_reboot (void)
|
||
+{
|
||
+ stop ();
|
||
+}
|
||
+
|
||
+void
|
||
+grub_halt (int no_apm)
|
||
+{
|
||
+ stop ();
|
||
+}
|
||
+
|
||
+/* calls for direct boot-loader chaining */
|
||
+void
|
||
+chain_stage1 (unsigned long segment, unsigned long offset,
|
||
+ unsigned long part_table_addr)
|
||
+{
|
||
+ stop ();
|
||
+}
|
||
+
|
||
+
|
||
+void
|
||
+chain_stage2 (unsigned long segment, unsigned long offset, int second_sector)
|
||
+{
|
||
+ stop ();
|
||
+}
|
||
+
|
||
+
|
||
+/* do some funky stuff, then boot linux */
|
||
+void
|
||
+linux_boot (void)
|
||
+{
|
||
+ stop ();
|
||
+}
|
||
+
|
||
+
|
||
+/* For bzImage kernels. */
|
||
+void
|
||
+big_linux_boot (void)
|
||
+{
|
||
+ stop ();
|
||
+}
|
||
+
|
||
+
|
||
+/* booting a multiboot executable */
|
||
+void
|
||
+multi_boot (int start, int mb_info)
|
||
+{
|
||
+ stop ();
|
||
+}
|
||
+
|
||
+/* sets it to linear or wired A20 operation */
|
||
+void
|
||
+gateA20 (int linear)
|
||
+{
|
||
+ /* Nothing to do in the simulator. */
|
||
+}
|
||
+
|
||
+/* Set up the int15 handler. */
|
||
+void
|
||
+set_int15_handler (void)
|
||
+{
|
||
+ /* Nothing to do in the simulator. */
|
||
+}
|
||
+
|
||
+/* Restore the original int15 handler. */
|
||
+void
|
||
+unset_int15_handler (void)
|
||
+{
|
||
+ /* Nothing to do in the simulator. */
|
||
+}
|
||
+
|
||
+/* The key map. */
|
||
+unsigned short bios_key_map[KEY_MAP_SIZE + 1];
|
||
+unsigned short ascii_key_map[KEY_MAP_SIZE + 1];
|
||
+
|
||
+/* Copy MAP to the drive map and set up the int13 handler. */
|
||
+void
|
||
+set_int13_handler (unsigned short *map)
|
||
+{
|
||
+ /* Nothing to do in the simulator. */
|
||
+}
|
||
+
|
||
+int
|
||
+get_code_end (void)
|
||
+{
|
||
+ /* Just return a little area for simulation. */
|
||
+ return BOOTSEC_LOCATION + (60 * 1024);
|
||
+}
|
||
+
|
||
+
|
||
+/* memory probe routines */
|
||
+int
|
||
+get_memsize (int type)
|
||
+{
|
||
+ if (! type)
|
||
+ return CONVENTIONAL_MEMSIZE >> 10;
|
||
+ else
|
||
+ return EXTENDED_MEMSIZE >> 10;
|
||
+}
|
||
+
|
||
+
|
||
+/* get_eisamemsize() : return packed EISA memory map, lower 16 bits is
|
||
+ * memory between 1M and 16M in 1K parts, upper 16 bits is
|
||
+ * memory above 16M in 64K parts. If error, return -1.
|
||
+ */
|
||
+int
|
||
+get_eisamemsize (void)
|
||
+{
|
||
+ return (EXTENDED_MEMSIZE >> 10);
|
||
+}
|
||
+
|
||
+
|
||
+#define MMAR_DESC_TYPE_AVAILABLE 1 /* available to OS */
|
||
+#define MMAR_DESC_TYPE_RESERVED 2 /* not available */
|
||
+#define MMAR_DESC_TYPE_ACPI_RECLAIM 3 /* usable by OS after reading ACPI */
|
||
+#define MMAR_DESC_TYPE_ACPI_NVS 4 /* required to save between NVS sessions */
|
||
+
|
||
+#define MMAR_DESC_LENGTH 20
|
||
+
|
||
+/* Fetch the next entry in the memory map and return the continuation
|
||
+ value. DESC is a pointer to the descriptor buffer, and CONT is the
|
||
+ previous continuation value (0 to get the first entry in the
|
||
+ map). */
|
||
+int
|
||
+get_mmap_entry (struct mmar_desc *desc, int cont)
|
||
+{
|
||
+ /* Record the memory map statically. */
|
||
+ static struct mmar_desc desc_table[] =
|
||
+ {
|
||
+ /* The conventional memory. */
|
||
+ {
|
||
+ MMAR_DESC_LENGTH,
|
||
+ 0,
|
||
+ CONVENTIONAL_MEMSIZE,
|
||
+ MMAR_DESC_TYPE_AVAILABLE
|
||
+ },
|
||
+ /* BIOS RAM and ROM (such as video memory). */
|
||
+ {
|
||
+ MMAR_DESC_LENGTH,
|
||
+ CONVENTIONAL_MEMSIZE,
|
||
+ 0x100000 - CONVENTIONAL_MEMSIZE,
|
||
+ MMAR_DESC_TYPE_RESERVED
|
||
+ },
|
||
+ /* The extended memory. */
|
||
+ {
|
||
+ MMAR_DESC_LENGTH,
|
||
+ 0x100000,
|
||
+ EXTENDED_MEMSIZE,
|
||
+ MMAR_DESC_TYPE_AVAILABLE
|
||
+ }
|
||
+ };
|
||
+
|
||
+ int num = sizeof (desc_table) / sizeof (*desc_table);
|
||
+
|
||
+ if (cont < 0 || cont >= num)
|
||
+ {
|
||
+ /* Should not happen. */
|
||
+ desc->desc_len = 0;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Copy the entry. */
|
||
+ *desc = desc_table[cont++];
|
||
+
|
||
+ /* If the next entry exists, return the index. */
|
||
+ if (cont < num)
|
||
+ return cont;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* Track the int13 handler. */
|
||
+void
|
||
+track_int13 (int drive)
|
||
+{
|
||
+ /* Nothing to do in the simulator. */
|
||
+}
|
||
+
|
||
+/* Get the ROM configuration table. */
|
||
+unsigned long
|
||
+get_rom_config_table (void)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* Get APM BIOS information. */
|
||
+void
|
||
+get_apm_info (void)
|
||
+{
|
||
+ /* Nothing to do in the simulator. */
|
||
+}
|
||
+
|
||
+/* Get VBE controller information. */
|
||
+int
|
||
+get_vbe_controller_info (struct vbe_controller *controller)
|
||
+{
|
||
+ /* Always fails. */
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* Get VBE mode information. */
|
||
+int
|
||
+get_vbe_mode_info (int mode_number, struct vbe_mode *mode)
|
||
+{
|
||
+ /* Always fails. */
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* Set VBE mode. */
|
||
+int
|
||
+set_vbe_mode (int mode_number)
|
||
+{
|
||
+ /* Always fails. */
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* low-level timing info */
|
||
+int
|
||
+getrtsecs (void)
|
||
+{
|
||
+ /* FIXME: exact value is not important, so just return time_t for now. */
|
||
+ return time (0);
|
||
+}
|
||
+
|
||
+int
|
||
+currticks (void)
|
||
+{
|
||
+ struct timeval tv;
|
||
+ long csecs;
|
||
+ int ticks_per_csec, ticks_per_usec;
|
||
+
|
||
+ /* Note: 18.2 ticks/sec. */
|
||
+
|
||
+ /* Get current time. */
|
||
+ gettimeofday (&tv, 0);
|
||
+
|
||
+ /* Compute centiseconds. */
|
||
+ csecs = tv.tv_sec / 10;
|
||
+
|
||
+ /* Ticks per centisecond. */
|
||
+ ticks_per_csec = csecs * 182;
|
||
+
|
||
+ /* Ticks per microsecond. */
|
||
+ ticks_per_usec = (((tv.tv_sec - csecs * 10) * 1000000 + tv.tv_usec)
|
||
+ * 182 / 10000000);
|
||
+
|
||
+ /* Sum them. */
|
||
+ return ticks_per_csec + ticks_per_usec;
|
||
+}
|
||
+
|
||
+/* displays an ASCII character. IBM displays will translate some
|
||
+ characters to special graphical ones */
|
||
+void
|
||
+console_putchar (int c)
|
||
+{
|
||
+ /* Curses doesn't have VGA fonts. */
|
||
+ switch (c)
|
||
+ {
|
||
+ case DISP_UL:
|
||
+ c = ACS_ULCORNER;
|
||
+ break;
|
||
+ case DISP_UR:
|
||
+ c = ACS_URCORNER;
|
||
+ break;
|
||
+ case DISP_LL:
|
||
+ c = ACS_LLCORNER;
|
||
+ break;
|
||
+ case DISP_LR:
|
||
+ c = ACS_LRCORNER;
|
||
+ break;
|
||
+ case DISP_HORIZ:
|
||
+ c = ACS_HLINE;
|
||
+ break;
|
||
+ case DISP_VERT:
|
||
+ c = ACS_VLINE;
|
||
+ break;
|
||
+ case DISP_LEFT:
|
||
+ c = ACS_LARROW;
|
||
+ break;
|
||
+ case DISP_RIGHT:
|
||
+ c = ACS_RARROW;
|
||
+ break;
|
||
+ case DISP_UP:
|
||
+ c = ACS_UARROW;
|
||
+ break;
|
||
+ case DISP_DOWN:
|
||
+ c = ACS_DARROW;
|
||
+ break;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+
|
||
+#ifdef HAVE_LIBCURSES
|
||
+ if (use_curses)
|
||
+ {
|
||
+ /* In ncurses, a newline is treated badly, so we emulate it in our
|
||
+ own way. */
|
||
+ if (c == '\n')
|
||
+ {
|
||
+ int x, y;
|
||
+
|
||
+ getyx (stdscr, y, x);
|
||
+ if (y + 1 == LINES)
|
||
+ scroll (stdscr);
|
||
+ else
|
||
+ move (y + 1, x);
|
||
+ }
|
||
+ else if (isprint (c))
|
||
+ {
|
||
+ int x, y;
|
||
+
|
||
+ getyx (stdscr, y, x);
|
||
+ if (x + 1 == COLS)
|
||
+ {
|
||
+ console_putchar ('\r');
|
||
+ console_putchar ('\n');
|
||
+ }
|
||
+ addch (c | console_current_color);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ addch (c);
|
||
+ }
|
||
+
|
||
+#ifdef REFRESH_IMMEDIATELY
|
||
+ refresh ();
|
||
+#endif
|
||
+ }
|
||
+ else
|
||
+#endif
|
||
+ {
|
||
+ /* CR is not used in Unix. */
|
||
+ if (c != '\r')
|
||
+ putchar (c);
|
||
+ }
|
||
+}
|
||
+
|
||
+/* The store for ungetch simulation. This is necessary, because
|
||
+ ncurses-1.9.9g is still used in the world and its ungetch is
|
||
+ completely broken. */
|
||
+#ifdef HAVE_LIBCURSES
|
||
+static int save_char = ERR;
|
||
+#endif
|
||
+
|
||
+static int
|
||
+console_translate_key (int c)
|
||
+{
|
||
+ switch (c)
|
||
+ {
|
||
+ case KEY_LEFT:
|
||
+ return 2;
|
||
+ case KEY_RIGHT:
|
||
+ return 6;
|
||
+ case KEY_UP:
|
||
+ return 16;
|
||
+ case KEY_DOWN:
|
||
+ return 14;
|
||
+ case KEY_DC:
|
||
+ return 4;
|
||
+ case KEY_BACKSPACE:
|
||
+ return 8;
|
||
+ case KEY_HOME:
|
||
+ return 1;
|
||
+ case KEY_END:
|
||
+ return 5;
|
||
+ case KEY_PPAGE:
|
||
+ return 7;
|
||
+ case KEY_NPAGE:
|
||
+ return 3;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ return c;
|
||
+}
|
||
+
|
||
+/* like 'getkey', but doesn't wait, returns -1 if nothing available */
|
||
+int
|
||
+console_checkkey (void)
|
||
+{
|
||
+#ifdef HAVE_LIBCURSES
|
||
+ if (use_curses)
|
||
+ {
|
||
+ int c;
|
||
+
|
||
+ /* Check for SAVE_CHAR. This should not be true, because this
|
||
+ means checkkey is called twice continuously. */
|
||
+ if (save_char != ERR)
|
||
+ return save_char;
|
||
+
|
||
+ c = getch ();
|
||
+ /* If C is not ERR, then put it back in the input queue. */
|
||
+ if (c != ERR)
|
||
+ save_char = c;
|
||
+ return console_translate_key (c);
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ /* Just pretend they hit the space bar, then read the real key when
|
||
+ they call getkey. */
|
||
+ return ' ';
|
||
+}
|
||
+
|
||
+/* returns packed BIOS/ASCII code */
|
||
+int
|
||
+console_getkey (void)
|
||
+{
|
||
+ int c;
|
||
+
|
||
+#ifdef HAVE_LIBCURSES
|
||
+ if (use_curses)
|
||
+ {
|
||
+ /* If checkkey has already got a character, then return it. */
|
||
+ if (save_char != ERR)
|
||
+ {
|
||
+ c = save_char;
|
||
+ save_char = ERR;
|
||
+ return console_translate_key (c);
|
||
+ }
|
||
+
|
||
+ wtimeout (stdscr, -1);
|
||
+ c = getch ();
|
||
+ wtimeout (stdscr, 100);
|
||
+ }
|
||
+ else
|
||
+#endif
|
||
+ c = getchar ();
|
||
+
|
||
+ /* Quit if we get EOF. */
|
||
+ if (c == -1)
|
||
+ stop ();
|
||
+
|
||
+ return console_translate_key (c);
|
||
+}
|
||
+
|
||
+/* returns packed values, LSB+1 is x, LSB is y */
|
||
+int
|
||
+console_getxy (void)
|
||
+{
|
||
+ int y, x;
|
||
+#ifdef HAVE_LIBCURSES
|
||
+ if (use_curses)
|
||
+ getyx (stdscr, y, x);
|
||
+ else
|
||
+#endif
|
||
+ y = x = 0;
|
||
+ return (x << 8) | (y & 0xff);
|
||
+}
|
||
+
|
||
+void
|
||
+console_gotoxy (int x, int y)
|
||
+{
|
||
+#ifdef HAVE_LIBCURSES
|
||
+ if (use_curses)
|
||
+ move (y, x);
|
||
+#endif
|
||
+}
|
||
+
|
||
+/* low-level character I/O */
|
||
+void
|
||
+console_cls (void)
|
||
+{
|
||
+#ifdef HAVE_LIBCURSES
|
||
+ if (use_curses)
|
||
+ clear ();
|
||
+#endif
|
||
+}
|
||
+
|
||
+void
|
||
+console_setcolorstate (color_state state)
|
||
+{
|
||
+ console_current_color =
|
||
+ (state == COLOR_STATE_HIGHLIGHT) ? A_REVERSE : A_NORMAL;
|
||
+}
|
||
+
|
||
+void
|
||
+console_setcolor (int normal_color, int highlight_color)
|
||
+{
|
||
+ /* Nothing to do. */
|
||
+}
|
||
+
|
||
+int
|
||
+console_setcursor (int on)
|
||
+{
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+/* Low-level disk I/O. Our stubbed version just returns a file
|
||
+ descriptor, not the actual geometry. */
|
||
+int
|
||
+get_diskinfo (int drive, struct geometry *geometry)
|
||
+{
|
||
+ /* FIXME: this function is truly horrid. We try opening the device,
|
||
+ then severely abuse the GEOMETRY->flags field to pass a file
|
||
+ descriptor to biosdisk. Thank God nobody's looking at this comment,
|
||
+ or my reputation would be ruined. --Gord */
|
||
+
|
||
+ /* See if we have a cached device. */
|
||
+ if (disks[drive].flags == -1)
|
||
+ {
|
||
+ /* The unpartitioned device name: /dev/XdX */
|
||
+ char *devname = device_map[drive];
|
||
+ char buf[512];
|
||
+
|
||
+ if (! devname)
|
||
+ return -1;
|
||
+
|
||
+ if (verbose)
|
||
+ grub_printf ("Attempt to open drive 0x%x (%s)\n",
|
||
+ drive, devname);
|
||
+
|
||
+ /* Open read/write, or read-only if that failed. */
|
||
+ if (! read_only)
|
||
+ disks[drive].flags = open (devname, O_RDWR);
|
||
+
|
||
+ if (disks[drive].flags == -1)
|
||
+ {
|
||
+ if (read_only || errno == EACCES || errno == EROFS || errno == EPERM)
|
||
+ {
|
||
+ disks[drive].flags = open (devname, O_RDONLY);
|
||
+ if (disks[drive].flags == -1)
|
||
+ {
|
||
+ assign_device_name (drive, 0);
|
||
+ return -1;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ assign_device_name (drive, 0);
|
||
+ return -1;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Attempt to read the first sector. */
|
||
+ if (read (disks[drive].flags, buf, 512) != 512)
|
||
+ {
|
||
+ close (disks[drive].flags);
|
||
+ disks[drive].flags = -1;
|
||
+ assign_device_name (drive, 0);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ if (disks[drive].flags != -1)
|
||
+ get_drive_geometry (&disks[drive], device_map, drive);
|
||
+ }
|
||
+
|
||
+ if (disks[drive].flags == -1)
|
||
+ return -1;
|
||
+
|
||
+#ifdef __linux__
|
||
+ /* In Linux, invalidate the buffer cache, so that left overs
|
||
+ from other program in the cache are flushed and seen by us */
|
||
+ ioctl (disks[drive].flags, BLKFLSBUF, 0);
|
||
+#endif
|
||
+
|
||
+ *geometry = disks[drive];
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
|
||
+ error occurs, otherwise return LEN. */
|
||
+static int
|
||
+nread (int fd, char *buf, size_t len)
|
||
+{
|
||
+ int size = len;
|
||
+
|
||
+ while (len)
|
||
+ {
|
||
+ int ret = read (fd, buf, len);
|
||
+
|
||
+ if (ret <= 0)
|
||
+ {
|
||
+ if (errno == EINTR)
|
||
+ continue;
|
||
+ else
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ len -= ret;
|
||
+ buf += ret;
|
||
+ }
|
||
+
|
||
+ return size;
|
||
+}
|
||
+
|
||
+/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
|
||
+ error occurs, otherwise return LEN. */
|
||
+static int
|
||
+nwrite (int fd, char *buf, size_t len)
|
||
+{
|
||
+ int size = len;
|
||
+
|
||
+ while (len)
|
||
+ {
|
||
+ int ret = write (fd, buf, len);
|
||
+
|
||
+ if (ret <= 0)
|
||
+ {
|
||
+ if (errno == EINTR)
|
||
+ continue;
|
||
+ else
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ len -= ret;
|
||
+ buf += ret;
|
||
+ }
|
||
+
|
||
+ return size;
|
||
+}
|
||
+
|
||
+/* Dump BUF in the format of hexadecimal numbers. */
|
||
+static void
|
||
+hex_dump (void *buf, size_t size)
|
||
+{
|
||
+ /* FIXME: How to determine which length is readable? */
|
||
+#define MAX_COLUMN 70
|
||
+
|
||
+ /* use unsigned char for numerical computations */
|
||
+ unsigned char *ptr = buf;
|
||
+ /* count the width of the line */
|
||
+ int column = 0;
|
||
+ /* how many bytes written */
|
||
+ int count = 0;
|
||
+
|
||
+ while (size > 0)
|
||
+ {
|
||
+ /* high 4 bits */
|
||
+ int hi = *ptr >> 4;
|
||
+ /* low 4 bits */
|
||
+ int low = *ptr & 0xf;
|
||
+
|
||
+ /* grub_printf does not handle prefix number, such as %2x, so
|
||
+ format the number by hand... */
|
||
+ grub_printf ("%x%x", hi, low);
|
||
+ column += 2;
|
||
+ count++;
|
||
+ ptr++;
|
||
+ size--;
|
||
+
|
||
+ /* Insert space or newline with the interval 4 bytes. */
|
||
+ if (size != 0 && (count % 4) == 0)
|
||
+ {
|
||
+ if (column < MAX_COLUMN)
|
||
+ {
|
||
+ grub_printf (" ");
|
||
+ column++;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ grub_printf ("\n");
|
||
+ column = 0;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Add a newline at the end for readability. */
|
||
+ grub_printf ("\n");
|
||
+}
|
||
+
|
||
+int
|
||
+biosdisk (int subfunc, int drive, struct geometry *geometry,
|
||
+ int sector, int nsec, int segment)
|
||
+{
|
||
+ char *buf;
|
||
+ int fd = geometry->flags;
|
||
+
|
||
+ /* Get the file pointer from the geometry, and make sure it matches. */
|
||
+ if (fd == -1 || fd != disks[drive].flags)
|
||
+ return BIOSDISK_ERROR_GEOMETRY;
|
||
+
|
||
+ /* Seek to the specified location. */
|
||
+#if defined(__linux__) && (!defined(__GLIBC__) || \
|
||
+ ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
|
||
+ /* Maybe libc doesn't have large file support. */
|
||
+ {
|
||
+ loff_t offset, result;
|
||
+ static int _llseek (uint filedes, ulong hi, ulong lo,
|
||
+ loff_t *res, uint wh);
|
||
+ _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
|
||
+ loff_t *, res, uint, wh);
|
||
+
|
||
+ offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
|
||
+ if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
|
||
+ return -1;
|
||
+ }
|
||
+#else
|
||
+ {
|
||
+ off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
|
||
+
|
||
+ if (lseek (fd, offset, SEEK_SET) != offset)
|
||
+ return -1;
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ buf = (char *) (segment << 4);
|
||
+
|
||
+ switch (subfunc)
|
||
+ {
|
||
+ case BIOSDISK_READ:
|
||
+#ifdef __linux__
|
||
+ if (sector == 0 && nsec > 1)
|
||
+ {
|
||
+ /* Work around a bug in linux's ez remapping. Linux remaps all
|
||
+ sectors that are read together with the MBR in one read. It
|
||
+ should only remap the MBR, so we split the read in two
|
||
+ parts. -jochen */
|
||
+ if (nread (fd, buf, SECTOR_SIZE) != SECTOR_SIZE)
|
||
+ return -1;
|
||
+ buf += SECTOR_SIZE;
|
||
+ nsec--;
|
||
+ }
|
||
+#endif
|
||
+ if (nread (fd, buf, nsec * SECTOR_SIZE) != nsec * SECTOR_SIZE)
|
||
+ return -1;
|
||
+ break;
|
||
+
|
||
+ case BIOSDISK_WRITE:
|
||
+ if (verbose)
|
||
+ {
|
||
+ grub_printf ("Write %d sectors starting from %d sector"
|
||
+ " to drive 0x%x (%s)\n",
|
||
+ nsec, sector, drive, device_map[drive]);
|
||
+ hex_dump (buf, nsec * SECTOR_SIZE);
|
||
+ }
|
||
+ if (! read_only)
|
||
+ if (nwrite (fd, buf, nsec * SECTOR_SIZE) != nsec * SECTOR_SIZE)
|
||
+ return -1;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ grub_printf ("unknown subfunc %d\n", subfunc);
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+void
|
||
+stop_floppy (void)
|
||
+{
|
||
+ /* NOTUSED */
|
||
+}
|
||
+
|
||
+/* Fetch a key from a serial device. */
|
||
+int
|
||
+serial_hw_fetch (void)
|
||
+{
|
||
+ fd_set fds;
|
||
+ struct timeval to;
|
||
+ char c;
|
||
+
|
||
+ /* Wait only for the serial device. */
|
||
+ FD_ZERO (&fds);
|
||
+ FD_SET (serial_fd, &fds);
|
||
+
|
||
+ to.tv_sec = 0;
|
||
+ to.tv_usec = 0;
|
||
+
|
||
+ if (select (serial_fd + 1, &fds, 0, 0, &to) > 0)
|
||
+ {
|
||
+ if (nread (serial_fd, &c, 1) != 1)
|
||
+ stop ();
|
||
+
|
||
+ return c;
|
||
+ }
|
||
+
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+/* Put a character to a serial device. */
|
||
+void
|
||
+serial_hw_put (int c)
|
||
+{
|
||
+ char ch = (char) c;
|
||
+
|
||
+ if (nwrite (serial_fd, &ch, 1) != 1)
|
||
+ stop ();
|
||
+}
|
||
+
|
||
+void
|
||
+serial_hw_delay (void)
|
||
+{
|
||
+#ifdef SIMULATE_SLOWNESS_OF_SERIAL
|
||
+ struct timeval otv, tv;
|
||
+
|
||
+ gettimeofday (&otv, 0);
|
||
+
|
||
+ while (1)
|
||
+ {
|
||
+ long delta;
|
||
+
|
||
+ gettimeofday (&tv, 0);
|
||
+ delta = tv.tv_usec - otv.tv_usec;
|
||
+ if (delta < 0)
|
||
+ delta += 1000000;
|
||
+
|
||
+ if (delta >= 1000000 / (serial_speed >> 3))
|
||
+ break;
|
||
+ }
|
||
+#endif /* SIMULATE_SLOWNESS_OF_SERIAL */
|
||
+}
|
||
+
|
||
+static speed_t
|
||
+get_termios_speed (int speed)
|
||
+{
|
||
+ switch (speed)
|
||
+ {
|
||
+ case 2400: return B2400;
|
||
+ case 4800: return B4800;
|
||
+ case 9600: return B9600;
|
||
+ case 19200: return B19200;
|
||
+ case 38400: return B38400;
|
||
+#ifdef B57600
|
||
+ case 57600: return B57600;
|
||
+#endif
|
||
+#ifdef B115200
|
||
+ case 115200: return B115200;
|
||
+#endif
|
||
+ }
|
||
+
|
||
+ return B0;
|
||
+}
|
||
+
|
||
+/* Get the port number of the unit UNIT. In the grub shell, this doesn't
|
||
+ make sense. */
|
||
+unsigned short
|
||
+serial_hw_get_port (int unit)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* Initialize a serial device. In the grub shell, PORT is unused. */
|
||
+int
|
||
+serial_hw_init (unsigned short port, unsigned int speed,
|
||
+ int word_len, int parity, int stop_bit_len)
|
||
+{
|
||
+ struct termios termios;
|
||
+ speed_t termios_speed;
|
||
+ int i;
|
||
+
|
||
+ /* Check if the file name is specified. */
|
||
+ if (! serial_device)
|
||
+ return 0;
|
||
+
|
||
+ /* If a serial device is already opened, close it first. */
|
||
+ if (serial_fd >= 0)
|
||
+ close (serial_fd);
|
||
+
|
||
+ /* Open the device file. */
|
||
+ serial_fd = open (serial_device,
|
||
+ O_RDWR | O_NOCTTY
|
||
+#if defined(O_SYNC)
|
||
+ /* O_SYNC is used in Linux (and some others?). */
|
||
+ | O_SYNC
|
||
+#elif defined(O_FSYNC)
|
||
+ /* O_FSYNC is used in FreeBSD. */
|
||
+ | O_FSYNC
|
||
+#endif
|
||
+ );
|
||
+ if (serial_fd < 0)
|
||
+ return 0;
|
||
+
|
||
+ /* Get the termios parameters. */
|
||
+ if (tcgetattr (serial_fd, &termios))
|
||
+ goto fail;
|
||
+
|
||
+ /* Raw mode. */
|
||
+ cfmakeraw (&termios);
|
||
+
|
||
+ /* Set the speed. */
|
||
+ termios_speed = get_termios_speed (speed);
|
||
+ if (termios_speed == B0)
|
||
+ goto fail;
|
||
+
|
||
+ cfsetispeed (&termios, termios_speed);
|
||
+ cfsetospeed (&termios, termios_speed);
|
||
+
|
||
+ /* Set the word length. */
|
||
+ termios.c_cflag &= ~CSIZE;
|
||
+ switch (word_len)
|
||
+ {
|
||
+ case UART_5BITS_WORD:
|
||
+ termios.c_cflag |= CS5;
|
||
+ break;
|
||
+ case UART_6BITS_WORD:
|
||
+ termios.c_cflag |= CS6;
|
||
+ break;
|
||
+ case UART_7BITS_WORD:
|
||
+ termios.c_cflag |= CS7;
|
||
+ break;
|
||
+ case UART_8BITS_WORD:
|
||
+ termios.c_cflag |= CS8;
|
||
+ break;
|
||
+ default:
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* Set the parity. */
|
||
+ switch (parity)
|
||
+ {
|
||
+ case UART_NO_PARITY:
|
||
+ termios.c_cflag &= ~PARENB;
|
||
+ break;
|
||
+ case UART_ODD_PARITY:
|
||
+ termios.c_cflag |= PARENB;
|
||
+ termios.c_cflag |= PARODD;
|
||
+ break;
|
||
+ case UART_EVEN_PARITY:
|
||
+ termios.c_cflag |= PARENB;
|
||
+ termios.c_cflag &= ~PARODD;
|
||
+ break;
|
||
+ default:
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* Set the length of stop bit. */
|
||
+ switch (stop_bit_len)
|
||
+ {
|
||
+ case UART_1_STOP_BIT:
|
||
+ termios.c_cflag &= ~CSTOPB;
|
||
+ break;
|
||
+ case UART_2_STOP_BITS:
|
||
+ termios.c_cflag |= CSTOPB;
|
||
+ break;
|
||
+ default:
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* Set the parameters. */
|
||
+ if (tcsetattr (serial_fd, TCSANOW, &termios))
|
||
+ goto fail;
|
||
+
|
||
+#ifdef SIMULATE_SLOWNESS_OF_SERIAL
|
||
+ serial_speed = speed;
|
||
+#endif /* SIMUATE_SLOWNESS_OF_SERIAL */
|
||
+
|
||
+ /* Get rid of the flag TERM_NEED_INIT from the serial terminal. */
|
||
+ for (i = 0; term_table[i].name; i++)
|
||
+ {
|
||
+ if (strcmp (term_table[i].name, "serial") == 0)
|
||
+ {
|
||
+ term_table[i].flags &= ~(TERM_NEED_INIT);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return 1;
|
||
+
|
||
+ fail:
|
||
+ close (serial_fd);
|
||
+ serial_fd = -1;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* Set the file name of a serial device (or a pty device). This is a
|
||
+ function specific to the grub shell. */
|
||
+void
|
||
+serial_set_device (const char *device)
|
||
+{
|
||
+ if (serial_device)
|
||
+ free (serial_device);
|
||
+
|
||
+ serial_device = strdup (device);
|
||
+}
|
||
+
|
||
+/* There is no difference between console and hercules in the grub shell. */
|
||
+void
|
||
+hercules_putchar (int c)
|
||
+{
|
||
+ console_putchar (c);
|
||
+}
|
||
+
|
||
+int
|
||
+hercules_getxy (void)
|
||
+{
|
||
+ return console_getxy ();
|
||
+}
|
||
+
|
||
+void
|
||
+hercules_gotoxy (int x, int y)
|
||
+{
|
||
+ console_gotoxy (x, y);
|
||
+}
|
||
+
|
||
+void
|
||
+hercules_cls (void)
|
||
+{
|
||
+ console_cls ();
|
||
+}
|
||
+
|
||
+void
|
||
+hercules_setcolorstate (color_state state)
|
||
+{
|
||
+ console_setcolorstate (state);
|
||
+}
|
||
+
|
||
+void
|
||
+hercules_setcolor (int normal_color, int highlight_color)
|
||
+{
|
||
+ console_setcolor (normal_color, highlight_color);
|
||
+}
|
||
+
|
||
+int
|
||
+hercules_setcursor (int on)
|
||
+{
|
||
+ return 1;
|
||
+}
|
||
diff -Nur grub-0.97/grub/main.c grub-0.97-patched/grub/main.c
|
||
--- grub-0.97/grub/main.c 2003-07-09 13:45:36.000000000 +0200
|
||
+++ grub-0.97-patched/grub/main.c 2012-11-11 17:07:12.720729374 +0100
|
||
@@ -32,6 +32,7 @@
|
||
#define WITHOUT_LIBC_STUBS 1
|
||
#include <shared.h>
|
||
#include <term.h>
|
||
+#include <device.h>
|
||
|
||
char *program_name = 0;
|
||
int use_config_file = 1;
|
||
@@ -140,10 +141,7 @@
|
||
program_name = argv[0];
|
||
default_boot_drive = boot_drive;
|
||
default_install_partition = install_partition;
|
||
- if (config_file)
|
||
- default_config_file = config_file;
|
||
- else
|
||
- default_config_file = "NONE";
|
||
+ default_config_file = config_file;
|
||
|
||
/* Parse command-line options. */
|
||
do
|
||
@@ -192,6 +190,12 @@
|
||
perror ("strtoul");
|
||
exit (1);
|
||
}
|
||
+ if (boot_drive >= NUM_DISKS)
|
||
+ {
|
||
+ fprintf (stderr, "boot_drive should be from 0 to %d\n",
|
||
+ NUM_DISKS - 1);
|
||
+ exit (1);
|
||
+ }
|
||
break;
|
||
|
||
case OPT_NO_CONFIG_FILE:
|
||
diff -Nur grub-0.97/grub/main.c.orig grub-0.97-patched/grub/main.c.orig
|
||
--- grub-0.97/grub/main.c.orig 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/grub/main.c.orig 2003-07-09 13:45:36.000000000 +0200
|
||
@@ -0,0 +1,265 @@
|
||
+/* main.c - experimental GRUB stage2 that runs under Unix */
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc.
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License as published by
|
||
+ * the Free Software Foundation; either version 2 of the License, or
|
||
+ * (at your option) any later version.
|
||
+ *
|
||
+ * This program is distributed in the hope that it will be useful,
|
||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ * GNU General Public License for more details.
|
||
+ *
|
||
+ * You should have received a copy of the GNU General Public License
|
||
+ * along with this program; if not, write to the Free Software
|
||
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
+ */
|
||
+
|
||
+/* Simulator entry point. */
|
||
+int grub_stage2 (void);
|
||
+
|
||
+#include <stdio.h>
|
||
+#include <getopt.h>
|
||
+#include <unistd.h>
|
||
+#include <string.h>
|
||
+#include <stdlib.h>
|
||
+#include <limits.h>
|
||
+#include <setjmp.h>
|
||
+
|
||
+#define WITHOUT_LIBC_STUBS 1
|
||
+#include <shared.h>
|
||
+#include <term.h>
|
||
+
|
||
+char *program_name = 0;
|
||
+int use_config_file = 1;
|
||
+int use_preset_menu = 0;
|
||
+#ifdef HAVE_LIBCURSES
|
||
+int use_curses = 1;
|
||
+#else
|
||
+int use_curses = 0;
|
||
+#endif
|
||
+int verbose = 0;
|
||
+int read_only = 0;
|
||
+int floppy_disks = 1;
|
||
+char *device_map_file = 0;
|
||
+static int default_boot_drive;
|
||
+static int default_install_partition;
|
||
+static char *default_config_file;
|
||
+
|
||
+#define OPT_HELP -2
|
||
+#define OPT_VERSION -3
|
||
+#define OPT_HOLD -4
|
||
+#define OPT_CONFIG_FILE -5
|
||
+#define OPT_INSTALL_PARTITION -6
|
||
+#define OPT_BOOT_DRIVE -7
|
||
+#define OPT_NO_CONFIG_FILE -8
|
||
+#define OPT_NO_CURSES -9
|
||
+#define OPT_BATCH -10
|
||
+#define OPT_VERBOSE -11
|
||
+#define OPT_READ_ONLY -12
|
||
+#define OPT_PROBE_SECOND_FLOPPY -13
|
||
+#define OPT_NO_FLOPPY -14
|
||
+#define OPT_DEVICE_MAP -15
|
||
+#define OPT_PRESET_MENU -16
|
||
+#define OPT_NO_PAGER -17
|
||
+#define OPTSTRING ""
|
||
+
|
||
+static struct option longopts[] =
|
||
+{
|
||
+ {"batch", no_argument, 0, OPT_BATCH},
|
||
+ {"boot-drive", required_argument, 0, OPT_BOOT_DRIVE},
|
||
+ {"config-file", required_argument, 0, OPT_CONFIG_FILE},
|
||
+ {"device-map", required_argument, 0, OPT_DEVICE_MAP},
|
||
+ {"help", no_argument, 0, OPT_HELP},
|
||
+ {"hold", optional_argument, 0, OPT_HOLD},
|
||
+ {"install-partition", required_argument, 0, OPT_INSTALL_PARTITION},
|
||
+ {"no-config-file", no_argument, 0, OPT_NO_CONFIG_FILE},
|
||
+ {"no-curses", no_argument, 0, OPT_NO_CURSES},
|
||
+ {"no-floppy", no_argument, 0, OPT_NO_FLOPPY},
|
||
+ {"no-pager", no_argument, 0, OPT_NO_PAGER},
|
||
+ {"preset-menu", no_argument, 0, OPT_PRESET_MENU},
|
||
+ {"probe-second-floppy", no_argument, 0, OPT_PROBE_SECOND_FLOPPY},
|
||
+ {"read-only", no_argument, 0, OPT_READ_ONLY},
|
||
+ {"verbose", no_argument, 0, OPT_VERBOSE},
|
||
+ {"version", no_argument, 0, OPT_VERSION},
|
||
+ {0},
|
||
+};
|
||
+
|
||
+
|
||
+static void
|
||
+usage (int status)
|
||
+{
|
||
+ if (status)
|
||
+ fprintf (stderr, "Try ``grub --help'' for more information.\n");
|
||
+ else
|
||
+ printf ("\
|
||
+Usage: grub [OPTION]...\n\
|
||
+\n\
|
||
+Enter the GRand Unified Bootloader command shell.\n\
|
||
+\n\
|
||
+ --batch turn on batch mode for non-interactive use\n\
|
||
+ --boot-drive=DRIVE specify stage2 boot_drive [default=0x%x]\n\
|
||
+ --config-file=FILE specify stage2 config_file [default=%s]\n\
|
||
+ --device-map=FILE use the device map file FILE\n\
|
||
+ --help display this message and exit\n\
|
||
+ --hold wait until a debugger will attach\n\
|
||
+ --install-partition=PAR specify stage2 install_partition [default=0x%x]\n\
|
||
+ --no-config-file do not use the config file\n\
|
||
+ --no-curses do not use curses\n\
|
||
+ --no-floppy do not probe any floppy drive\n\
|
||
+ --no-pager do not use internal pager\n\
|
||
+ --preset-menu use the preset menu\n\
|
||
+ --probe-second-floppy probe the second floppy drive\n\
|
||
+ --read-only do not write anything to devices\n\
|
||
+ --verbose print verbose messages\n\
|
||
+ --version print version information and exit\n\
|
||
+\n\
|
||
+Report bugs to <bug-grub@gnu.org>.\n\
|
||
+",
|
||
+ default_boot_drive, default_config_file,
|
||
+ default_install_partition);
|
||
+
|
||
+ exit (status);
|
||
+}
|
||
+
|
||
+
|
||
+int
|
||
+main (int argc, char **argv)
|
||
+{
|
||
+ int c;
|
||
+ int hold = 0;
|
||
+
|
||
+ /* First of all, call sync so that all in-core data is scheduled to be
|
||
+ actually written to disks. This is very important because GRUB does
|
||
+ not use ordinary stdio interface but raw devices. */
|
||
+ sync ();
|
||
+
|
||
+ program_name = argv[0];
|
||
+ default_boot_drive = boot_drive;
|
||
+ default_install_partition = install_partition;
|
||
+ if (config_file)
|
||
+ default_config_file = config_file;
|
||
+ else
|
||
+ default_config_file = "NONE";
|
||
+
|
||
+ /* Parse command-line options. */
|
||
+ do
|
||
+ {
|
||
+ c = getopt_long (argc, argv, OPTSTRING, longopts, 0);
|
||
+ switch (c)
|
||
+ {
|
||
+ case EOF:
|
||
+ /* Fall through the bottom of the loop. */
|
||
+ break;
|
||
+
|
||
+ case OPT_HELP:
|
||
+ usage (0);
|
||
+ break;
|
||
+
|
||
+ case OPT_VERSION:
|
||
+ printf ("grub (GNU GRUB " VERSION ")\n");
|
||
+ exit (0);
|
||
+ break;
|
||
+
|
||
+ case OPT_HOLD:
|
||
+ if (! optarg)
|
||
+ hold = -1;
|
||
+ else
|
||
+ hold = atoi (optarg);
|
||
+ break;
|
||
+
|
||
+ case OPT_CONFIG_FILE:
|
||
+ strncpy (config_file, optarg, 127); /* FIXME: arbitrary */
|
||
+ config_file[127] = '\0';
|
||
+ break;
|
||
+
|
||
+ case OPT_INSTALL_PARTITION:
|
||
+ install_partition = strtoul (optarg, 0, 0);
|
||
+ if (install_partition == ULONG_MAX)
|
||
+ {
|
||
+ perror ("strtoul");
|
||
+ exit (1);
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case OPT_BOOT_DRIVE:
|
||
+ boot_drive = strtoul (optarg, 0, 0);
|
||
+ if (boot_drive == ULONG_MAX)
|
||
+ {
|
||
+ perror ("strtoul");
|
||
+ exit (1);
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case OPT_NO_CONFIG_FILE:
|
||
+ use_config_file = 0;
|
||
+ break;
|
||
+
|
||
+ case OPT_NO_CURSES:
|
||
+ use_curses = 0;
|
||
+ break;
|
||
+
|
||
+ case OPT_NO_PAGER:
|
||
+ use_pager = 0;
|
||
+ break;
|
||
+
|
||
+ case OPT_BATCH:
|
||
+ /* This is the same as "--no-config-file --no-curses --no-pager". */
|
||
+ use_config_file = 0;
|
||
+ use_curses = 0;
|
||
+ use_pager = 0;
|
||
+ break;
|
||
+
|
||
+ case OPT_READ_ONLY:
|
||
+ read_only = 1;
|
||
+ break;
|
||
+
|
||
+ case OPT_VERBOSE:
|
||
+ verbose = 1;
|
||
+ break;
|
||
+
|
||
+ case OPT_NO_FLOPPY:
|
||
+ floppy_disks = 0;
|
||
+ break;
|
||
+
|
||
+ case OPT_PROBE_SECOND_FLOPPY:
|
||
+ floppy_disks = 2;
|
||
+ break;
|
||
+
|
||
+ case OPT_DEVICE_MAP:
|
||
+ device_map_file = strdup (optarg);
|
||
+ break;
|
||
+
|
||
+ case OPT_PRESET_MENU:
|
||
+ use_preset_menu = 1;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ usage (1);
|
||
+ }
|
||
+ }
|
||
+ while (c != EOF);
|
||
+
|
||
+ /* Wait until the HOLD variable is cleared by an attached debugger. */
|
||
+ if (hold && verbose)
|
||
+ printf ("Run \"gdb %s %d\", and set HOLD to zero.\n",
|
||
+ program_name, (int) getpid ());
|
||
+ while (hold)
|
||
+ {
|
||
+ if (hold > 0)
|
||
+ hold--;
|
||
+
|
||
+ sleep (1);
|
||
+ }
|
||
+
|
||
+ /* If we don't have curses (!HAVE_LIBCURSES or --no-curses or
|
||
+ --batch) put terminal to dumb for better handling of line i/o */
|
||
+ if (! use_curses)
|
||
+ current_term->flags = TERM_NO_EDIT | TERM_DUMB;
|
||
+
|
||
+ /* Transfer control to the stage2 simulator. */
|
||
+ exit (grub_stage2 ());
|
||
+}
|
||
diff -Nur grub-0.97/lib/device.c grub-0.97-patched/lib/device.c
|
||
--- grub-0.97/lib/device.c 2005-03-28 01:14:25.000000000 +0200
|
||
+++ grub-0.97-patched/lib/device.c 2012-11-11 17:07:12.748730268 +0100
|
||
@@ -69,9 +69,9 @@
|
||
# ifndef CDROM_GET_CAPABILITY
|
||
# define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
|
||
# endif /* ! CDROM_GET_CAPABILITY */
|
||
-# ifndef BLKGETSIZE
|
||
-# define BLKGETSIZE _IO(0x12,96) /* return device size */
|
||
-# endif /* ! BLKGETSIZE */
|
||
+# ifndef BLKGETSIZE64
|
||
+# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
|
||
+# endif /* ! BLKGETSIZE64 */
|
||
#endif /* __linux__ */
|
||
|
||
/* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
|
||
@@ -131,6 +131,152 @@
|
||
#include <shared.h>
|
||
#include <device.h>
|
||
|
||
+#if defined(__linux__)
|
||
+/* The 2.6 kernel has removed all of the geometry handling for IDE drives
|
||
+ * that did fixups for LBA, etc. This means that the geometry we get
|
||
+ * with the ioctl has a good chance of being wrong. So, we get to
|
||
+ * also know about partition tables and try to read what the geometry
|
||
+ * is there. *grumble* Very closely based on code from cfdisk
|
||
+ */
|
||
+static void get_kernel_geometry(int fd, long long *cyl, int *heads, int *sectors) {
|
||
+ struct hd_geometry hdg;
|
||
+
|
||
+ if (ioctl (fd, HDIO_GETGEO, &hdg))
|
||
+ return;
|
||
+
|
||
+ *cyl = hdg.cylinders;
|
||
+ *heads = hdg.heads;
|
||
+ *sectors = hdg.sectors;
|
||
+}
|
||
+
|
||
+struct partition {
|
||
+ unsigned char boot_ind; /* 0x80 - active */
|
||
+ unsigned char head; /* starting head */
|
||
+ unsigned char sector; /* starting sector */
|
||
+ unsigned char cyl; /* starting cylinder */
|
||
+ unsigned char sys_ind; /* What partition type */
|
||
+ unsigned char end_head; /* end head */
|
||
+ unsigned char end_sector; /* end sector */
|
||
+ unsigned char end_cyl; /* end cylinder */
|
||
+ unsigned char start4[4]; /* starting sector counting from 0 */
|
||
+ unsigned char size4[4]; /* nr of sectors in partition */
|
||
+};
|
||
+
|
||
+#define ALIGNMENT 2
|
||
+typedef union {
|
||
+ struct {
|
||
+ unsigned char align[ALIGNMENT];
|
||
+ unsigned char b[SECTOR_SIZE];
|
||
+ } c;
|
||
+ struct {
|
||
+ unsigned char align[ALIGNMENT];
|
||
+ unsigned char buffer[0x1BE];
|
||
+ struct partition part[4];
|
||
+ unsigned char magicflag[2];
|
||
+ } p;
|
||
+} partition_table;
|
||
+
|
||
+#define PART_TABLE_FLAG0 0x55
|
||
+#define PART_TABLE_FLAG1 0xAA
|
||
+
|
||
+static void
|
||
+get_partition_table_geometry(partition_table *bufp, long long *cyl, int *heads,
|
||
+ int *sectors) {
|
||
+ struct partition *p;
|
||
+ int i,h,s,hh,ss;
|
||
+ int first = 1;
|
||
+ int bad = 0;
|
||
+
|
||
+ if (bufp->p.magicflag[0] != PART_TABLE_FLAG0 ||
|
||
+ bufp->p.magicflag[1] != PART_TABLE_FLAG1) {
|
||
+ /* Matthew Wilcox: slightly friendlier version of
|
||
+ fatal(_("Bad signature on partition table"), 3);
|
||
+ */
|
||
+ fprintf(stderr, "Unknown partition table signature\n");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ hh = ss = 0;
|
||
+ for (i=0; i<4; i++) {
|
||
+ p = &(bufp->p.part[i]);
|
||
+ if (p->sys_ind != 0) {
|
||
+ h = p->end_head + 1;
|
||
+ s = (p->end_sector & 077);
|
||
+ if (first) {
|
||
+ hh = h;
|
||
+ ss = s;
|
||
+ first = 0;
|
||
+ } else if (hh != h || ss != s)
|
||
+ bad = 1;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (!first && !bad) {
|
||
+ *heads = hh;
|
||
+ *sectors = ss;
|
||
+ }
|
||
+}
|
||
+
|
||
+static long long my_lseek (unsigned int fd, long long offset,
|
||
+ unsigned int origin)
|
||
+{
|
||
+#if defined(__linux__) && (!defined(__GLIBC__) || \
|
||
+ ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
|
||
+ /* Maybe libc doesn't have large file support. */
|
||
+ loff_t offset, result;
|
||
+ static int _llseek (uint filedes, ulong hi, ulong lo,
|
||
+ loff_t *res, uint wh);
|
||
+ _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
|
||
+ loff_t *, res, uint, wh);
|
||
+
|
||
+ if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET) < 0)
|
||
+ return (long long) -1;
|
||
+ return result;
|
||
+#else
|
||
+ return lseek(fd, offset, SEEK_SET);
|
||
+#endif
|
||
+}
|
||
+
|
||
+static void get_linux_geometry (int fd, struct geometry *geom) {
|
||
+ long long kern_cyl = 0; int kern_head = 0, kern_sectors = 0;
|
||
+ long long pt_cyl = 0; int pt_head = 0, pt_sectors = 0;
|
||
+ partition_table bufp;
|
||
+ char *buff, *buf_unaligned;
|
||
+
|
||
+ buf_unaligned = malloc(sizeof(partition_table) + 4095);
|
||
+ buff = (char *) (((unsigned long)buf_unaligned + 4096 - 1) &
|
||
+ (~(4096-1)));
|
||
+
|
||
+ get_kernel_geometry(fd, &kern_cyl, &kern_head, &kern_sectors);
|
||
+
|
||
+ if (my_lseek (fd, 0*SECTOR_SIZE, SEEK_SET) < 0) {
|
||
+ fprintf(stderr, "Unable to seek");
|
||
+ }
|
||
+
|
||
+ if (read(fd, buff, SECTOR_SIZE) == SECTOR_SIZE) {
|
||
+ memcpy(bufp.c.b, buff, SECTOR_SIZE);
|
||
+ get_partition_table_geometry(&bufp, &pt_cyl, &pt_head, &pt_sectors);
|
||
+ } else {
|
||
+ fprintf(stderr, "Unable to read partition table: %s\n", strerror(errno));
|
||
+ }
|
||
+
|
||
+ if (pt_head && pt_sectors) {
|
||
+ int cyl_size;
|
||
+
|
||
+ geom->heads = pt_head;
|
||
+ geom->sectors = pt_sectors;
|
||
+ cyl_size = pt_head * pt_sectors;
|
||
+ geom->cylinders = geom->total_sectors/cyl_size;
|
||
+ } else {
|
||
+ geom->heads = kern_head;
|
||
+ geom->sectors = kern_sectors;
|
||
+ geom->cylinders = kern_cyl;
|
||
+ }
|
||
+
|
||
+ return;
|
||
+}
|
||
+#endif
|
||
+
|
||
/* Get the geometry of a drive DRIVE. */
|
||
void
|
||
get_drive_geometry (struct geometry *geom, char **map, int drive)
|
||
@@ -151,20 +297,16 @@
|
||
#if defined(__linux__)
|
||
/* Linux */
|
||
{
|
||
- struct hd_geometry hdg;
|
||
- unsigned long nr;
|
||
+ unsigned long long nr;
|
||
|
||
- if (ioctl (fd, HDIO_GETGEO, &hdg))
|
||
- goto fail;
|
||
-
|
||
- if (ioctl (fd, BLKGETSIZE, &nr))
|
||
+ if (ioctl (fd, BLKGETSIZE64, &nr))
|
||
goto fail;
|
||
|
||
/* Got the geometry, so save it. */
|
||
- geom->cylinders = hdg.cylinders;
|
||
- geom->heads = hdg.heads;
|
||
- geom->sectors = hdg.sectors;
|
||
- geom->total_sectors = nr;
|
||
+ get_linux_geometry(fd, geom);
|
||
+ if (!geom->heads && !geom->cylinders && !geom->sectors)
|
||
+ goto fail;
|
||
+ geom->total_sectors = nr / 512;
|
||
|
||
goto success;
|
||
}
|
||
@@ -403,10 +545,28 @@
|
||
}
|
||
|
||
static void
|
||
+get_cciss_disk_name (char *name, int controller, int drive)
|
||
+{
|
||
+ sprintf (name, "/dev/cciss/c%dd%d", controller, drive);
|
||
+}
|
||
+
|
||
+static void
|
||
+get_ida_disk_name (char *name, int controller, int drive)
|
||
+{
|
||
+ sprintf (name, "/dev/ida/c%dd%d", controller, drive);
|
||
+}
|
||
+
|
||
+static void
|
||
get_ataraid_disk_name (char *name, int unit)
|
||
{
|
||
sprintf (name, "/dev/ataraid/d%c", unit + '0');
|
||
}
|
||
+
|
||
+static void
|
||
+get_i2o_disk_name (char *name, char unit)
|
||
+{
|
||
+ sprintf (name, "/dev/i2o/hd%c", unit);
|
||
+}
|
||
#endif
|
||
|
||
/* Check if DEVICE can be read. If an error occurs, return zero,
|
||
@@ -801,6 +961,97 @@
|
||
}
|
||
}
|
||
}
|
||
+
|
||
+ /* This is for I2O - we have /dev/i2o/hd<logical drive><partition> */
|
||
+ {
|
||
+ int unit;
|
||
+
|
||
+ for (unit = 'a'; unit < 'f'; unit++)
|
||
+ {
|
||
+ char name[24];
|
||
+
|
||
+ get_i2o_disk_name (name, unit);
|
||
+ if (check_device (name))
|
||
+ {
|
||
+ (*map)[num_hd + 0x80] = strdup (name);
|
||
+ assert ((*map)[num_hd + 0x80]);
|
||
+
|
||
+ /* If the device map file is opened, write the map. */
|
||
+ if (fp)
|
||
+ fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
|
||
+
|
||
+ num_hd++;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* This is for CCISS, its like the DAC960 - we have
|
||
+ /dev/cciss/<controller>d<logical drive>p<partition>
|
||
+
|
||
+ It currently supports up to 3 controllers, 10 logical volumes
|
||
+ and 10 partitions
|
||
+
|
||
+ Code gratuitously copied from DAC960 above.
|
||
+ Horms <horms@verge.net.au> 23rd July 2004
|
||
+ */
|
||
+ {
|
||
+ int controller, drive;
|
||
+
|
||
+ for (controller = 0; controller < 2; controller++)
|
||
+ {
|
||
+ for (drive = 0; drive < 9; drive++)
|
||
+ {
|
||
+ char name[24];
|
||
+
|
||
+ get_cciss_disk_name (name, controller, drive);
|
||
+ if (check_device (name))
|
||
+ {
|
||
+ (*map)[num_hd + 0x80] = strdup (name);
|
||
+ assert ((*map)[num_hd + 0x80]);
|
||
+
|
||
+ /* If the device map file is opened, write the map. */
|
||
+ if (fp)
|
||
+ fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
|
||
+
|
||
+ num_hd++;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* This is for Compaq Smart Array, its like the DAC960 - we have
|
||
+ /dev/ida/<controller>d<logical drive>p<partition>
|
||
+
|
||
+ It currently supports up to 3 controllers, 10 logical volumes
|
||
+ and 15 partitions
|
||
+
|
||
+ Code gratuitously copied from DAC960 above.
|
||
+ Piotr Roszatycki <dexter@debian.org>
|
||
+ */
|
||
+ {
|
||
+ int controller, drive;
|
||
+
|
||
+ for (controller = 0; controller < 2; controller++)
|
||
+ {
|
||
+ for (drive = 0; drive < 9; drive++)
|
||
+ {
|
||
+ char name[24];
|
||
+
|
||
+ get_ida_disk_name (name, controller, drive);
|
||
+ if (check_device (name))
|
||
+ {
|
||
+ (*map)[num_hd + 0x80] = strdup (name);
|
||
+ assert ((*map)[num_hd + 0x80]);
|
||
+
|
||
+ /* If the device map file is opened, write the map. */
|
||
+ if (fp)
|
||
+ fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
|
||
+
|
||
+ num_hd++;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ }
|
||
#endif /* __linux__ */
|
||
|
||
/* OK, close the device map file if opened. */
|
||
@@ -844,6 +1095,7 @@
|
||
{
|
||
char dev[PATH_MAX]; /* XXX */
|
||
int fd;
|
||
+ off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
|
||
|
||
if ((partition & 0x00FF00) != 0x00FF00)
|
||
{
|
||
@@ -861,6 +1113,14 @@
|
||
if (strcmp (dev + strlen(dev) - 5, "/disc") == 0)
|
||
strcpy (dev + strlen(dev) - 5, "/part");
|
||
}
|
||
+ else
|
||
+ {
|
||
+ if ((strncmp (dev, "/dev/ataraid/", 13) == 0) ||
|
||
+ (strncmp (dev, "/dev/ida/", 9) == 0) ||
|
||
+ (strncmp (dev, "/dev/cciss/", 11) == 0) ||
|
||
+ (strncmp (dev, "/dev/rd/", 8) == 0))
|
||
+ strcpy (dev + strlen(dev), "p");
|
||
+ }
|
||
sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1);
|
||
|
||
/* Open the partition. */
|
||
@@ -870,35 +1130,13 @@
|
||
errnum = ERR_NO_PART;
|
||
return 0;
|
||
}
|
||
-
|
||
-#if defined(__linux__) && (!defined(__GLIBC__) || \
|
||
- ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
|
||
- /* Maybe libc doesn't have large file support. */
|
||
- {
|
||
- loff_t offset, result;
|
||
- static int _llseek (uint filedes, ulong hi, ulong lo,
|
||
- loff_t *res, uint wh);
|
||
- _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
|
||
- loff_t *, res, uint, wh);
|
||
|
||
- offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
|
||
- if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
|
||
- {
|
||
- errnum = ERR_DEV_VALUES;
|
||
- return 0;
|
||
- }
|
||
- }
|
||
-#else
|
||
- {
|
||
- off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
|
||
|
||
- if (lseek (fd, offset, SEEK_SET) != offset)
|
||
- {
|
||
- errnum = ERR_DEV_VALUES;
|
||
- return 0;
|
||
- }
|
||
- }
|
||
-#endif
|
||
+ if (my_lseek(fd, offset, SEEK_SET) != offset)
|
||
+ {
|
||
+ errnum = ERR_DEV_VALUES;
|
||
+ return 0;
|
||
+ }
|
||
|
||
if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE))
|
||
{
|
||
diff -Nur grub-0.97/netboot/cs89x0.c grub-0.97-patched/netboot/cs89x0.c
|
||
--- grub-0.97/netboot/cs89x0.c 2003-07-09 13:45:37.000000000 +0200
|
||
+++ grub-0.97-patched/netboot/cs89x0.c 2012-11-11 17:07:12.722729437 +0100
|
||
@@ -1,3 +1,21 @@
|
||
+/**
|
||
+ Per an email message from Russ Nelson <nelson@crynwr.com> on
|
||
+ 18 March 2008 this file is now licensed under GPL Version 2.
|
||
+
|
||
+ From: Russ Nelson <nelson@crynwr.com>
|
||
+ Date: Tue, 18 Mar 2008 12:42:00 -0400
|
||
+ Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
|
||
+ -- quote from email
|
||
+ As copyright holder, if I say it doesn't conflict with the GPL,
|
||
+ then it doesn't conflict with the GPL.
|
||
+
|
||
+ However, there's no point in causing people's brains to overheat,
|
||
+ so yes, I grant permission for the code to be relicensed under the
|
||
+ GPLv2. Please make sure that this change in licensing makes its
|
||
+ way upstream. -russ
|
||
+ -- quote from email
|
||
+**/
|
||
+
|
||
/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. */
|
||
/*
|
||
Permission is granted to distribute the enclosed cs89x0.[ch] driver
|
||
diff -Nur grub-0.97/netboot/cs89x0.h grub-0.97-patched/netboot/cs89x0.h
|
||
--- grub-0.97/netboot/cs89x0.h 2003-07-09 13:45:37.000000000 +0200
|
||
+++ grub-0.97-patched/netboot/cs89x0.h 2012-11-11 17:07:12.723729469 +0100
|
||
@@ -1,3 +1,21 @@
|
||
+/**
|
||
+ Per an email message from Russ Nelson <nelson@crynwr.com> on
|
||
+ 18 March 2008 this file is now licensed under GPL Version 2.
|
||
+
|
||
+ From: Russ Nelson <nelson@crynwr.com>
|
||
+ Date: Tue, 18 Mar 2008 12:42:00 -0400
|
||
+ Subject: Re: [Etherboot-developers] cs89x0 driver in etherboot
|
||
+ -- quote from email
|
||
+ As copyright holder, if I say it doesn't conflict with the GPL,
|
||
+ then it doesn't conflict with the GPL.
|
||
+
|
||
+ However, there's no point in causing people's brains to overheat,
|
||
+ so yes, I grant permission for the code to be relicensed under the
|
||
+ GPLv2. Please make sure that this change in licensing makes its
|
||
+ way upstream. -russ
|
||
+ -- quote from email
|
||
+**/
|
||
+
|
||
/* Copyright, 1988-1992, Russell Nelson, Crynwr Software
|
||
|
||
This program is free software; you can redistribute it and/or modify
|
||
diff -Nur grub-0.97/netboot/etherboot.h grub-0.97-patched/netboot/etherboot.h
|
||
--- grub-0.97/netboot/etherboot.h 2003-07-09 13:45:37.000000000 +0200
|
||
+++ grub-0.97-patched/netboot/etherboot.h 2012-11-11 17:07:12.723729469 +0100
|
||
@@ -531,9 +531,6 @@
|
||
extern int network_ready;
|
||
extern struct rom_info rom;
|
||
extern struct arptable_t arptable[MAX_ARP];
|
||
-extern struct bootpd_t bootp_data;
|
||
-#define BOOTP_DATA_ADDR (&bootp_data)
|
||
-extern unsigned char *end_of_rfc1533;
|
||
|
||
/* config.c */
|
||
extern struct nic nic;
|
||
diff -Nur grub-0.97/netboot/main.c grub-0.97-patched/netboot/main.c
|
||
--- grub-0.97/netboot/main.c 2004-05-21 00:19:33.000000000 +0200
|
||
+++ grub-0.97-patched/netboot/main.c 2012-11-11 17:07:12.724729500 +0100
|
||
@@ -56,7 +56,8 @@
|
||
static unsigned long netmask;
|
||
static struct bootpd_t bootp_data;
|
||
static unsigned long xid;
|
||
-static unsigned char *end_of_rfc1533 = NULL;
|
||
+
|
||
+#define BOOTP_DATA_ADDR (&bootp_data)
|
||
|
||
#ifndef NO_DHCP_SUPPORT
|
||
#endif /* NO_DHCP_SUPPORT */
|
||
@@ -83,7 +84,9 @@
|
||
RFC2132_MAX_SIZE,2, /* request as much as we can */
|
||
ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
|
||
RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY,
|
||
- RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH
|
||
+ RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
|
||
+ /* Vendor class identifier */
|
||
+ RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
|
||
};
|
||
|
||
static const unsigned char dhcprequest[] =
|
||
@@ -103,6 +106,8 @@
|
||
/* Etherboot vendortags */
|
||
RFC1533_VENDOR_MAGIC,
|
||
RFC1533_VENDOR_CONFIGFILE,
|
||
+ /* Vendor class identifier */
|
||
+ RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
|
||
};
|
||
|
||
#endif /* ! NO_DHCP_SUPPORT */
|
||
@@ -701,7 +706,7 @@
|
||
"adcw %%ax,%0\n\t" /* add carry of previous iteration */
|
||
"loop 1b\n\t"
|
||
"adcw $0,%0" /* add carry of last iteration */
|
||
- : "=b" (*sum), "=S"(start), "=c"(len)
|
||
+ : "=r" (*sum), "=S"(start), "=c"(len)
|
||
: "0"(*sum), "1"(start), "2"(len)
|
||
: "ax", "cc"
|
||
);
|
||
@@ -967,7 +972,6 @@
|
||
|
||
if (block == 0)
|
||
{
|
||
- end_of_rfc1533 = NULL;
|
||
vendorext_isvalid = 0;
|
||
|
||
if (grub_memcmp (p, rfc1533_cookie, 4))
|
||
@@ -1021,7 +1025,7 @@
|
||
}
|
||
else if (c == RFC1533_END)
|
||
{
|
||
- end_of_rfc1533 = endp = p;
|
||
+ endp = p;
|
||
continue;
|
||
}
|
||
else if (c == RFC1533_NETMASK)
|
||
diff -Nur grub-0.97/netboot/natsemi.c grub-0.97-patched/netboot/natsemi.c
|
||
--- grub-0.97/netboot/natsemi.c 2003-07-09 13:45:38.000000000 +0200
|
||
+++ grub-0.97-patched/netboot/natsemi.c 2012-11-11 17:07:12.724729500 +0100
|
||
@@ -608,7 +608,7 @@
|
||
const char *p) /* Packet */
|
||
{
|
||
u32 status, to, nstype;
|
||
- u32 tx_status;
|
||
+ volatile u32 tx_status;
|
||
|
||
/* Stop the transmitter */
|
||
outl(TxOff, ioaddr + ChipCmd);
|
||
@@ -647,7 +647,7 @@
|
||
|
||
to = currticks() + TX_TIMEOUT;
|
||
|
||
- while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to))
|
||
+ while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
|
||
/* wait */ ;
|
||
|
||
if (currticks() >= to) {
|
||
diff -Nur grub-0.97/netboot/pci.c grub-0.97-patched/netboot/pci.c
|
||
--- grub-0.97/netboot/pci.c 2003-07-09 13:45:38.000000000 +0200
|
||
+++ grub-0.97-patched/netboot/pci.c 2012-11-11 17:07:07.227553894 +0100
|
||
@@ -105,13 +105,16 @@
|
||
|
||
save_flags(flags);
|
||
__asm__(
|
||
+ "pushl %%ebx\n\t" /* save %ebx */
|
||
#ifdef ABSOLUTE_WITHOUT_ASTERISK
|
||
- "lcall (%%edi)"
|
||
+ "lcall (%%edi)\n\t"
|
||
#else
|
||
- "lcall *(%%edi)"
|
||
+ "lcall *(%%edi)\n\t"
|
||
#endif
|
||
+ "movl %%ebx, %1\n\t" /* capture what was in %ebx */
|
||
+ "popl %%ebx\n\t" /* restore %ebx */
|
||
: "=a" (return_code),
|
||
- "=b" (address),
|
||
+ "=r" (address),
|
||
"=c" (length),
|
||
"=d" (entry)
|
||
: "0" (service),
|
||
@@ -141,18 +144,21 @@
|
||
|
||
save_flags(flags);
|
||
__asm__(
|
||
+ "pushl %%ebx\n\t" /* save %ebx */
|
||
+ "movl %3, %%ebx\n\t" /* put the value into ebx */
|
||
#ifdef ABSOLUTE_WITHOUT_ASTERISK
|
||
"lcall (%%esi)\n\t"
|
||
#else
|
||
"lcall *(%%esi)\n\t"
|
||
#endif
|
||
"jc 1f\n\t"
|
||
- "xor %%ah, %%ah\n"
|
||
+ "popl %%ebx\n\t" /* restore %ebx */
|
||
+ "xor %%ah, %%ah\n\t"
|
||
"1:"
|
||
: "=c" (*value),
|
||
"=a" (ret)
|
||
: "1" (PCIBIOS_READ_CONFIG_BYTE),
|
||
- "b" (bx),
|
||
+ "r" (bx),
|
||
"D" ((long) where),
|
||
"S" (&pci_indirect));
|
||
restore_flags(flags);
|
||
@@ -168,18 +174,21 @@
|
||
|
||
save_flags(flags);
|
||
__asm__(
|
||
+ "pushl %%ebx\n\t" /* save %ebx */
|
||
+ "movl %3, %%ebx\n\t" /* put the value into ebx */
|
||
#ifdef ABSOLUTE_WITHOUT_ASTERISK
|
||
"lcall (%%esi)\n\t"
|
||
#else
|
||
"lcall *(%%esi)\n\t"
|
||
#endif
|
||
"jc 1f\n\t"
|
||
- "xor %%ah, %%ah\n"
|
||
+ "popl %%ebx\n\t" /* restore %ebx */
|
||
+ "xor %%ah, %%ah\n\t"
|
||
"1:"
|
||
: "=c" (*value),
|
||
"=a" (ret)
|
||
: "1" (PCIBIOS_READ_CONFIG_WORD),
|
||
- "b" (bx),
|
||
+ "r" (bx),
|
||
"D" ((long) where),
|
||
"S" (&pci_indirect));
|
||
restore_flags(flags);
|
||
@@ -195,18 +204,21 @@
|
||
|
||
save_flags(flags);
|
||
__asm__(
|
||
+ "pushl %%ebx\n\t" /* save %ebx */
|
||
+ "movl %3, %%ebx\n\t" /* put the value into ebx */
|
||
#ifdef ABSOLUTE_WITHOUT_ASTERISK
|
||
"lcall (%%esi)\n\t"
|
||
#else
|
||
"lcall *(%%esi)\n\t"
|
||
#endif
|
||
"jc 1f\n\t"
|
||
- "xor %%ah, %%ah\n"
|
||
+ "popl %%ebx\n\t" /* restore %ebx */
|
||
+ "xor %%ah, %%ah\n\t"
|
||
"1:"
|
||
: "=c" (*value),
|
||
"=a" (ret)
|
||
: "1" (PCIBIOS_READ_CONFIG_DWORD),
|
||
- "b" (bx),
|
||
+ "r" (bx),
|
||
"D" ((long) where),
|
||
"S" (&pci_indirect));
|
||
restore_flags(flags);
|
||
@@ -222,18 +234,21 @@
|
||
|
||
save_flags(flags); cli();
|
||
__asm__(
|
||
+ "pushl %%ebx\n\t" /* save %ebx */
|
||
+ "movl %3, %%ebx\n\t" /* put the value into ebx */
|
||
#ifdef ABSOLUTE_WITHOUT_ASTERISK
|
||
"lcall (%%esi)\n\t"
|
||
#else
|
||
"lcall *(%%esi)\n\t"
|
||
#endif
|
||
"jc 1f\n\t"
|
||
- "xor %%ah, %%ah\n"
|
||
+ "popl %%ebx\n\t" /* restore %ebx */
|
||
+ "xor %%ah, %%ah\n\t"
|
||
"1:"
|
||
: "=a" (ret)
|
||
: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
|
||
"c" (value),
|
||
- "b" (bx),
|
||
+ "r" (bx),
|
||
"D" ((long) where),
|
||
"S" (&pci_indirect));
|
||
restore_flags(flags);
|
||
@@ -249,18 +264,21 @@
|
||
|
||
save_flags(flags); cli();
|
||
__asm__(
|
||
+ "pushl %%ebx\n\t" /* save %ebx */
|
||
+ "movl %3, %%ebx\n\t" /* put the value into ebx */
|
||
#ifdef ABSOLUTE_WITHOUT_ASTERISK
|
||
"lcall (%%esi)\n\t"
|
||
#else
|
||
"lcall *(%%esi)\n\t"
|
||
#endif
|
||
"jc 1f\n\t"
|
||
- "xor %%ah, %%ah\n"
|
||
+ "popl %%ebx\n\t" /* restore %ebx */
|
||
+ "xor %%ah, %%ah\n\t"
|
||
"1:"
|
||
: "=a" (ret)
|
||
: "0" (PCIBIOS_WRITE_CONFIG_WORD),
|
||
"c" (value),
|
||
- "b" (bx),
|
||
+ "r" (bx),
|
||
"D" ((long) where),
|
||
"S" (&pci_indirect));
|
||
restore_flags(flags);
|
||
@@ -276,18 +294,21 @@
|
||
|
||
save_flags(flags); cli();
|
||
__asm__(
|
||
+ "pushl %%ebx\n\t" /* save %ebx */
|
||
+ "movl %3, %%ebx\n\t" /* put the value into ebx */
|
||
#ifdef ABSOLUTE_WITHOUT_ASTERISK
|
||
"lcall (%%esi)\n\t"
|
||
#else
|
||
"lcall *(%%esi)\n\t"
|
||
#endif
|
||
"jc 1f\n\t"
|
||
- "xor %%ah, %%ah\n"
|
||
+ "popl %%ebx\n\t" /* restore %ebx */
|
||
+ "xor %%ah, %%ah\n\t"
|
||
"1:"
|
||
: "=a" (ret)
|
||
: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
|
||
"c" (value),
|
||
- "b" (bx),
|
||
+ "r" (bx),
|
||
"D" ((long) where),
|
||
"S" (&pci_indirect));
|
||
restore_flags(flags);
|
||
@@ -308,20 +329,22 @@
|
||
|
||
save_flags(flags);
|
||
__asm__(
|
||
+ "pushl %%ebx\n\t" /* save %ebx */
|
||
#ifdef ABSOLUTE_WITHOUT_ASTERISK
|
||
"lcall (%%edi)\n\t"
|
||
#else
|
||
"lcall *(%%edi)\n\t"
|
||
#endif
|
||
"jc 1f\n\t"
|
||
- "xor %%ah, %%ah\n"
|
||
+ "xor %%ah, %%ah\n\t"
|
||
"1:\tshl $8, %%eax\n\t"
|
||
- "movw %%bx, %%ax"
|
||
+ "movw %%bx, %%ax\n\t"
|
||
+ "popl %%ebx\n\t" /* restore %ebx */
|
||
: "=d" (signature),
|
||
"=a" (pack)
|
||
: "1" (PCIBIOS_PCI_BIOS_PRESENT),
|
||
"D" (&pci_indirect)
|
||
- : "bx", "cx");
|
||
+ : "cx");
|
||
restore_flags(flags);
|
||
|
||
present_status = (pack >> 16) & 0xff;
|
||
diff -Nur grub-0.97/netboot/sis900.c grub-0.97-patched/netboot/sis900.c
|
||
--- grub-0.97/netboot/sis900.c 2003-07-09 13:45:38.000000000 +0200
|
||
+++ grub-0.97-patched/netboot/sis900.c 2012-11-11 17:07:12.725729531 +0100
|
||
@@ -901,7 +901,7 @@
|
||
const char *p) /* Packet */
|
||
{
|
||
u32 status, to, nstype;
|
||
- u32 tx_status;
|
||
+ volatile u32 tx_status;
|
||
|
||
/* Stop the transmitter */
|
||
outl(TxDIS, ioaddr + cr);
|
||
@@ -940,7 +940,7 @@
|
||
|
||
to = currticks() + TX_TIMEOUT;
|
||
|
||
- while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to))
|
||
+ while (((tx_status=txd.cmdsts) & OWN) && (currticks() < to))
|
||
/* wait */ ;
|
||
|
||
if (currticks() >= to) {
|
||
diff -Nur grub-0.97/stage1/Makefile.am grub-0.97-patched/stage1/Makefile.am
|
||
--- grub-0.97/stage1/Makefile.am 2004-07-16 13:44:56.000000000 +0200
|
||
+++ grub-0.97-patched/stage1/Makefile.am 2012-11-11 17:07:12.747730236 +0100
|
||
@@ -1,11 +1,11 @@
|
||
-pkglibdir = $(libdir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
|
||
-nodist_pkglib_DATA = stage1
|
||
+stagedir = $(libdir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
|
||
+nodist_stage_DATA = stage1
|
||
|
||
-CLEANFILES = $(nodist_pkglib_DATA)
|
||
+CLEANFILES = $(nodist_stage_DATA)
|
||
|
||
# We can't use builtins or standard includes.
|
||
AM_CCASFLAGS = $(STAGE1_CFLAGS) -fno-builtin -nostdinc
|
||
-LDFLAGS = -nostdlib -Wl,-N,-Ttext,7C00
|
||
+stage1_exec_LDFLAGS = -nostdlib -Wl,-N,-Ttext,7C00
|
||
|
||
noinst_PROGRAMS = stage1.exec
|
||
stage1_exec_SOURCES = stage1.S stage1.h
|
||
diff -Nur grub-0.97/stage2/asm.S grub-0.97-patched/stage2/asm.S
|
||
--- grub-0.97/stage2/asm.S 2004-06-19 18:55:22.000000000 +0200
|
||
+++ grub-0.97-patched/stage2/asm.S 2012-11-11 17:07:03.850446017 +0100
|
||
@@ -1651,7 +1651,29 @@
|
||
jnz 3f
|
||
ret
|
||
|
||
-3: /* use keyboard controller */
|
||
+3: /*
|
||
+ * try to switch gateA20 using PORT92, the "Fast A20 and Init"
|
||
+ * register
|
||
+ */
|
||
+ mov $0x92, %dx
|
||
+ inb %dx, %al
|
||
+ /* skip the port92 code if it's unimplemented (read returns 0xff) */
|
||
+ cmpb $0xff, %al
|
||
+ jz 6f
|
||
+
|
||
+ /* set or clear bit1, the ALT_A20_GATE bit */
|
||
+ movb 4(%esp), %ah
|
||
+ testb %ah, %ah
|
||
+ jz 4f
|
||
+ orb $2, %al
|
||
+ jmp 5f
|
||
+4: and $0xfd, %al
|
||
+
|
||
+ /* clear the INIT_NOW bit don't accidently reset the machine */
|
||
+5: and $0xfe, %al
|
||
+ outb %al, %dx
|
||
+
|
||
+6: /* use keyboard controller */
|
||
pushl %eax
|
||
|
||
call gloop1
|
||
@@ -1661,9 +1683,12 @@
|
||
|
||
gloopint1:
|
||
inb $K_STATUS
|
||
+ cmpb $0xff, %al
|
||
+ jz gloopint1_done
|
||
andb $K_IBUF_FUL, %al
|
||
jnz gloopint1
|
||
|
||
+gloopint1_done:
|
||
movb $KB_OUTPUT_MASK, %al
|
||
cmpb $0, 0x8(%esp)
|
||
jz gdoit
|
||
@@ -1684,6 +1709,8 @@
|
||
|
||
gloop1:
|
||
inb $K_STATUS
|
||
+ cmpb $0xff, %al
|
||
+ jz gloop2ret
|
||
andb $K_IBUF_FUL, %al
|
||
jnz gloop1
|
||
|
||
@@ -1991,6 +2018,11 @@
|
||
ENTRY(console_getkey)
|
||
push %ebp
|
||
|
||
+wait_for_key:
|
||
+ call EXT_C(console_checkkey)
|
||
+ incl %eax
|
||
+ jz wait_for_key
|
||
+
|
||
call EXT_C(prot_to_real)
|
||
.code16
|
||
|
||
@@ -2216,6 +2248,156 @@
|
||
pop %ebx
|
||
pop %ebp
|
||
ret
|
||
+
|
||
+/* graphics mode functions */
|
||
+#ifdef SUPPORT_GRAPHICS
|
||
+VARIABLE(cursorX)
|
||
+.word 0
|
||
+VARIABLE(cursorY)
|
||
+.word 0
|
||
+VARIABLE(cursorCount)
|
||
+.word 0
|
||
+VARIABLE(cursorBuf)
|
||
+.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||
+
|
||
+
|
||
+/*
|
||
+ * int set_videomode(mode)
|
||
+ * BIOS call "INT 10H Function 0h" to set video mode
|
||
+ * Call with %ah = 0x0
|
||
+ * %al = video mode
|
||
+ * Returns old videomode.
|
||
+ */
|
||
+ENTRY(set_videomode)
|
||
+ push %ebp
|
||
+ push %ebx
|
||
+ push %ecx
|
||
+
|
||
+ movb 0x10(%esp), %cl
|
||
+
|
||
+ call EXT_C(prot_to_real)
|
||
+ .code16
|
||
+
|
||
+ xorw %bx, %bx
|
||
+ movb $0xf, %ah
|
||
+ int $0x10 /* Get Current Video mode */
|
||
+ movb %al, %ch
|
||
+ xorb %ah, %ah
|
||
+ movb %cl, %al
|
||
+ int $0x10 /* Set Video mode */
|
||
+
|
||
+ DATA32 call EXT_C(real_to_prot)
|
||
+ .code32
|
||
+
|
||
+ xorb %ah, %ah
|
||
+ movb %ch, %al
|
||
+
|
||
+ pop %ecx
|
||
+ pop %ebx
|
||
+ pop %ebp
|
||
+ ret
|
||
+
|
||
+
|
||
+/*
|
||
+ * unsigned char * graphics_get_font()
|
||
+ * BIOS call "INT 10H Function 11h" to set font
|
||
+ * Call with %ah = 0x11
|
||
+ */
|
||
+ENTRY(graphics_get_font)
|
||
+ push %ebp
|
||
+ push %ebx
|
||
+ push %ecx
|
||
+ push %edx
|
||
+
|
||
+ call EXT_C(prot_to_real)
|
||
+ .code16
|
||
+
|
||
+ movw $0x1130, %ax
|
||
+ movb $6, %bh /* font 8x16 */
|
||
+ int $0x10
|
||
+ movw %bp, %dx
|
||
+ movw %es, %cx
|
||
+
|
||
+ DATA32 call EXT_C(real_to_prot)
|
||
+ .code32
|
||
+
|
||
+ xorl %eax, %eax
|
||
+ movw %cx, %ax
|
||
+ shll $4, %eax
|
||
+ movw %dx, %ax
|
||
+
|
||
+ pop %edx
|
||
+ pop %ecx
|
||
+ pop %ebx
|
||
+ pop %ebp
|
||
+ ret
|
||
+
|
||
+
|
||
+
|
||
+/*
|
||
+ * graphics_set_palette(index, red, green, blue)
|
||
+ * BIOS call "INT 10H Function 10h" to set individual dac register
|
||
+ * Call with %ah = 0x10
|
||
+ * %bx = register number
|
||
+ * %ch = new value for green (0-63)
|
||
+ * %cl = new value for blue (0-63)
|
||
+ * %dh = new value for red (0-63)
|
||
+ */
|
||
+
|
||
+ENTRY(graphics_set_palette)
|
||
+ push %ebp
|
||
+ push %eax
|
||
+ push %ebx
|
||
+ push %ecx
|
||
+ push %edx
|
||
+
|
||
+ movw $0x3c8, %bx /* address write mode register */
|
||
+
|
||
+ /* wait vertical retrace */
|
||
+
|
||
+ movw $0x3da, %dx
|
||
+l1b: inb %dx, %al /* wait vertical active display */
|
||
+ test $8, %al
|
||
+ jnz l1b
|
||
+
|
||
+l2b: inb %dx, %al /* wait vertical retrace */
|
||
+ test $8, %al
|
||
+ jnz l2b
|
||
+
|
||
+ mov %bx, %dx
|
||
+ movb 0x18(%esp), %al /* index */
|
||
+ outb %al, %dx
|
||
+ inc %dx
|
||
+
|
||
+ movb 0x1c(%esp), %al /* red */
|
||
+ outb %al, %dx
|
||
+
|
||
+ movb 0x20(%esp), %al /* green */
|
||
+ outb %al, %dx
|
||
+
|
||
+ movb 0x24(%esp), %al /* blue */
|
||
+ outb %al, %dx
|
||
+
|
||
+ movw 0x18(%esp), %bx
|
||
+
|
||
+ call EXT_C(prot_to_real)
|
||
+ .code16
|
||
+
|
||
+ movb %bl, %bh
|
||
+ movw $0x1000, %ax
|
||
+ int $0x10
|
||
+
|
||
+ DATA32 call EXT_C(real_to_prot)
|
||
+ .code32
|
||
+
|
||
+ pop %edx
|
||
+ pop %ecx
|
||
+ pop %ebx
|
||
+ pop %eax
|
||
+ pop %ebp
|
||
+ ret
|
||
+
|
||
+#endif /* SUPPORT_GRAPHICS */
|
||
|
||
/*
|
||
* getrtsecs()
|
||
diff -Nur grub-0.97/stage2/bios.c grub-0.97-patched/stage2/bios.c
|
||
--- grub-0.97/stage2/bios.c 2004-03-27 17:34:04.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/bios.c 2012-11-11 17:07:12.751730363 +0100
|
||
@@ -47,7 +47,7 @@
|
||
return the error number. Otherwise, return 0. */
|
||
int
|
||
biosdisk (int read, int drive, struct geometry *geometry,
|
||
- int sector, int nsec, int segment)
|
||
+ unsigned int sector, int nsec, int segment)
|
||
{
|
||
int err;
|
||
|
||
@@ -60,7 +60,18 @@
|
||
unsigned short blocks;
|
||
unsigned long buffer;
|
||
unsigned long long block;
|
||
- } __attribute__ ((packed)) dap;
|
||
+
|
||
+ /* This structure is passed in the stack. A buggy BIOS could write
|
||
+ * garbage data to the tail of the struct and hang the machine. So
|
||
+ * we need this protection. - Tinybit
|
||
+ */
|
||
+ unsigned char dummy[16];
|
||
+ } __attribute__ ((packed)) *dap;
|
||
+
|
||
+ /* Even the above protection is not enough to avoid stupid actions by
|
||
+ * buggy BIOSes. So we do it in the 0040:0000 segment. - Tinybit
|
||
+ */
|
||
+ dap = (struct disk_address_packet *)0x580;
|
||
|
||
/* XXX: Don't check the geometry by default, because some buggy
|
||
BIOSes don't return the number of total sectors correctly,
|
||
@@ -72,15 +83,15 @@
|
||
|
||
/* FIXME: sizeof (DAP) must be 0x10. Should assert that the compiler
|
||
can't add any padding. */
|
||
- dap.length = sizeof (dap);
|
||
- dap.block = sector;
|
||
- dap.blocks = nsec;
|
||
- dap.reserved = 0;
|
||
+ dap->length = 0x10;
|
||
+ dap->block = sector;
|
||
+ dap->blocks = nsec;
|
||
+ dap->reserved = 0;
|
||
/* This is undocumented part. The address is formated in
|
||
SEGMENT:ADDRESS. */
|
||
- dap.buffer = segment << 16;
|
||
+ dap->buffer = segment << 16;
|
||
|
||
- err = biosdisk_int13_extensions ((read + 0x42) << 8, drive, &dap);
|
||
+ err = biosdisk_int13_extensions ((read + 0x42) << 8, drive, dap);
|
||
|
||
/* #undef NO_INT13_FALLBACK */
|
||
#ifndef NO_INT13_FALLBACK
|
||
diff -Nur grub-0.97/stage2/boot.c grub-0.97-patched/stage2/boot.c
|
||
--- grub-0.97/stage2/boot.c 2004-03-30 13:44:08.000000000 +0200
|
||
+++ grub-0.97-patched/stage2/boot.c 2012-11-11 17:07:12.727729596 +0100
|
||
@@ -1,7 +1,7 @@
|
||
/* boot.c - load and bootstrap a kernel */
|
||
/*
|
||
* GRUB -- GRand Unified Bootloader
|
||
- * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
|
||
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc.
|
||
*
|
||
* This program is free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
@@ -96,7 +96,7 @@
|
||
lh = (struct linux_kernel_header *) buffer;
|
||
|
||
/* ELF loading supported if multiboot, FreeBSD and NetBSD. */
|
||
- if ((type == KERNEL_TYPE_MULTIBOOT
|
||
+ if (((type == KERNEL_TYPE_MULTIBOOT && ! (flags & MULTIBOOT_AOUT_KLUDGE))
|
||
|| pu.elf->e_ident[EI_OSABI] == ELFOSABI_FREEBSD
|
||
|| grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0
|
||
|| suggested_type == KERNEL_TYPE_NETBSD)
|
||
@@ -241,7 +241,7 @@
|
||
}
|
||
|
||
if (lh->version >= 0x0202)
|
||
- lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_OFFSET;
|
||
+ lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_0202_PRM_OFFSET;
|
||
else
|
||
{
|
||
lh->cl_magic = LINUX_CL_MAGIC;
|
||
@@ -407,6 +407,15 @@
|
||
while (dest < linux_data_tmp_addr + LINUX_CL_END_OFFSET && *src)
|
||
*(dest++) = *(src++);
|
||
|
||
+ {
|
||
+ char *src = skip_to (0, arg);
|
||
+ char *dest = linux_data_tmp_addr + LINUX_CL_0202_PRM_OFFSET;
|
||
+
|
||
+ while (dest < linux_data_tmp_addr + LINUX_CL_0202_PRM_END_OFFSET && *src)
|
||
+ *(dest++) = *(src++);
|
||
+ *dest = 0;
|
||
+ }
|
||
+
|
||
/* Old Linux kernels have problems determining the amount of
|
||
the available memory. To work around this problem, we add
|
||
the "mem" option to the kernel command line. This has its
|
||
@@ -824,8 +833,11 @@
|
||
moveto = (mbi.mem_upper + 0x400) << 10;
|
||
|
||
moveto = (moveto - len) & 0xfffff000;
|
||
- max_addr = (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0203
|
||
- ? lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS);
|
||
+ max_addr = LINUX_INITRD_MAX_ADDRESS;
|
||
+ if (lh->header == LINUX_MAGIC_SIGNATURE &&
|
||
+ lh->version >= 0x0203 &&
|
||
+ lh->initrd_addr_max < max_addr)
|
||
+ max_addr = lh->initrd_addr_max;
|
||
if (moveto + len >= max_addr)
|
||
moveto = (max_addr - len) & 0xfffff000;
|
||
|
||
diff -Nur grub-0.97/stage2/boot.c.orig grub-0.97-patched/stage2/boot.c.orig
|
||
--- grub-0.97/stage2/boot.c.orig 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/boot.c.orig 2004-03-30 13:44:08.000000000 +0200
|
||
@@ -0,0 +1,1020 @@
|
||
+/* boot.c - load and bootstrap a kernel */
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License as published by
|
||
+ * the Free Software Foundation; either version 2 of the License, or
|
||
+ * (at your option) any later version.
|
||
+ *
|
||
+ * This program is distributed in the hope that it will be useful,
|
||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ * GNU General Public License for more details.
|
||
+ *
|
||
+ * You should have received a copy of the GNU General Public License
|
||
+ * along with this program; if not, write to the Free Software
|
||
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
+ */
|
||
+
|
||
+
|
||
+#include "shared.h"
|
||
+
|
||
+#include "freebsd.h"
|
||
+#include "imgact_aout.h"
|
||
+#include "i386-elf.h"
|
||
+
|
||
+static int cur_addr;
|
||
+entry_func entry_addr;
|
||
+static struct mod_list mll[99];
|
||
+static int linux_mem_size;
|
||
+
|
||
+/*
|
||
+ * The next two functions, 'load_image' and 'load_module', are the building
|
||
+ * blocks of the multiboot loader component. They handle essentially all
|
||
+ * of the gory details of loading in a bootable image and the modules.
|
||
+ */
|
||
+
|
||
+kernel_t
|
||
+load_image (char *kernel, char *arg, kernel_t suggested_type,
|
||
+ unsigned long load_flags)
|
||
+{
|
||
+ int len, i, exec_type = 0, align_4k = 1;
|
||
+ entry_func real_entry_addr = 0;
|
||
+ kernel_t type = KERNEL_TYPE_NONE;
|
||
+ unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0;
|
||
+ char *str = 0, *str2 = 0;
|
||
+ struct linux_kernel_header *lh;
|
||
+ union
|
||
+ {
|
||
+ struct multiboot_header *mb;
|
||
+ struct exec *aout;
|
||
+ Elf32_Ehdr *elf;
|
||
+ }
|
||
+ pu;
|
||
+ /* presuming that MULTIBOOT_SEARCH is large enough to encompass an
|
||
+ executable header */
|
||
+ unsigned char buffer[MULTIBOOT_SEARCH];
|
||
+
|
||
+ /* sets the header pointer to point to the beginning of the
|
||
+ buffer by default */
|
||
+ pu.aout = (struct exec *) buffer;
|
||
+
|
||
+ if (!grub_open (kernel))
|
||
+ return KERNEL_TYPE_NONE;
|
||
+
|
||
+ if (!(len = grub_read (buffer, MULTIBOOT_SEARCH)) || len < 32)
|
||
+ {
|
||
+ grub_close ();
|
||
+
|
||
+ if (!errnum)
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+
|
||
+ return KERNEL_TYPE_NONE;
|
||
+ }
|
||
+
|
||
+ for (i = 0; i < len; i++)
|
||
+ {
|
||
+ if (MULTIBOOT_FOUND ((int) (buffer + i), len - i))
|
||
+ {
|
||
+ flags = ((struct multiboot_header *) (buffer + i))->flags;
|
||
+ if (flags & MULTIBOOT_UNSUPPORTED)
|
||
+ {
|
||
+ grub_close ();
|
||
+ errnum = ERR_BOOT_FEATURES;
|
||
+ return KERNEL_TYPE_NONE;
|
||
+ }
|
||
+ type = KERNEL_TYPE_MULTIBOOT;
|
||
+ str2 = "Multiboot";
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Use BUFFER as a linux kernel header, if the image is Linux zImage
|
||
+ or bzImage. */
|
||
+ lh = (struct linux_kernel_header *) buffer;
|
||
+
|
||
+ /* ELF loading supported if multiboot, FreeBSD and NetBSD. */
|
||
+ if ((type == KERNEL_TYPE_MULTIBOOT
|
||
+ || pu.elf->e_ident[EI_OSABI] == ELFOSABI_FREEBSD
|
||
+ || grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0
|
||
+ || suggested_type == KERNEL_TYPE_NETBSD)
|
||
+ && len > sizeof (Elf32_Ehdr)
|
||
+ && BOOTABLE_I386_ELF ((*((Elf32_Ehdr *) buffer))))
|
||
+ {
|
||
+ if (type == KERNEL_TYPE_MULTIBOOT)
|
||
+ entry_addr = (entry_func) pu.elf->e_entry;
|
||
+ else
|
||
+ entry_addr = (entry_func) (pu.elf->e_entry & 0xFFFFFF);
|
||
+
|
||
+ if (entry_addr < (entry_func) 0x100000)
|
||
+ errnum = ERR_BELOW_1MB;
|
||
+
|
||
+ /* don't want to deal with ELF program header at some random
|
||
+ place in the file -- this generally won't happen */
|
||
+ if (pu.elf->e_phoff == 0 || pu.elf->e_phnum == 0
|
||
+ || ((pu.elf->e_phoff + (pu.elf->e_phentsize * pu.elf->e_phnum))
|
||
+ >= len))
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+ str = "elf";
|
||
+
|
||
+ if (type == KERNEL_TYPE_NONE)
|
||
+ {
|
||
+ /* At the moment, there is no way to identify a NetBSD ELF
|
||
+ kernel, so rely on the suggested type by the user. */
|
||
+ if (suggested_type == KERNEL_TYPE_NETBSD)
|
||
+ {
|
||
+ str2 = "NetBSD";
|
||
+ type = suggested_type;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ str2 = "FreeBSD";
|
||
+ type = KERNEL_TYPE_FREEBSD;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else if (flags & MULTIBOOT_AOUT_KLUDGE)
|
||
+ {
|
||
+ pu.mb = (struct multiboot_header *) (buffer + i);
|
||
+ entry_addr = (entry_func) pu.mb->entry_addr;
|
||
+ cur_addr = pu.mb->load_addr;
|
||
+ /* first offset into file */
|
||
+ grub_seek (i - (pu.mb->header_addr - cur_addr));
|
||
+
|
||
+ /* If the load end address is zero, load the whole contents. */
|
||
+ if (! pu.mb->load_end_addr)
|
||
+ pu.mb->load_end_addr = cur_addr + filemax;
|
||
+
|
||
+ text_len = pu.mb->load_end_addr - cur_addr;
|
||
+ data_len = 0;
|
||
+
|
||
+ /* If the bss end address is zero, assume that there is no bss area. */
|
||
+ if (! pu.mb->bss_end_addr)
|
||
+ pu.mb->bss_end_addr = pu.mb->load_end_addr;
|
||
+
|
||
+ bss_len = pu.mb->bss_end_addr - pu.mb->load_end_addr;
|
||
+
|
||
+ if (pu.mb->header_addr < pu.mb->load_addr
|
||
+ || pu.mb->load_end_addr <= pu.mb->load_addr
|
||
+ || pu.mb->bss_end_addr < pu.mb->load_end_addr
|
||
+ || (pu.mb->header_addr - pu.mb->load_addr) > i)
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+
|
||
+ if (cur_addr < 0x100000)
|
||
+ errnum = ERR_BELOW_1MB;
|
||
+
|
||
+ pu.aout = (struct exec *) buffer;
|
||
+ exec_type = 2;
|
||
+ str = "kludge";
|
||
+ }
|
||
+ else if (len > sizeof (struct exec) && !N_BADMAG ((*(pu.aout))))
|
||
+ {
|
||
+ entry_addr = (entry_func) pu.aout->a_entry;
|
||
+
|
||
+ if (type == KERNEL_TYPE_NONE)
|
||
+ {
|
||
+ /*
|
||
+ * If it doesn't have a Multiboot header, then presume
|
||
+ * it is either a FreeBSD or NetBSD executable. If so,
|
||
+ * then use a magic number of normal ordering, ZMAGIC to
|
||
+ * determine if it is FreeBSD.
|
||
+ *
|
||
+ * This is all because freebsd and netbsd seem to require
|
||
+ * masking out some address bits... differently for each
|
||
+ * one... plus of course we need to know which booting
|
||
+ * method to use.
|
||
+ */
|
||
+ entry_addr = (entry_func) ((int) entry_addr & 0xFFFFFF);
|
||
+
|
||
+ if (buffer[0] == 0xb && buffer[1] == 1)
|
||
+ {
|
||
+ type = KERNEL_TYPE_FREEBSD;
|
||
+ cur_addr = (int) entry_addr;
|
||
+ str2 = "FreeBSD";
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ type = KERNEL_TYPE_NETBSD;
|
||
+ cur_addr = (int) entry_addr & 0xF00000;
|
||
+ if (N_GETMAGIC ((*(pu.aout))) != NMAGIC)
|
||
+ align_4k = 0;
|
||
+ str2 = "NetBSD";
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* first offset into file */
|
||
+ grub_seek (N_TXTOFF (*(pu.aout)));
|
||
+ text_len = pu.aout->a_text;
|
||
+ data_len = pu.aout->a_data;
|
||
+ bss_len = pu.aout->a_bss;
|
||
+
|
||
+ if (cur_addr < 0x100000)
|
||
+ errnum = ERR_BELOW_1MB;
|
||
+
|
||
+ exec_type = 1;
|
||
+ str = "a.out";
|
||
+ }
|
||
+ else if (lh->boot_flag == BOOTSEC_SIGNATURE
|
||
+ && lh->setup_sects <= LINUX_MAX_SETUP_SECTS)
|
||
+ {
|
||
+ int big_linux = 0;
|
||
+ int setup_sects = lh->setup_sects;
|
||
+
|
||
+ if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200)
|
||
+ {
|
||
+ big_linux = (lh->loadflags & LINUX_FLAG_BIG_KERNEL);
|
||
+ lh->type_of_loader = LINUX_BOOT_LOADER_TYPE;
|
||
+
|
||
+ /* Put the real mode part at as a high location as possible. */
|
||
+ linux_data_real_addr
|
||
+ = (char *) ((mbi.mem_lower << 10) - LINUX_SETUP_MOVE_SIZE);
|
||
+ /* But it must not exceed the traditional area. */
|
||
+ if (linux_data_real_addr > (char *) LINUX_OLD_REAL_MODE_ADDR)
|
||
+ linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;
|
||
+
|
||
+ if (lh->version >= 0x0201)
|
||
+ {
|
||
+ lh->heap_end_ptr = LINUX_HEAP_END_OFFSET;
|
||
+ lh->loadflags |= LINUX_FLAG_CAN_USE_HEAP;
|
||
+ }
|
||
+
|
||
+ if (lh->version >= 0x0202)
|
||
+ lh->cmd_line_ptr = linux_data_real_addr + LINUX_CL_OFFSET;
|
||
+ else
|
||
+ {
|
||
+ lh->cl_magic = LINUX_CL_MAGIC;
|
||
+ lh->cl_offset = LINUX_CL_OFFSET;
|
||
+ lh->setup_move_size = LINUX_SETUP_MOVE_SIZE;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Your kernel is quite old... */
|
||
+ lh->cl_magic = LINUX_CL_MAGIC;
|
||
+ lh->cl_offset = LINUX_CL_OFFSET;
|
||
+
|
||
+ setup_sects = LINUX_DEFAULT_SETUP_SECTS;
|
||
+
|
||
+ linux_data_real_addr = (char *) LINUX_OLD_REAL_MODE_ADDR;
|
||
+ }
|
||
+
|
||
+ /* If SETUP_SECTS is not set, set it to the default (4). */
|
||
+ if (! setup_sects)
|
||
+ setup_sects = LINUX_DEFAULT_SETUP_SECTS;
|
||
+
|
||
+ data_len = setup_sects << 9;
|
||
+ text_len = filemax - data_len - SECTOR_SIZE;
|
||
+
|
||
+ linux_data_tmp_addr = (char *) LINUX_BZIMAGE_ADDR + text_len;
|
||
+
|
||
+ if (! big_linux
|
||
+ && text_len > linux_data_real_addr - (char *) LINUX_ZIMAGE_ADDR)
|
||
+ {
|
||
+ grub_printf (" linux 'zImage' kernel too big, try 'make bzImage'\n");
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ }
|
||
+ else if (linux_data_real_addr + LINUX_SETUP_MOVE_SIZE
|
||
+ > RAW_ADDR ((char *) (mbi.mem_lower << 10)))
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ else
|
||
+ {
|
||
+ grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n",
|
||
+ (big_linux ? "bzImage" : "zImage"), data_len, text_len);
|
||
+
|
||
+ /* Video mode selection support. What a mess! */
|
||
+ /* NOTE: Even the word "mess" is not still enough to
|
||
+ represent how wrong and bad the Linux video support is,
|
||
+ but I don't want to hear complaints from Linux fanatics
|
||
+ any more. -okuji */
|
||
+ {
|
||
+ char *vga;
|
||
+
|
||
+ /* Find the substring "vga=". */
|
||
+ vga = grub_strstr (arg, "vga=");
|
||
+ if (vga)
|
||
+ {
|
||
+ char *value = vga + 4;
|
||
+ int vid_mode;
|
||
+
|
||
+ /* Handle special strings. */
|
||
+ if (substring ("normal", value) < 1)
|
||
+ vid_mode = LINUX_VID_MODE_NORMAL;
|
||
+ else if (substring ("ext", value) < 1)
|
||
+ vid_mode = LINUX_VID_MODE_EXTENDED;
|
||
+ else if (substring ("ask", value) < 1)
|
||
+ vid_mode = LINUX_VID_MODE_ASK;
|
||
+ else if (safe_parse_maxint (&value, &vid_mode))
|
||
+ ;
|
||
+ else
|
||
+ {
|
||
+ /* ERRNUM is already set inside the function
|
||
+ safe_parse_maxint. */
|
||
+ grub_close ();
|
||
+ return KERNEL_TYPE_NONE;
|
||
+ }
|
||
+
|
||
+ lh->vid_mode = vid_mode;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Check the mem= option to limit memory used for initrd. */
|
||
+ {
|
||
+ char *mem;
|
||
+
|
||
+ mem = grub_strstr (arg, "mem=");
|
||
+ if (mem)
|
||
+ {
|
||
+ char *value = mem + 4;
|
||
+
|
||
+ safe_parse_maxint (&value, &linux_mem_size);
|
||
+ switch (errnum)
|
||
+ {
|
||
+ case ERR_NUMBER_OVERFLOW:
|
||
+ /* If an overflow occurs, use the maximum address for
|
||
+ initrd instead. This is good, because MAXINT is
|
||
+ greater than LINUX_INITRD_MAX_ADDRESS. */
|
||
+ linux_mem_size = LINUX_INITRD_MAX_ADDRESS;
|
||
+ errnum = ERR_NONE;
|
||
+ break;
|
||
+
|
||
+ case ERR_NONE:
|
||
+ {
|
||
+ int shift = 0;
|
||
+
|
||
+ switch (grub_tolower (*value))
|
||
+ {
|
||
+ case 'g':
|
||
+ shift += 10;
|
||
+ case 'm':
|
||
+ shift += 10;
|
||
+ case 'k':
|
||
+ shift += 10;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* Check an overflow. */
|
||
+ if (linux_mem_size > (MAXINT >> shift))
|
||
+ linux_mem_size = LINUX_INITRD_MAX_ADDRESS;
|
||
+ else
|
||
+ linux_mem_size <<= shift;
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ linux_mem_size = 0;
|
||
+ errnum = ERR_NONE;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ linux_mem_size = 0;
|
||
+ }
|
||
+
|
||
+ /* It is possible that DATA_LEN + SECTOR_SIZE is greater than
|
||
+ MULTIBOOT_SEARCH, so the data may have been read partially. */
|
||
+ if (data_len + SECTOR_SIZE <= MULTIBOOT_SEARCH)
|
||
+ grub_memmove (linux_data_tmp_addr, buffer,
|
||
+ data_len + SECTOR_SIZE);
|
||
+ else
|
||
+ {
|
||
+ grub_memmove (linux_data_tmp_addr, buffer, MULTIBOOT_SEARCH);
|
||
+ grub_read (linux_data_tmp_addr + MULTIBOOT_SEARCH,
|
||
+ data_len + SECTOR_SIZE - MULTIBOOT_SEARCH);
|
||
+ }
|
||
+
|
||
+ if (lh->header != LINUX_MAGIC_SIGNATURE ||
|
||
+ lh->version < 0x0200)
|
||
+ /* Clear the heap space. */
|
||
+ grub_memset (linux_data_tmp_addr + ((setup_sects + 1) << 9),
|
||
+ 0,
|
||
+ (64 - setup_sects - 1) << 9);
|
||
+
|
||
+ /* Copy command-line plus memory hack to staging area.
|
||
+ NOTE: Linux has a bug that it doesn't handle multiple spaces
|
||
+ between two options and a space after a "mem=" option isn't
|
||
+ removed correctly so the arguments to init could be like
|
||
+ {"init", "", "", NULL}. This affects some not-very-clever
|
||
+ shells. Thus, the code below does a trick to avoid the bug.
|
||
+ That is, copy "mem=XXX" to the end of the command-line, and
|
||
+ avoid to copy spaces unnecessarily. Hell. */
|
||
+ {
|
||
+ char *src = skip_to (0, arg);
|
||
+ char *dest = linux_data_tmp_addr + LINUX_CL_OFFSET;
|
||
+
|
||
+ while (dest < linux_data_tmp_addr + LINUX_CL_END_OFFSET && *src)
|
||
+ *(dest++) = *(src++);
|
||
+
|
||
+ /* Old Linux kernels have problems determining the amount of
|
||
+ the available memory. To work around this problem, we add
|
||
+ the "mem" option to the kernel command line. This has its
|
||
+ own drawbacks because newer kernels can determine the
|
||
+ memory map more accurately. Boot protocol 2.03, which
|
||
+ appeared in Linux 2.4.18, provides a pointer to the kernel
|
||
+ version string, so we could check it. But since kernel
|
||
+ 2.4.18 and newer are known to detect memory reliably, boot
|
||
+ protocol 2.03 already implies that the kernel is new
|
||
+ enough. The "mem" option is added if neither of the
|
||
+ following conditions is met:
|
||
+ 1) The "mem" option is already present.
|
||
+ 2) The "kernel" command is used with "--no-mem-option".
|
||
+ 3) GNU GRUB is configured not to pass the "mem" option.
|
||
+ 4) The kernel supports boot protocol 2.03 or newer. */
|
||
+ if (! grub_strstr (arg, "mem=")
|
||
+ && ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION)
|
||
+ && lh->version < 0x0203 /* kernel version < 2.4.18 */
|
||
+ && dest + 15 < linux_data_tmp_addr + LINUX_CL_END_OFFSET)
|
||
+ {
|
||
+ *dest++ = ' ';
|
||
+ *dest++ = 'm';
|
||
+ *dest++ = 'e';
|
||
+ *dest++ = 'm';
|
||
+ *dest++ = '=';
|
||
+
|
||
+ dest = convert_to_ascii (dest, 'u', (extended_memory + 0x400));
|
||
+ *dest++ = 'K';
|
||
+ }
|
||
+
|
||
+ *dest = 0;
|
||
+ }
|
||
+
|
||
+ /* offset into file */
|
||
+ grub_seek (data_len + SECTOR_SIZE);
|
||
+
|
||
+ cur_addr = (int) linux_data_tmp_addr + LINUX_SETUP_MOVE_SIZE;
|
||
+ grub_read ((char *) LINUX_BZIMAGE_ADDR, text_len);
|
||
+
|
||
+ if (errnum == ERR_NONE)
|
||
+ {
|
||
+ grub_close ();
|
||
+
|
||
+ /* Sanity check. */
|
||
+ if (suggested_type != KERNEL_TYPE_NONE
|
||
+ && ((big_linux && suggested_type != KERNEL_TYPE_BIG_LINUX)
|
||
+ || (! big_linux && suggested_type != KERNEL_TYPE_LINUX)))
|
||
+ {
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+ return KERNEL_TYPE_NONE;
|
||
+ }
|
||
+
|
||
+ /* Ugly hack. */
|
||
+ linux_text_len = text_len;
|
||
+
|
||
+ return big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else /* no recognizable format */
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+
|
||
+ /* return if error */
|
||
+ if (errnum)
|
||
+ {
|
||
+ grub_close ();
|
||
+ return KERNEL_TYPE_NONE;
|
||
+ }
|
||
+
|
||
+ /* fill the multiboot info structure */
|
||
+ mbi.cmdline = (int) arg;
|
||
+ mbi.mods_count = 0;
|
||
+ mbi.mods_addr = 0;
|
||
+ mbi.boot_device = (current_drive << 24) | current_partition;
|
||
+ mbi.flags &= ~(MB_INFO_MODS | MB_INFO_AOUT_SYMS | MB_INFO_ELF_SHDR);
|
||
+ mbi.syms.a.tabsize = 0;
|
||
+ mbi.syms.a.strsize = 0;
|
||
+ mbi.syms.a.addr = 0;
|
||
+ mbi.syms.a.pad = 0;
|
||
+
|
||
+ printf (" [%s-%s", str2, str);
|
||
+
|
||
+ str = "";
|
||
+
|
||
+ if (exec_type) /* can be loaded like a.out */
|
||
+ {
|
||
+ if (flags & MULTIBOOT_AOUT_KLUDGE)
|
||
+ str = "-and-data";
|
||
+
|
||
+ printf (", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len);
|
||
+
|
||
+ /* read text, then read data */
|
||
+ if (grub_read ((char *) RAW_ADDR (cur_addr), text_len) == text_len)
|
||
+ {
|
||
+ cur_addr += text_len;
|
||
+
|
||
+ if (!(flags & MULTIBOOT_AOUT_KLUDGE))
|
||
+ {
|
||
+ /* we have to align to a 4K boundary */
|
||
+ if (align_4k)
|
||
+ cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
|
||
+ else
|
||
+ printf (", C");
|
||
+
|
||
+ printf (", data=0x%x", data_len);
|
||
+
|
||
+ if ((grub_read ((char *) RAW_ADDR (cur_addr), data_len)
|
||
+ != data_len)
|
||
+ && !errnum)
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+ cur_addr += data_len;
|
||
+ }
|
||
+
|
||
+ if (!errnum)
|
||
+ {
|
||
+ memset ((char *) RAW_ADDR (cur_addr), 0, bss_len);
|
||
+ cur_addr += bss_len;
|
||
+
|
||
+ printf (", bss=0x%x", bss_len);
|
||
+ }
|
||
+ }
|
||
+ else if (!errnum)
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+
|
||
+ if (!errnum && pu.aout->a_syms
|
||
+ && pu.aout->a_syms < (filemax - filepos))
|
||
+ {
|
||
+ int symtab_err, orig_addr = cur_addr;
|
||
+
|
||
+ /* we should align to a 4K boundary here for good measure */
|
||
+ if (align_4k)
|
||
+ cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
|
||
+
|
||
+ mbi.syms.a.addr = cur_addr;
|
||
+
|
||
+ *((int *) RAW_ADDR (cur_addr)) = pu.aout->a_syms;
|
||
+ cur_addr += sizeof (int);
|
||
+
|
||
+ printf (", symtab=0x%x", pu.aout->a_syms);
|
||
+
|
||
+ if (grub_read ((char *) RAW_ADDR (cur_addr), pu.aout->a_syms)
|
||
+ == pu.aout->a_syms)
|
||
+ {
|
||
+ cur_addr += pu.aout->a_syms;
|
||
+ mbi.syms.a.tabsize = pu.aout->a_syms;
|
||
+
|
||
+ if (grub_read ((char *) &i, sizeof (int)) == sizeof (int))
|
||
+ {
|
||
+ *((int *) RAW_ADDR (cur_addr)) = i;
|
||
+ cur_addr += sizeof (int);
|
||
+
|
||
+ mbi.syms.a.strsize = i;
|
||
+
|
||
+ i -= sizeof (int);
|
||
+
|
||
+ printf (", strtab=0x%x", i);
|
||
+
|
||
+ symtab_err = (grub_read ((char *) RAW_ADDR (cur_addr), i)
|
||
+ != i);
|
||
+ cur_addr += i;
|
||
+ }
|
||
+ else
|
||
+ symtab_err = 1;
|
||
+ }
|
||
+ else
|
||
+ symtab_err = 1;
|
||
+
|
||
+ if (symtab_err)
|
||
+ {
|
||
+ printf ("(bad)");
|
||
+ cur_addr = orig_addr;
|
||
+ mbi.syms.a.tabsize = 0;
|
||
+ mbi.syms.a.strsize = 0;
|
||
+ mbi.syms.a.addr = 0;
|
||
+ }
|
||
+ else
|
||
+ mbi.flags |= MB_INFO_AOUT_SYMS;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ /* ELF executable */
|
||
+ {
|
||
+ unsigned loaded = 0, memaddr, memsiz, filesiz;
|
||
+ Elf32_Phdr *phdr;
|
||
+
|
||
+ /* reset this to zero for now */
|
||
+ cur_addr = 0;
|
||
+
|
||
+ /* scan for program segments */
|
||
+ for (i = 0; i < pu.elf->e_phnum; i++)
|
||
+ {
|
||
+ phdr = (Elf32_Phdr *)
|
||
+ (pu.elf->e_phoff + ((int) buffer)
|
||
+ + (pu.elf->e_phentsize * i));
|
||
+ if (phdr->p_type == PT_LOAD)
|
||
+ {
|
||
+ /* offset into file */
|
||
+ grub_seek (phdr->p_offset);
|
||
+ filesiz = phdr->p_filesz;
|
||
+
|
||
+ if (type == KERNEL_TYPE_FREEBSD || type == KERNEL_TYPE_NETBSD)
|
||
+ memaddr = RAW_ADDR (phdr->p_paddr & 0xFFFFFF);
|
||
+ else
|
||
+ memaddr = RAW_ADDR (phdr->p_paddr);
|
||
+
|
||
+ memsiz = phdr->p_memsz;
|
||
+ if (memaddr < RAW_ADDR (0x100000))
|
||
+ errnum = ERR_BELOW_1MB;
|
||
+
|
||
+ /* If the memory range contains the entry address, get the
|
||
+ physical address here. */
|
||
+ if (type == KERNEL_TYPE_MULTIBOOT
|
||
+ && (unsigned) entry_addr >= phdr->p_vaddr
|
||
+ && (unsigned) entry_addr < phdr->p_vaddr + memsiz)
|
||
+ real_entry_addr = (entry_func) ((unsigned) entry_addr
|
||
+ + memaddr - phdr->p_vaddr);
|
||
+
|
||
+ /* make sure we only load what we're supposed to! */
|
||
+ if (filesiz > memsiz)
|
||
+ filesiz = memsiz;
|
||
+ /* mark memory as used */
|
||
+ if (cur_addr < memaddr + memsiz)
|
||
+ cur_addr = memaddr + memsiz;
|
||
+ printf (", <0x%x:0x%x:0x%x>", memaddr, filesiz,
|
||
+ memsiz - filesiz);
|
||
+ /* increment number of segments */
|
||
+ loaded++;
|
||
+
|
||
+ /* load the segment */
|
||
+ if (memcheck (memaddr, memsiz)
|
||
+ && grub_read ((char *) memaddr, filesiz) == filesiz)
|
||
+ {
|
||
+ if (memsiz > filesiz)
|
||
+ memset ((char *) (memaddr + filesiz), 0, memsiz - filesiz);
|
||
+ }
|
||
+ else
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (! errnum)
|
||
+ {
|
||
+ if (! loaded)
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+ else
|
||
+ {
|
||
+ /* Load ELF symbols. */
|
||
+ Elf32_Shdr *shdr = NULL;
|
||
+ int tab_size, sec_size;
|
||
+ int symtab_err = 0;
|
||
+
|
||
+ mbi.syms.e.num = pu.elf->e_shnum;
|
||
+ mbi.syms.e.size = pu.elf->e_shentsize;
|
||
+ mbi.syms.e.shndx = pu.elf->e_shstrndx;
|
||
+
|
||
+ /* We should align to a 4K boundary here for good measure. */
|
||
+ if (align_4k)
|
||
+ cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
|
||
+
|
||
+ tab_size = pu.elf->e_shentsize * pu.elf->e_shnum;
|
||
+
|
||
+ grub_seek (pu.elf->e_shoff);
|
||
+ if (grub_read ((char *) RAW_ADDR (cur_addr), tab_size)
|
||
+ == tab_size)
|
||
+ {
|
||
+ mbi.syms.e.addr = cur_addr;
|
||
+ shdr = (Elf32_Shdr *) mbi.syms.e.addr;
|
||
+ cur_addr += tab_size;
|
||
+
|
||
+ printf (", shtab=0x%x", cur_addr);
|
||
+
|
||
+ for (i = 0; i < mbi.syms.e.num; i++)
|
||
+ {
|
||
+ /* This section is a loaded section,
|
||
+ so we don't care. */
|
||
+ if (shdr[i].sh_addr != 0)
|
||
+ continue;
|
||
+
|
||
+ /* This section is empty, so we don't care. */
|
||
+ if (shdr[i].sh_size == 0)
|
||
+ continue;
|
||
+
|
||
+ /* Align the section to a sh_addralign bits boundary. */
|
||
+ cur_addr = ((cur_addr + shdr[i].sh_addralign) &
|
||
+ - (int) shdr[i].sh_addralign);
|
||
+
|
||
+ grub_seek (shdr[i].sh_offset);
|
||
+
|
||
+ sec_size = shdr[i].sh_size;
|
||
+
|
||
+ if (! (memcheck (cur_addr, sec_size)
|
||
+ && (grub_read ((char *) RAW_ADDR (cur_addr),
|
||
+ sec_size)
|
||
+ == sec_size)))
|
||
+ {
|
||
+ symtab_err = 1;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ shdr[i].sh_addr = cur_addr;
|
||
+ cur_addr += sec_size;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ symtab_err = 1;
|
||
+
|
||
+ if (mbi.syms.e.addr < RAW_ADDR(0x10000))
|
||
+ symtab_err = 1;
|
||
+
|
||
+ if (symtab_err)
|
||
+ {
|
||
+ printf ("(bad)");
|
||
+ mbi.syms.e.num = 0;
|
||
+ mbi.syms.e.size = 0;
|
||
+ mbi.syms.e.addr = 0;
|
||
+ mbi.syms.e.shndx = 0;
|
||
+ cur_addr = 0;
|
||
+ }
|
||
+ else
|
||
+ mbi.flags |= MB_INFO_ELF_SHDR;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (! errnum)
|
||
+ {
|
||
+ grub_printf (", entry=0x%x]\n", (unsigned) entry_addr);
|
||
+
|
||
+ /* If the entry address is physically different from that of the ELF
|
||
+ header, correct it here. */
|
||
+ if (real_entry_addr)
|
||
+ entry_addr = real_entry_addr;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ putchar ('\n');
|
||
+ type = KERNEL_TYPE_NONE;
|
||
+ }
|
||
+
|
||
+ grub_close ();
|
||
+
|
||
+ /* Sanity check. */
|
||
+ if (suggested_type != KERNEL_TYPE_NONE && suggested_type != type)
|
||
+ {
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+ return KERNEL_TYPE_NONE;
|
||
+ }
|
||
+
|
||
+ return type;
|
||
+}
|
||
+
|
||
+int
|
||
+load_module (char *module, char *arg)
|
||
+{
|
||
+ int len;
|
||
+
|
||
+ /* if we are supposed to load on 4K boundaries */
|
||
+ cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
|
||
+
|
||
+ if (!grub_open (module))
|
||
+ return 0;
|
||
+
|
||
+ len = grub_read ((char *) cur_addr, -1);
|
||
+ if (! len)
|
||
+ {
|
||
+ grub_close ();
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ printf (" [Multiboot-module @ 0x%x, 0x%x bytes]\n", cur_addr, len);
|
||
+
|
||
+ /* these two simply need to be set if any modules are loaded at all */
|
||
+ mbi.flags |= MB_INFO_MODS;
|
||
+ mbi.mods_addr = (int) mll;
|
||
+
|
||
+ mll[mbi.mods_count].cmdline = (int) arg;
|
||
+ mll[mbi.mods_count].mod_start = cur_addr;
|
||
+ cur_addr += len;
|
||
+ mll[mbi.mods_count].mod_end = cur_addr;
|
||
+ mll[mbi.mods_count].pad = 0;
|
||
+
|
||
+ /* increment number of modules included */
|
||
+ mbi.mods_count++;
|
||
+
|
||
+ grub_close ();
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+int
|
||
+load_initrd (char *initrd)
|
||
+{
|
||
+ int len;
|
||
+ unsigned long moveto;
|
||
+ unsigned long max_addr;
|
||
+ struct linux_kernel_header *lh
|
||
+ = (struct linux_kernel_header *) (cur_addr - LINUX_SETUP_MOVE_SIZE);
|
||
+
|
||
+#ifndef NO_DECOMPRESSION
|
||
+ no_decompression = 1;
|
||
+#endif
|
||
+
|
||
+ if (! grub_open (initrd))
|
||
+ goto fail;
|
||
+
|
||
+ len = grub_read ((char *) cur_addr, -1);
|
||
+ if (! len)
|
||
+ {
|
||
+ grub_close ();
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ if (linux_mem_size)
|
||
+ moveto = linux_mem_size;
|
||
+ else
|
||
+ moveto = (mbi.mem_upper + 0x400) << 10;
|
||
+
|
||
+ moveto = (moveto - len) & 0xfffff000;
|
||
+ max_addr = (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0203
|
||
+ ? lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS);
|
||
+ if (moveto + len >= max_addr)
|
||
+ moveto = (max_addr - len) & 0xfffff000;
|
||
+
|
||
+ /* XXX: Linux 2.3.xx has a bug in the memory range check, so avoid
|
||
+ the last page.
|
||
+ XXX: Linux 2.2.xx has a bug in the memory range check, which is
|
||
+ worse than that of Linux 2.3.xx, so avoid the last 64kb. *sigh* */
|
||
+ moveto -= 0x10000;
|
||
+ memmove ((void *) RAW_ADDR (moveto), (void *) cur_addr, len);
|
||
+
|
||
+ printf (" [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len);
|
||
+
|
||
+ /* FIXME: Should check if the kernel supports INITRD. */
|
||
+ lh->ramdisk_image = RAW_ADDR (moveto);
|
||
+ lh->ramdisk_size = len;
|
||
+
|
||
+ grub_close ();
|
||
+
|
||
+ fail:
|
||
+
|
||
+#ifndef NO_DECOMPRESSION
|
||
+ no_decompression = 0;
|
||
+#endif
|
||
+
|
||
+ return ! errnum;
|
||
+}
|
||
+
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+/* Dummy function to fake the *BSD boot. */
|
||
+static void
|
||
+bsd_boot_entry (int flags, int bootdev, int sym_start, int sym_end,
|
||
+ int mem_upper, int mem_lower)
|
||
+{
|
||
+ stop ();
|
||
+}
|
||
+#endif
|
||
+
|
||
+
|
||
+/*
|
||
+ * All "*_boot" commands depend on the images being loaded into memory
|
||
+ * correctly, the variables in this file being set up correctly, and
|
||
+ * the root partition being set in the 'saved_drive' and 'saved_partition'
|
||
+ * variables.
|
||
+ */
|
||
+
|
||
+
|
||
+void
|
||
+bsd_boot (kernel_t type, int bootdev, char *arg)
|
||
+{
|
||
+ char *str;
|
||
+ int clval = 0, i;
|
||
+ struct bootinfo bi;
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+ entry_addr = (entry_func) bsd_boot_entry;
|
||
+#else
|
||
+ stop_floppy ();
|
||
+#endif
|
||
+
|
||
+ while (*(++arg) && *arg != ' ');
|
||
+ str = arg;
|
||
+ while (*str)
|
||
+ {
|
||
+ if (*str == '-')
|
||
+ {
|
||
+ while (*str && *str != ' ')
|
||
+ {
|
||
+ if (*str == 'C')
|
||
+ clval |= RB_CDROM;
|
||
+ if (*str == 'a')
|
||
+ clval |= RB_ASKNAME;
|
||
+ if (*str == 'b')
|
||
+ clval |= RB_HALT;
|
||
+ if (*str == 'c')
|
||
+ clval |= RB_CONFIG;
|
||
+ if (*str == 'd')
|
||
+ clval |= RB_KDB;
|
||
+ if (*str == 'D')
|
||
+ clval |= RB_MULTIPLE;
|
||
+ if (*str == 'g')
|
||
+ clval |= RB_GDB;
|
||
+ if (*str == 'h')
|
||
+ clval |= RB_SERIAL;
|
||
+ if (*str == 'm')
|
||
+ clval |= RB_MUTE;
|
||
+ if (*str == 'r')
|
||
+ clval |= RB_DFLTROOT;
|
||
+ if (*str == 's')
|
||
+ clval |= RB_SINGLE;
|
||
+ if (*str == 'v')
|
||
+ clval |= RB_VERBOSE;
|
||
+ str++;
|
||
+ }
|
||
+ continue;
|
||
+ }
|
||
+ str++;
|
||
+ }
|
||
+
|
||
+ if (type == KERNEL_TYPE_FREEBSD)
|
||
+ {
|
||
+ clval |= RB_BOOTINFO;
|
||
+
|
||
+ bi.bi_version = BOOTINFO_VERSION;
|
||
+
|
||
+ *arg = 0;
|
||
+ while ((--arg) > (char *) MB_CMDLINE_BUF && *arg != '/');
|
||
+ if (*arg == '/')
|
||
+ bi.bi_kernelname = arg + 1;
|
||
+ else
|
||
+ bi.bi_kernelname = 0;
|
||
+
|
||
+ bi.bi_nfs_diskless = 0;
|
||
+ bi.bi_n_bios_used = 0; /* this field is apparently unused */
|
||
+
|
||
+ for (i = 0; i < N_BIOS_GEOM; i++)
|
||
+ {
|
||
+ struct geometry geom;
|
||
+
|
||
+ /* XXX Should check the return value. */
|
||
+ get_diskinfo (i + 0x80, &geom);
|
||
+ /* FIXME: If HEADS or SECTORS is greater than 255, then this will
|
||
+ break the geometry information. That is a drawback of BSD
|
||
+ but not of GRUB. */
|
||
+ bi.bi_bios_geom[i] = (((geom.cylinders - 1) << 16)
|
||
+ + (((geom.heads - 1) & 0xff) << 8)
|
||
+ + (geom.sectors & 0xff));
|
||
+ }
|
||
+
|
||
+ bi.bi_size = sizeof (struct bootinfo);
|
||
+ bi.bi_memsizes_valid = 1;
|
||
+ bi.bi_bios_dev = saved_drive;
|
||
+ bi.bi_basemem = mbi.mem_lower;
|
||
+ bi.bi_extmem = extended_memory;
|
||
+
|
||
+ if (mbi.flags & MB_INFO_AOUT_SYMS)
|
||
+ {
|
||
+ bi.bi_symtab = mbi.syms.a.addr;
|
||
+ bi.bi_esymtab = mbi.syms.a.addr + 4
|
||
+ + mbi.syms.a.tabsize + mbi.syms.a.strsize;
|
||
+ }
|
||
+#if 0
|
||
+ else if (mbi.flags & MB_INFO_ELF_SHDR)
|
||
+ {
|
||
+ /* FIXME: Should check if a symbol table exists and, if exists,
|
||
+ pass the table to BI. */
|
||
+ }
|
||
+#endif
|
||
+ else
|
||
+ {
|
||
+ bi.bi_symtab = 0;
|
||
+ bi.bi_esymtab = 0;
|
||
+ }
|
||
+
|
||
+ /* call entry point */
|
||
+ (*entry_addr) (clval, bootdev, 0, 0, 0, ((int) (&bi)));
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /*
|
||
+ * We now pass the various bootstrap parameters to the loaded
|
||
+ * image via the argument list.
|
||
+ *
|
||
+ * This is the official list:
|
||
+ *
|
||
+ * arg0 = 8 (magic)
|
||
+ * arg1 = boot flags
|
||
+ * arg2 = boot device
|
||
+ * arg3 = start of symbol table (0 if not loaded)
|
||
+ * arg4 = end of symbol table (0 if not loaded)
|
||
+ * arg5 = transfer address from image
|
||
+ * arg6 = transfer address for next image pointer
|
||
+ * arg7 = conventional memory size (640)
|
||
+ * arg8 = extended memory size (8196)
|
||
+ *
|
||
+ * ...in actuality, we just pass the parameters used by the kernel.
|
||
+ */
|
||
+
|
||
+ /* call entry point */
|
||
+ unsigned long end_mark;
|
||
+
|
||
+ if (mbi.flags & MB_INFO_AOUT_SYMS)
|
||
+ end_mark = (mbi.syms.a.addr + 4
|
||
+ + mbi.syms.a.tabsize + mbi.syms.a.strsize);
|
||
+ else
|
||
+ /* FIXME: it should be mbi.syms.e.size. */
|
||
+ end_mark = 0;
|
||
+
|
||
+ (*entry_addr) (clval, bootdev, 0, end_mark,
|
||
+ extended_memory, mbi.mem_lower);
|
||
+ }
|
||
+}
|
||
diff -Nur grub-0.97/stage2/builtins.c grub-0.97-patched/stage2/builtins.c
|
||
--- grub-0.97/stage2/builtins.c 2005-02-15 22:58:23.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/builtins.c 2012-11-11 17:07:12.729729661 +0100
|
||
@@ -131,63 +131,98 @@
|
||
}
|
||
|
||
|
||
+/* blocklist_read_helper nee disk_read_blocklist_func was a nested
|
||
+ * function, to which pointers were taken and exposed globally. Even
|
||
+ * in the GNU-C nested functions extension, they have local linkage,
|
||
+ * and aren't guaranteed to be accessable *at all* outside of their
|
||
+ * containing scope.
|
||
+ *
|
||
+ * Above and beyond all of that, the variables within blocklist_func_context
|
||
+ * are originally local variables, with local (not even static) linkage,
|
||
+ * from within blocklist_func. These were each referenced by
|
||
+ * disk_read_blocklist_func, which is only called from other functions
|
||
+ * through a globally scoped pointer.
|
||
+ *
|
||
+ * The documentation in GCC actually uses the words "all hell will break
|
||
+ * loose" to describe this scenario.
|
||
+ *
|
||
+ * Also, "start_sector" was also used uninitialized, but gcc doesn't warn
|
||
+ * about it (possibly because of the scoping madness?)
|
||
+ */
|
||
+
|
||
+static struct {
|
||
+ int start_sector;
|
||
+ int num_sectors;
|
||
+ int num_entries;
|
||
+ int last_length;
|
||
+} blocklist_func_context = {
|
||
+ .start_sector = 0,
|
||
+ .num_sectors = 0,
|
||
+ .num_entries = 0,
|
||
+ .last_length = 0
|
||
+};
|
||
+
|
||
+/* Collect contiguous blocks into one entry as many as possible,
|
||
+ and print the blocklist notation on the screen. */
|
||
+static void
|
||
+blocklist_read_helper (int sector, int offset, int length)
|
||
+{
|
||
+ int *start_sector = &blocklist_func_context.start_sector;
|
||
+ int *num_sectors = &blocklist_func_context.num_sectors;
|
||
+ int *num_entries = &blocklist_func_context.num_entries;
|
||
+ int *last_length = &blocklist_func_context.last_length;
|
||
+
|
||
+ if (*num_sectors > 0)
|
||
+ {
|
||
+ if (*start_sector + *num_sectors == sector
|
||
+ && offset == 0 && *last_length == SECTOR_SIZE)
|
||
+ {
|
||
+ *num_sectors++;
|
||
+ *last_length = length;
|
||
+ return;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if (*last_length == SECTOR_SIZE)
|
||
+ grub_printf ("%s%d+%d", *num_entries ? "," : "",
|
||
+ *start_sector - part_start, *num_sectors);
|
||
+ else if (*num_sectors > 1)
|
||
+ grub_printf ("%s%d+%d,%d[0-%d]", *num_entries ? "," : "",
|
||
+ *start_sector - part_start, *num_sectors-1,
|
||
+ *start_sector + *num_sectors-1 - part_start,
|
||
+ *last_length);
|
||
+ else
|
||
+ grub_printf ("%s%d[0-%d]", *num_entries ? "," : "",
|
||
+ *start_sector - part_start, *last_length);
|
||
+ *num_entries++;
|
||
+ *num_sectors = 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (offset > 0)
|
||
+ {
|
||
+ grub_printf("%s%d[%d-%d]", *num_entries ? "," : "",
|
||
+ sector-part_start, offset, offset+length);
|
||
+ *num_entries++;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ *start_sector = sector;
|
||
+ *num_sectors = 1;
|
||
+ *last_length = length;
|
||
+ }
|
||
+}
|
||
+
|
||
/* blocklist */
|
||
static int
|
||
blocklist_func (char *arg, int flags)
|
||
{
|
||
char *dummy = (char *) RAW_ADDR (0x100000);
|
||
- int start_sector;
|
||
- int num_sectors = 0;
|
||
- int num_entries = 0;
|
||
- int last_length = 0;
|
||
|
||
- auto void disk_read_blocklist_func (int sector, int offset, int length);
|
||
+ int *start_sector = &blocklist_func_context.start_sector;
|
||
+ int *num_sectors = &blocklist_func_context.num_sectors;
|
||
+ int *num_entries = &blocklist_func_context.num_entries;
|
||
|
||
- /* Collect contiguous blocks into one entry as many as possible,
|
||
- and print the blocklist notation on the screen. */
|
||
- auto void disk_read_blocklist_func (int sector, int offset, int length)
|
||
- {
|
||
- if (num_sectors > 0)
|
||
- {
|
||
- if (start_sector + num_sectors == sector
|
||
- && offset == 0 && last_length == SECTOR_SIZE)
|
||
- {
|
||
- num_sectors++;
|
||
- last_length = length;
|
||
- return;
|
||
- }
|
||
- else
|
||
- {
|
||
- if (last_length == SECTOR_SIZE)
|
||
- grub_printf ("%s%d+%d", num_entries ? "," : "",
|
||
- start_sector - part_start, num_sectors);
|
||
- else if (num_sectors > 1)
|
||
- grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "",
|
||
- start_sector - part_start, num_sectors-1,
|
||
- start_sector + num_sectors-1 - part_start,
|
||
- last_length);
|
||
- else
|
||
- grub_printf ("%s%d[0-%d]", num_entries ? "," : "",
|
||
- start_sector - part_start, last_length);
|
||
- num_entries++;
|
||
- num_sectors = 0;
|
||
- }
|
||
- }
|
||
-
|
||
- if (offset > 0)
|
||
- {
|
||
- grub_printf("%s%d[%d-%d]", num_entries ? "," : "",
|
||
- sector-part_start, offset, offset+length);
|
||
- num_entries++;
|
||
- }
|
||
- else
|
||
- {
|
||
- start_sector = sector;
|
||
- num_sectors = 1;
|
||
- last_length = length;
|
||
- }
|
||
- }
|
||
-
|
||
/* Open the file. */
|
||
if (! grub_open (arg))
|
||
return 1;
|
||
@@ -206,15 +241,15 @@
|
||
grub_printf (")");
|
||
|
||
/* Read in the whole file to DUMMY. */
|
||
- disk_read_hook = disk_read_blocklist_func;
|
||
+ disk_read_hook = blocklist_read_helper;
|
||
if (! grub_read (dummy, -1))
|
||
goto fail;
|
||
|
||
/* The last entry may not be printed yet. Don't check if it is a
|
||
* full sector, since it doesn't matter if we read too much. */
|
||
- if (num_sectors > 0)
|
||
- grub_printf ("%s%d+%d", num_entries ? "," : "",
|
||
- start_sector - part_start, num_sectors);
|
||
+ if (*num_sectors > 0)
|
||
+ grub_printf ("%s%d+%d", *num_entries ? "," : "",
|
||
+ *start_sector - part_start, *num_sectors);
|
||
|
||
grub_printf ("\n");
|
||
|
||
@@ -852,6 +887,138 @@
|
||
};
|
||
#endif /* SUPPORT_NETBOOT */
|
||
|
||
+static int terminal_func (char *arg, int flags);
|
||
+
|
||
+#ifdef SUPPORT_GRAPHICS
|
||
+
|
||
+static int splashimage_func(char *arg, int flags) {
|
||
+ char splashimage[64];
|
||
+ int i;
|
||
+
|
||
+ /* filename can only be 64 characters due to our buffer size */
|
||
+ if (strlen(arg) > 63)
|
||
+ return 1;
|
||
+ if (flags == BUILTIN_CMDLINE) {
|
||
+ if (!grub_open(arg))
|
||
+ return 1;
|
||
+ grub_close();
|
||
+ }
|
||
+
|
||
+ strcpy(splashimage, arg);
|
||
+
|
||
+ /* get rid of TERM_NEED_INIT from the graphics terminal. */
|
||
+ for (i = 0; term_table[i].name; i++) {
|
||
+ if (grub_strcmp (term_table[i].name, "graphics") == 0) {
|
||
+ term_table[i].flags &= ~TERM_NEED_INIT;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ graphics_set_splash(splashimage);
|
||
+
|
||
+ if (flags == BUILTIN_CMDLINE && graphics_inited) {
|
||
+ graphics_end();
|
||
+ graphics_init();
|
||
+ graphics_cls();
|
||
+ }
|
||
+
|
||
+ /* FIXME: should we be explicitly switching the terminal as a
|
||
+ * side effect here? */
|
||
+ terminal_func("graphics", flags);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_splashimage =
|
||
+{
|
||
+ "splashimage",
|
||
+ splashimage_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "splashimage FILE",
|
||
+ "Load FILE as the background image when in graphics mode."
|
||
+};
|
||
+
|
||
+
|
||
+/* foreground */
|
||
+static int
|
||
+foreground_func(char *arg, int flags)
|
||
+{
|
||
+ if (grub_strlen(arg) == 6) {
|
||
+ int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
|
||
+ int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
|
||
+ int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
|
||
+
|
||
+ foreground = (r << 16) | (g << 8) | b;
|
||
+ if (graphics_inited)
|
||
+ graphics_set_palette(15, r, g, b);
|
||
+
|
||
+ return (0);
|
||
+ }
|
||
+
|
||
+ return (1);
|
||
+}
|
||
+
|
||
+static struct builtin builtin_foreground =
|
||
+{
|
||
+ "foreground",
|
||
+ foreground_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "foreground RRGGBB",
|
||
+ "Sets the foreground color when in graphics mode."
|
||
+ "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
|
||
+};
|
||
+
|
||
+
|
||
+/* background */
|
||
+static int
|
||
+background_func(char *arg, int flags)
|
||
+{
|
||
+ if (grub_strlen(arg) == 6) {
|
||
+ int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
|
||
+ int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
|
||
+ int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
|
||
+
|
||
+ background = (r << 16) | (g << 8) | b;
|
||
+ if (graphics_inited)
|
||
+ graphics_set_palette(0, r, g, b);
|
||
+ return (0);
|
||
+ }
|
||
+
|
||
+ return (1);
|
||
+}
|
||
+
|
||
+static struct builtin builtin_background =
|
||
+{
|
||
+ "background",
|
||
+ background_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "background RRGGBB",
|
||
+ "Sets the background color when in graphics mode."
|
||
+ "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
|
||
+};
|
||
+
|
||
+#endif /* SUPPORT_GRAPHICS */
|
||
+
|
||
+
|
||
+/* clear */
|
||
+static int
|
||
+clear_func()
|
||
+{
|
||
+ if (current_term->cls)
|
||
+ current_term->cls();
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_clear =
|
||
+{
|
||
+ "clear",
|
||
+ clear_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "clear",
|
||
+ "Clear the screen"
|
||
+};
|
||
+
|
||
|
||
/* displayapm */
|
||
static int
|
||
@@ -1233,14 +1400,15 @@
|
||
for (drive = 0x80; drive < 0x88; drive++)
|
||
{
|
||
unsigned long part = 0xFFFFFF;
|
||
- unsigned long start, len, offset, ext_offset;
|
||
- int type, entry;
|
||
+ unsigned long start, len, offset, ext_offset, gpt_offset;
|
||
+ int type, entry, gpt_count, gpt_size;
|
||
char buf[SECTOR_SIZE];
|
||
|
||
current_drive = drive;
|
||
while (next_partition (drive, 0xFFFFFF, &part, &type,
|
||
&start, &len, &offset, &entry,
|
||
- &ext_offset, buf))
|
||
+ &ext_offset, &gpt_offset,
|
||
+ &gpt_count, &gpt_size, buf))
|
||
{
|
||
if (type != PC_SLICE_TYPE_NONE
|
||
&& ! IS_PC_SLICE_TYPE_BSD (type)
|
||
@@ -1740,6 +1908,77 @@
|
||
|
||
|
||
/* install */
|
||
+static struct {
|
||
+ int saved_sector;
|
||
+ int installaddr;
|
||
+ int installlist;
|
||
+ char *stage2_first_buffer;
|
||
+} install_func_context = {
|
||
+ .saved_sector = 0,
|
||
+ .installaddr = 0,
|
||
+ .installlist = 0,
|
||
+ .stage2_first_buffer = NULL,
|
||
+};
|
||
+
|
||
+/* Save the first sector of Stage2 in STAGE2_SECT. */
|
||
+/* Formerly disk_read_savesect_func with local scope inside install_func */
|
||
+static void
|
||
+install_savesect_helper(int sector, int offset, int length)
|
||
+{
|
||
+ if (debug)
|
||
+ printf ("[%d]", sector);
|
||
+
|
||
+ /* ReiserFS has files which sometimes contain data not aligned
|
||
+ on sector boundaries. Returning an error is better than
|
||
+ silently failing. */
|
||
+ if (offset != 0 || length != SECTOR_SIZE)
|
||
+ errnum = ERR_UNALIGNED;
|
||
+
|
||
+ install_func_context.saved_sector = sector;
|
||
+}
|
||
+
|
||
+/* Write SECTOR to INSTALLLIST, and update INSTALLADDR and INSTALLSECT. */
|
||
+/* Formerly disk_read_blocklist_func with local scope inside install_func */
|
||
+static void
|
||
+install_blocklist_helper (int sector, int offset, int length)
|
||
+{
|
||
+ int *installaddr = &install_func_context.installaddr;
|
||
+ int *installlist = &install_func_context.installlist;
|
||
+ char **stage2_first_buffer = &install_func_context.stage2_first_buffer;
|
||
+ /* Was the last sector full? */
|
||
+ static int last_length = SECTOR_SIZE;
|
||
+
|
||
+ if (debug)
|
||
+ printf("[%d]", sector);
|
||
+
|
||
+ if (offset != 0 || last_length != SECTOR_SIZE)
|
||
+ {
|
||
+ /* We found a non-sector-aligned data block. */
|
||
+ errnum = ERR_UNALIGNED;
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ last_length = length;
|
||
+
|
||
+ if (*((unsigned long *) (*installlist - 4))
|
||
+ + *((unsigned short *) *installlist) != sector
|
||
+ || *installlist == (int) *stage2_first_buffer + SECTOR_SIZE + 4)
|
||
+ {
|
||
+ *installlist -= 8;
|
||
+
|
||
+ if (*((unsigned long *) (*installlist - 8)))
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ else
|
||
+ {
|
||
+ *((unsigned short *) (*installlist + 2)) = (*installaddr >> 4);
|
||
+ *((unsigned long *) (*installlist - 4)) = sector;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ *((unsigned short *) *installlist) += 1;
|
||
+ *installaddr += 512;
|
||
+}
|
||
+
|
||
static int
|
||
install_func (char *arg, int flags)
|
||
{
|
||
@@ -1747,8 +1986,12 @@
|
||
char *stage1_buffer = (char *) RAW_ADDR (0x100000);
|
||
char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
|
||
char *old_sect = stage2_buffer + SECTOR_SIZE;
|
||
- char *stage2_first_buffer = old_sect + SECTOR_SIZE;
|
||
- char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
|
||
+ /* stage2_first_buffer used to be defined as:
|
||
+ * char *stage2_first_buffer = old_sect + SECTOR_SIZE; */
|
||
+ char **stage2_first_buffer = &install_func_context.stage2_first_buffer;
|
||
+ /* and stage2_second_buffer was:
|
||
+ * char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; */
|
||
+ char *stage2_second_buffer = old_sect + SECTOR_SIZE + SECTOR_SIZE;
|
||
/* XXX: Probably SECTOR_SIZE is reasonable. */
|
||
char *config_filename = stage2_second_buffer + SECTOR_SIZE;
|
||
char *dummy = config_filename + SECTOR_SIZE;
|
||
@@ -1757,10 +2000,11 @@
|
||
int src_drive, src_partition, src_part_start;
|
||
int i;
|
||
struct geometry dest_geom, src_geom;
|
||
- int saved_sector;
|
||
+ int *saved_sector = &install_func_context.saved_sector;
|
||
int stage2_first_sector, stage2_second_sector;
|
||
char *ptr;
|
||
- int installaddr, installlist;
|
||
+ int *installaddr = &install_func_context.installaddr;
|
||
+ int *installlist = &install_func_context.installlist;
|
||
/* Point to the location of the name of a configuration file in Stage 2. */
|
||
char *config_file_location;
|
||
/* If FILE is a Stage 1.5? */
|
||
@@ -1769,67 +2013,13 @@
|
||
int is_open = 0;
|
||
/* If LBA is forced? */
|
||
int is_force_lba = 0;
|
||
- /* Was the last sector full? */
|
||
- int last_length = SECTOR_SIZE;
|
||
-
|
||
+
|
||
+ *stage2_first_buffer = old_sect + SECTOR_SIZE;
|
||
#ifdef GRUB_UTIL
|
||
/* If the Stage 2 is in a partition mounted by an OS, this will store
|
||
the filename under the OS. */
|
||
char *stage2_os_file = 0;
|
||
#endif /* GRUB_UTIL */
|
||
-
|
||
- auto void disk_read_savesect_func (int sector, int offset, int length);
|
||
- auto void disk_read_blocklist_func (int sector, int offset, int length);
|
||
-
|
||
- /* Save the first sector of Stage2 in STAGE2_SECT. */
|
||
- auto void disk_read_savesect_func (int sector, int offset, int length)
|
||
- {
|
||
- if (debug)
|
||
- printf ("[%d]", sector);
|
||
-
|
||
- /* ReiserFS has files which sometimes contain data not aligned
|
||
- on sector boundaries. Returning an error is better than
|
||
- silently failing. */
|
||
- if (offset != 0 || length != SECTOR_SIZE)
|
||
- errnum = ERR_UNALIGNED;
|
||
-
|
||
- saved_sector = sector;
|
||
- }
|
||
-
|
||
- /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
|
||
- INSTALLSECT. */
|
||
- auto void disk_read_blocklist_func (int sector, int offset, int length)
|
||
- {
|
||
- if (debug)
|
||
- printf("[%d]", sector);
|
||
-
|
||
- if (offset != 0 || last_length != SECTOR_SIZE)
|
||
- {
|
||
- /* We found a non-sector-aligned data block. */
|
||
- errnum = ERR_UNALIGNED;
|
||
- return;
|
||
- }
|
||
-
|
||
- last_length = length;
|
||
-
|
||
- if (*((unsigned long *) (installlist - 4))
|
||
- + *((unsigned short *) installlist) != sector
|
||
- || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
|
||
- {
|
||
- installlist -= 8;
|
||
-
|
||
- if (*((unsigned long *) (installlist - 8)))
|
||
- errnum = ERR_WONT_FIT;
|
||
- else
|
||
- {
|
||
- *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
|
||
- *((unsigned long *) (installlist - 4)) = sector;
|
||
- }
|
||
- }
|
||
-
|
||
- *((unsigned short *) installlist) += 1;
|
||
- installaddr += 512;
|
||
- }
|
||
|
||
/* First, check the GNU-style long option. */
|
||
while (1)
|
||
@@ -1862,10 +2052,10 @@
|
||
addr = skip_to (0, file);
|
||
|
||
/* Get the installation address. */
|
||
- if (! safe_parse_maxint (&addr, &installaddr))
|
||
+ if (! safe_parse_maxint (&addr, installaddr))
|
||
{
|
||
/* ADDR is not specified. */
|
||
- installaddr = 0;
|
||
+ *installaddr = 0;
|
||
ptr = addr;
|
||
errnum = 0;
|
||
}
|
||
@@ -1961,17 +2151,17 @@
|
||
= 0x9090;
|
||
|
||
/* Read the first sector of Stage 2. */
|
||
- disk_read_hook = disk_read_savesect_func;
|
||
- if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
|
||
+ disk_read_hook = install_savesect_helper;
|
||
+ if (grub_read (*stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
|
||
goto fail;
|
||
|
||
- stage2_first_sector = saved_sector;
|
||
+ stage2_first_sector = *saved_sector;
|
||
|
||
/* Read the second sector of Stage 2. */
|
||
if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
|
||
goto fail;
|
||
|
||
- stage2_second_sector = saved_sector;
|
||
+ stage2_second_sector = *saved_sector;
|
||
|
||
/* Check for the version of Stage 2. */
|
||
if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
|
||
@@ -1987,27 +2177,27 @@
|
||
|
||
/* If INSTALLADDR is not specified explicitly in the command-line,
|
||
determine it by the Stage 2 id. */
|
||
- if (! installaddr)
|
||
+ if (! *installaddr)
|
||
{
|
||
if (! is_stage1_5)
|
||
/* Stage 2. */
|
||
- installaddr = 0x8000;
|
||
+ *installaddr = 0x8000;
|
||
else
|
||
/* Stage 1.5. */
|
||
- installaddr = 0x2000;
|
||
+ *installaddr = 0x2000;
|
||
}
|
||
|
||
*((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
|
||
= stage2_first_sector;
|
||
*((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
|
||
- = installaddr;
|
||
+ = *installaddr;
|
||
*((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
|
||
- = installaddr >> 4;
|
||
+ = *installaddr >> 4;
|
||
|
||
- i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
|
||
+ i = (int) *stage2_first_buffer + SECTOR_SIZE - 4;
|
||
while (*((unsigned long *) i))
|
||
{
|
||
- if (i < (int) stage2_first_buffer
|
||
+ if (i < (int) *stage2_first_buffer
|
||
|| (*((int *) (i - 4)) & 0x80000000)
|
||
|| *((unsigned short *) i) >= 0xA00
|
||
|| *((short *) (i + 2)) == 0)
|
||
@@ -2021,13 +2211,13 @@
|
||
i -= 8;
|
||
}
|
||
|
||
- installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
|
||
- installaddr += SECTOR_SIZE;
|
||
+ *installlist = (int) *stage2_first_buffer + SECTOR_SIZE + 4;
|
||
+ *installaddr += SECTOR_SIZE;
|
||
|
||
/* Read the whole of Stage2 except for the first sector. */
|
||
grub_seek (SECTOR_SIZE);
|
||
|
||
- disk_read_hook = disk_read_blocklist_func;
|
||
+ disk_read_hook = install_blocklist_helper;
|
||
if (! grub_read (dummy, -1))
|
||
goto fail;
|
||
|
||
@@ -2110,7 +2300,7 @@
|
||
/* Skip the first sector. */
|
||
grub_seek (SECTOR_SIZE);
|
||
|
||
- disk_read_hook = disk_read_savesect_func;
|
||
+ disk_read_hook = install_savesect_helper;
|
||
if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
|
||
goto fail;
|
||
|
||
@@ -2180,7 +2370,7 @@
|
||
else
|
||
#endif /* GRUB_UTIL */
|
||
{
|
||
- if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
|
||
+ if (! devwrite (*saved_sector - part_start, 1, stage2_buffer))
|
||
goto fail;
|
||
}
|
||
}
|
||
@@ -2202,7 +2392,7 @@
|
||
goto fail;
|
||
}
|
||
|
||
- if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
|
||
+ if (fwrite (*stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
|
||
{
|
||
fclose (fp);
|
||
errnum = ERR_WRITE;
|
||
@@ -2229,7 +2419,7 @@
|
||
goto fail;
|
||
|
||
if (! devwrite (stage2_first_sector - src_part_start, 1,
|
||
- stage2_first_buffer))
|
||
+ *stage2_first_buffer))
|
||
goto fail;
|
||
|
||
if (! devwrite (stage2_second_sector - src_part_start, 1,
|
||
@@ -2815,8 +3005,8 @@
|
||
{
|
||
int new_type;
|
||
unsigned long part = 0xFFFFFF;
|
||
- unsigned long start, len, offset, ext_offset;
|
||
- int entry, type;
|
||
+ unsigned long start, len, offset, ext_offset, gpt_offset;
|
||
+ int entry, type, gpt_count, gpt_size;
|
||
char mbr[512];
|
||
|
||
/* Get the drive and the partition. */
|
||
@@ -2853,8 +3043,15 @@
|
||
/* Look for the partition. */
|
||
while (next_partition (current_drive, 0xFFFFFF, &part, &type,
|
||
&start, &len, &offset, &entry,
|
||
- &ext_offset, mbr))
|
||
+ &ext_offset, &gpt_offset, &gpt_count, &gpt_size, mbr))
|
||
{
|
||
+ /* The partition may not be a GPT partition. */
|
||
+ if (gpt_offset != 0)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
if (part == current_partition)
|
||
{
|
||
/* Found. */
|
||
@@ -3830,15 +4027,15 @@
|
||
{
|
||
char tmp[16];
|
||
grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
|
||
- grub_strncat (device, tmp, 256);
|
||
+ grub_strncat (device, tmp, sizeof (device));
|
||
}
|
||
if ((partition & 0x00FF00) != 0x00FF00)
|
||
{
|
||
char tmp[16];
|
||
grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
|
||
- grub_strncat (device, tmp, 256);
|
||
+ grub_strncat (device, tmp, sizeof (device));
|
||
}
|
||
- grub_strncat (device, ")", 256);
|
||
+ grub_strncat (device, ")", sizeof (device));
|
||
}
|
||
|
||
int embed_stage1_5 (char *stage1_5, int drive, int partition)
|
||
@@ -4085,7 +4282,7 @@
|
||
};
|
||
|
||
|
||
-#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
|
||
+#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
|
||
/* terminal */
|
||
static int
|
||
terminal_func (char *arg, int flags)
|
||
@@ -4244,17 +4441,21 @@
|
||
end:
|
||
current_term = term_table + default_term;
|
||
current_term->flags = term_flags;
|
||
-
|
||
+
|
||
if (lines)
|
||
max_lines = lines;
|
||
else
|
||
- /* 24 would be a good default value. */
|
||
- max_lines = 24;
|
||
-
|
||
+ max_lines = current_term->max_lines;
|
||
+
|
||
/* If the interface is currently the command-line,
|
||
restart it to repaint the screen. */
|
||
- if (current_term != prev_term && (flags & BUILTIN_CMDLINE))
|
||
+ if ((current_term != prev_term) && (flags & BUILTIN_CMDLINE)){
|
||
+ if (prev_term->shutdown)
|
||
+ prev_term->shutdown();
|
||
+ if (current_term->startup)
|
||
+ current_term->startup();
|
||
grub_longjmp (restart_cmdline_env, 0);
|
||
+ }
|
||
|
||
return 0;
|
||
}
|
||
@@ -4264,7 +4465,7 @@
|
||
"terminal",
|
||
terminal_func,
|
||
BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
- "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules]",
|
||
+ "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules] [graphics]",
|
||
"Select a terminal. When multiple terminals are specified, wait until"
|
||
" you push any key to continue. If both console and serial are specified,"
|
||
" the terminal to which you input a key first will be selected. If no"
|
||
@@ -4276,7 +4477,7 @@
|
||
" seconds. The option --lines specifies the maximum number of lines."
|
||
" The option --silent is used to suppress messages."
|
||
};
|
||
-#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */
|
||
+#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
|
||
|
||
|
||
#ifdef SUPPORT_SERIAL
|
||
@@ -4795,6 +4996,9 @@
|
||
/* The table of builtin commands. Sorted in dictionary order. */
|
||
struct builtin *builtin_table[] =
|
||
{
|
||
+#ifdef SUPPORT_GRAPHICS
|
||
+ &builtin_background,
|
||
+#endif
|
||
&builtin_blocklist,
|
||
&builtin_boot,
|
||
#ifdef SUPPORT_NETBOOT
|
||
@@ -4802,6 +5006,7 @@
|
||
#endif /* SUPPORT_NETBOOT */
|
||
&builtin_cat,
|
||
&builtin_chainloader,
|
||
+ &builtin_clear,
|
||
&builtin_cmp,
|
||
&builtin_color,
|
||
&builtin_configfile,
|
||
@@ -4821,6 +5026,9 @@
|
||
&builtin_embed,
|
||
&builtin_fallback,
|
||
&builtin_find,
|
||
+#ifdef SUPPORT_GRAPHICS
|
||
+ &builtin_foreground,
|
||
+#endif
|
||
&builtin_fstest,
|
||
&builtin_geometry,
|
||
&builtin_halt,
|
||
@@ -4864,9 +5072,12 @@
|
||
#endif /* SUPPORT_SERIAL */
|
||
&builtin_setkey,
|
||
&builtin_setup,
|
||
-#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
|
||
+#ifdef SUPPORT_GRAPHICS
|
||
+ &builtin_splashimage,
|
||
+#endif /* SUPPORT_GRAPHICS */
|
||
+#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
|
||
&builtin_terminal,
|
||
-#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */
|
||
+#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
|
||
#ifdef SUPPORT_SERIAL
|
||
&builtin_terminfo,
|
||
#endif /* SUPPORT_SERIAL */
|
||
diff -Nur grub-0.97/stage2/builtins.c.orig grub-0.97-patched/stage2/builtins.c.orig
|
||
--- grub-0.97/stage2/builtins.c.orig 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/builtins.c.orig 2005-02-15 22:58:23.000000000 +0100
|
||
@@ -0,0 +1,4884 @@
|
||
+/* builtins.c - the GRUB builtin commands */
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License as published by
|
||
+ * the Free Software Foundation; either version 2 of the License, or
|
||
+ * (at your option) any later version.
|
||
+ *
|
||
+ * This program is distributed in the hope that it will be useful,
|
||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ * GNU General Public License for more details.
|
||
+ *
|
||
+ * You should have received a copy of the GNU General Public License
|
||
+ * along with this program; if not, write to the Free Software
|
||
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
+ */
|
||
+
|
||
+/* Include stdio.h before shared.h, because we can't define
|
||
+ WITHOUT_LIBC_STUBS here. */
|
||
+#ifdef GRUB_UTIL
|
||
+# include <stdio.h>
|
||
+#endif
|
||
+
|
||
+#include <shared.h>
|
||
+#include <filesys.h>
|
||
+#include <term.h>
|
||
+
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+# define GRUB 1
|
||
+# include <etherboot.h>
|
||
+#endif
|
||
+
|
||
+#ifdef SUPPORT_SERIAL
|
||
+# include <serial.h>
|
||
+# include <terminfo.h>
|
||
+#endif
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+# include <device.h>
|
||
+#else /* ! GRUB_UTIL */
|
||
+# include <apic.h>
|
||
+# include <smp-imps.h>
|
||
+#endif /* ! GRUB_UTIL */
|
||
+
|
||
+#ifdef USE_MD5_PASSWORDS
|
||
+# include <md5.h>
|
||
+#endif
|
||
+
|
||
+/* The type of kernel loaded. */
|
||
+kernel_t kernel_type;
|
||
+/* The boot device. */
|
||
+static int bootdev;
|
||
+/* True when the debug mode is turned on, and false
|
||
+ when it is turned off. */
|
||
+int debug = 0;
|
||
+/* The default entry. */
|
||
+int default_entry = 0;
|
||
+/* The fallback entry. */
|
||
+int fallback_entryno;
|
||
+int fallback_entries[MAX_FALLBACK_ENTRIES];
|
||
+/* The number of current entry. */
|
||
+int current_entryno;
|
||
+/* The address for Multiboot command-line buffer. */
|
||
+static char *mb_cmdline;
|
||
+/* The password. */
|
||
+char *password;
|
||
+/* The password type. */
|
||
+password_t password_type;
|
||
+/* The flag for indicating that the user is authoritative. */
|
||
+int auth = 0;
|
||
+/* The timeout. */
|
||
+int grub_timeout = -1;
|
||
+/* Whether to show the menu or not. */
|
||
+int show_menu = 1;
|
||
+/* The BIOS drive map. */
|
||
+static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1];
|
||
+
|
||
+/* Prototypes for allowing straightfoward calling of builtins functions
|
||
+ inside other functions. */
|
||
+static int configfile_func (char *arg, int flags);
|
||
+
|
||
+/* Initialize the data for builtins. */
|
||
+void
|
||
+init_builtins (void)
|
||
+{
|
||
+ kernel_type = KERNEL_TYPE_NONE;
|
||
+ /* BSD and chainloading evil hacks! */
|
||
+ bootdev = set_bootdev (0);
|
||
+ mb_cmdline = (char *) MB_CMDLINE_BUF;
|
||
+}
|
||
+
|
||
+/* Initialize the data for the configuration file. */
|
||
+void
|
||
+init_config (void)
|
||
+{
|
||
+ default_entry = 0;
|
||
+ password = 0;
|
||
+ fallback_entryno = -1;
|
||
+ fallback_entries[0] = -1;
|
||
+ grub_timeout = -1;
|
||
+}
|
||
+
|
||
+/* Check a password for correctness. Returns 0 if password was
|
||
+ correct, and a value != 0 for error, similarly to strcmp. */
|
||
+int
|
||
+check_password (char *entered, char* expected, password_t type)
|
||
+{
|
||
+ switch (type)
|
||
+ {
|
||
+ case PASSWORD_PLAIN:
|
||
+ return strcmp (entered, expected);
|
||
+
|
||
+#ifdef USE_MD5_PASSWORDS
|
||
+ case PASSWORD_MD5:
|
||
+ return check_md5_password (entered, expected);
|
||
+#endif
|
||
+ default:
|
||
+ /* unsupported password type: be secure */
|
||
+ return 1;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Print which sector is read when loading a file. */
|
||
+static void
|
||
+disk_read_print_func (int sector, int offset, int length)
|
||
+{
|
||
+ grub_printf ("[%d,%d,%d]", sector, offset, length);
|
||
+}
|
||
+
|
||
+
|
||
+/* blocklist */
|
||
+static int
|
||
+blocklist_func (char *arg, int flags)
|
||
+{
|
||
+ char *dummy = (char *) RAW_ADDR (0x100000);
|
||
+ int start_sector;
|
||
+ int num_sectors = 0;
|
||
+ int num_entries = 0;
|
||
+ int last_length = 0;
|
||
+
|
||
+ auto void disk_read_blocklist_func (int sector, int offset, int length);
|
||
+
|
||
+ /* Collect contiguous blocks into one entry as many as possible,
|
||
+ and print the blocklist notation on the screen. */
|
||
+ auto void disk_read_blocklist_func (int sector, int offset, int length)
|
||
+ {
|
||
+ if (num_sectors > 0)
|
||
+ {
|
||
+ if (start_sector + num_sectors == sector
|
||
+ && offset == 0 && last_length == SECTOR_SIZE)
|
||
+ {
|
||
+ num_sectors++;
|
||
+ last_length = length;
|
||
+ return;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if (last_length == SECTOR_SIZE)
|
||
+ grub_printf ("%s%d+%d", num_entries ? "," : "",
|
||
+ start_sector - part_start, num_sectors);
|
||
+ else if (num_sectors > 1)
|
||
+ grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "",
|
||
+ start_sector - part_start, num_sectors-1,
|
||
+ start_sector + num_sectors-1 - part_start,
|
||
+ last_length);
|
||
+ else
|
||
+ grub_printf ("%s%d[0-%d]", num_entries ? "," : "",
|
||
+ start_sector - part_start, last_length);
|
||
+ num_entries++;
|
||
+ num_sectors = 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (offset > 0)
|
||
+ {
|
||
+ grub_printf("%s%d[%d-%d]", num_entries ? "," : "",
|
||
+ sector-part_start, offset, offset+length);
|
||
+ num_entries++;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ start_sector = sector;
|
||
+ num_sectors = 1;
|
||
+ last_length = length;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Open the file. */
|
||
+ if (! grub_open (arg))
|
||
+ return 1;
|
||
+
|
||
+ /* Print the device name. */
|
||
+ grub_printf ("(%cd%d",
|
||
+ (current_drive & 0x80) ? 'h' : 'f',
|
||
+ current_drive & ~0x80);
|
||
+
|
||
+ if ((current_partition & 0xFF0000) != 0xFF0000)
|
||
+ grub_printf (",%d", (current_partition >> 16) & 0xFF);
|
||
+
|
||
+ if ((current_partition & 0x00FF00) != 0x00FF00)
|
||
+ grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF));
|
||
+
|
||
+ grub_printf (")");
|
||
+
|
||
+ /* Read in the whole file to DUMMY. */
|
||
+ disk_read_hook = disk_read_blocklist_func;
|
||
+ if (! grub_read (dummy, -1))
|
||
+ goto fail;
|
||
+
|
||
+ /* The last entry may not be printed yet. Don't check if it is a
|
||
+ * full sector, since it doesn't matter if we read too much. */
|
||
+ if (num_sectors > 0)
|
||
+ grub_printf ("%s%d+%d", num_entries ? "," : "",
|
||
+ start_sector - part_start, num_sectors);
|
||
+
|
||
+ grub_printf ("\n");
|
||
+
|
||
+ fail:
|
||
+ disk_read_hook = 0;
|
||
+ grub_close ();
|
||
+ return errnum;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_blocklist =
|
||
+{
|
||
+ "blocklist",
|
||
+ blocklist_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "blocklist FILE",
|
||
+ "Print the blocklist notation of the file FILE."
|
||
+};
|
||
+
|
||
+/* boot */
|
||
+static int
|
||
+boot_func (char *arg, int flags)
|
||
+{
|
||
+ /* Clear the int15 handler if we can boot the kernel successfully.
|
||
+ This assumes that the boot code never fails only if KERNEL_TYPE is
|
||
+ not KERNEL_TYPE_NONE. Is this assumption is bad? */
|
||
+ if (kernel_type != KERNEL_TYPE_NONE)
|
||
+ unset_int15_handler ();
|
||
+
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+ /* Shut down the networking. */
|
||
+ cleanup_net ();
|
||
+#endif
|
||
+
|
||
+ switch (kernel_type)
|
||
+ {
|
||
+ case KERNEL_TYPE_FREEBSD:
|
||
+ case KERNEL_TYPE_NETBSD:
|
||
+ /* *BSD */
|
||
+ bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline);
|
||
+ break;
|
||
+
|
||
+ case KERNEL_TYPE_LINUX:
|
||
+ /* Linux */
|
||
+ linux_boot ();
|
||
+ break;
|
||
+
|
||
+ case KERNEL_TYPE_BIG_LINUX:
|
||
+ /* Big Linux */
|
||
+ big_linux_boot ();
|
||
+ break;
|
||
+
|
||
+ case KERNEL_TYPE_CHAINLOADER:
|
||
+ /* Chainloader */
|
||
+
|
||
+ /* Check if we should set the int13 handler. */
|
||
+ if (bios_drive_map[0] != 0)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ /* Search for SAVED_DRIVE. */
|
||
+ for (i = 0; i < DRIVE_MAP_SIZE; i++)
|
||
+ {
|
||
+ if (! bios_drive_map[i])
|
||
+ break;
|
||
+ else if ((bios_drive_map[i] & 0xFF) == saved_drive)
|
||
+ {
|
||
+ /* Exchage SAVED_DRIVE with the mapped drive. */
|
||
+ saved_drive = (bios_drive_map[i] >> 8) & 0xFF;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Set the handler. This is somewhat dangerous. */
|
||
+ set_int13_handler (bios_drive_map);
|
||
+ }
|
||
+
|
||
+ gateA20 (0);
|
||
+ boot_drive = saved_drive;
|
||
+ chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr);
|
||
+ break;
|
||
+
|
||
+ case KERNEL_TYPE_MULTIBOOT:
|
||
+ /* Multiboot */
|
||
+ multi_boot ((int) entry_addr, (int) &mbi);
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ errnum = ERR_BOOT_COMMAND;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_boot =
|
||
+{
|
||
+ "boot",
|
||
+ boot_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "boot",
|
||
+ "Boot the OS/chain-loader which has been loaded."
|
||
+};
|
||
+
|
||
+
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+/* bootp */
|
||
+static int
|
||
+bootp_func (char *arg, int flags)
|
||
+{
|
||
+ int with_configfile = 0;
|
||
+
|
||
+ if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1)
|
||
+ == 0)
|
||
+ {
|
||
+ with_configfile = 1;
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+
|
||
+ if (! bootp ())
|
||
+ {
|
||
+ if (errnum == ERR_NONE)
|
||
+ errnum = ERR_DEV_VALUES;
|
||
+
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Notify the configuration. */
|
||
+ print_network_configuration ();
|
||
+
|
||
+ /* XXX: this can cause an endless loop, but there is no easy way to
|
||
+ detect such a loop unfortunately. */
|
||
+ if (with_configfile)
|
||
+ configfile_func (config_file, flags);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_bootp =
|
||
+{
|
||
+ "bootp",
|
||
+ bootp_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "bootp [--with-configfile]",
|
||
+ "Initialize a network device via BOOTP. If the option `--with-configfile'"
|
||
+ " is given, try to load a configuration file specified by the 150 vendor"
|
||
+ " tag."
|
||
+};
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+
|
||
+
|
||
+/* cat */
|
||
+static int
|
||
+cat_func (char *arg, int flags)
|
||
+{
|
||
+ char c;
|
||
+
|
||
+ if (! grub_open (arg))
|
||
+ return 1;
|
||
+
|
||
+ while (grub_read (&c, 1))
|
||
+ {
|
||
+ /* Because running "cat" with a binary file can confuse the terminal,
|
||
+ print only some characters as they are. */
|
||
+ if (grub_isspace (c) || (c >= ' ' && c <= '~'))
|
||
+ grub_putchar (c);
|
||
+ else
|
||
+ grub_putchar ('?');
|
||
+ }
|
||
+
|
||
+ grub_close ();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_cat =
|
||
+{
|
||
+ "cat",
|
||
+ cat_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "cat FILE",
|
||
+ "Print the contents of the file FILE."
|
||
+};
|
||
+
|
||
+
|
||
+/* chainloader */
|
||
+static int
|
||
+chainloader_func (char *arg, int flags)
|
||
+{
|
||
+ int force = 0;
|
||
+ char *file = arg;
|
||
+
|
||
+ /* If the option `--force' is specified? */
|
||
+ if (substring ("--force", arg) <= 0)
|
||
+ {
|
||
+ force = 1;
|
||
+ file = skip_to (0, arg);
|
||
+ }
|
||
+
|
||
+ /* Open the file. */
|
||
+ if (! grub_open (file))
|
||
+ {
|
||
+ kernel_type = KERNEL_TYPE_NONE;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Read the first block. */
|
||
+ if (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) != SECTOR_SIZE)
|
||
+ {
|
||
+ grub_close ();
|
||
+ kernel_type = KERNEL_TYPE_NONE;
|
||
+
|
||
+ /* This below happens, if a file whose size is less than 512 bytes
|
||
+ is loaded. */
|
||
+ if (errnum == ERR_NONE)
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* If not loading it forcibly, check for the signature. */
|
||
+ if (! force
|
||
+ && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET))
|
||
+ != BOOTSEC_SIGNATURE))
|
||
+ {
|
||
+ grub_close ();
|
||
+ errnum = ERR_EXEC_FORMAT;
|
||
+ kernel_type = KERNEL_TYPE_NONE;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ grub_close ();
|
||
+ kernel_type = KERNEL_TYPE_CHAINLOADER;
|
||
+
|
||
+ /* XXX: Windows evil hack. For now, only the first five letters are
|
||
+ checked. */
|
||
+ if (IS_PC_SLICE_TYPE_FAT (current_slice)
|
||
+ && ! grub_memcmp ((char *) BOOTSEC_LOCATION + BOOTSEC_BPB_SYSTEM_ID,
|
||
+ "MSWIN", 5))
|
||
+ *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS))
|
||
+ = part_start;
|
||
+
|
||
+ errnum = ERR_NONE;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_chainloader =
|
||
+{
|
||
+ "chainloader",
|
||
+ chainloader_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "chainloader [--force] FILE",
|
||
+ "Load the chain-loader FILE. If --force is specified, then load it"
|
||
+ " forcibly, whether the boot loader signature is present or not."
|
||
+};
|
||
+
|
||
+
|
||
+/* This function could be used to debug new filesystem code. Put a file
|
||
+ in the new filesystem and the same file in a well-tested filesystem.
|
||
+ Then, run "cmp" with the files. If no output is obtained, probably
|
||
+ the code is good, otherwise investigate what's wrong... */
|
||
+/* cmp FILE1 FILE2 */
|
||
+static int
|
||
+cmp_func (char *arg, int flags)
|
||
+{
|
||
+ /* The filenames. */
|
||
+ char *file1, *file2;
|
||
+ /* The addresses. */
|
||
+ char *addr1, *addr2;
|
||
+ int i;
|
||
+ /* The size of the file. */
|
||
+ int size;
|
||
+
|
||
+ /* Get the filenames from ARG. */
|
||
+ file1 = arg;
|
||
+ file2 = skip_to (0, arg);
|
||
+ if (! *file1 || ! *file2)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Terminate the filenames for convenience. */
|
||
+ nul_terminate (file1);
|
||
+ nul_terminate (file2);
|
||
+
|
||
+ /* Read the whole data from FILE1. */
|
||
+ addr1 = (char *) RAW_ADDR (0x100000);
|
||
+ if (! grub_open (file1))
|
||
+ return 1;
|
||
+
|
||
+ /* Get the size. */
|
||
+ size = filemax;
|
||
+ if (grub_read (addr1, -1) != size)
|
||
+ {
|
||
+ grub_close ();
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ grub_close ();
|
||
+
|
||
+ /* Read the whole data from FILE2. */
|
||
+ addr2 = addr1 + size;
|
||
+ if (! grub_open (file2))
|
||
+ return 1;
|
||
+
|
||
+ /* Check if the size of FILE2 is equal to the one of FILE2. */
|
||
+ if (size != filemax)
|
||
+ {
|
||
+ grub_printf ("Differ in size: 0x%x [%s], 0x%x [%s]\n",
|
||
+ size, file1, filemax, file2);
|
||
+ grub_close ();
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (! grub_read (addr2, -1))
|
||
+ {
|
||
+ grub_close ();
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ grub_close ();
|
||
+
|
||
+ /* Now compare ADDR1 with ADDR2. */
|
||
+ for (i = 0; i < size; i++)
|
||
+ {
|
||
+ if (addr1[i] != addr2[i])
|
||
+ grub_printf ("Differ at the offset %d: 0x%x [%s], 0x%x [%s]\n",
|
||
+ i, (unsigned) addr1[i], file1,
|
||
+ (unsigned) addr2[i], file2);
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_cmp =
|
||
+{
|
||
+ "cmp",
|
||
+ cmp_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "cmp FILE1 FILE2",
|
||
+ "Compare the file FILE1 with the FILE2 and inform the different values"
|
||
+ " if any."
|
||
+};
|
||
+
|
||
+
|
||
+/* color */
|
||
+/* Set new colors used for the menu interface. Support two methods to
|
||
+ specify a color name: a direct integer representation and a symbolic
|
||
+ color name. An example of the latter is "blink-light-gray/blue". */
|
||
+static int
|
||
+color_func (char *arg, int flags)
|
||
+{
|
||
+ char *normal;
|
||
+ char *highlight;
|
||
+ int new_normal_color;
|
||
+ int new_highlight_color;
|
||
+ static char *color_list[16] =
|
||
+ {
|
||
+ "black",
|
||
+ "blue",
|
||
+ "green",
|
||
+ "cyan",
|
||
+ "red",
|
||
+ "magenta",
|
||
+ "brown",
|
||
+ "light-gray",
|
||
+ "dark-gray",
|
||
+ "light-blue",
|
||
+ "light-green",
|
||
+ "light-cyan",
|
||
+ "light-red",
|
||
+ "light-magenta",
|
||
+ "yellow",
|
||
+ "white"
|
||
+ };
|
||
+
|
||
+ auto int color_number (char *str);
|
||
+
|
||
+ /* Convert the color name STR into the magical number. */
|
||
+ auto int color_number (char *str)
|
||
+ {
|
||
+ char *ptr;
|
||
+ int i;
|
||
+ int color = 0;
|
||
+
|
||
+ /* Find the separator. */
|
||
+ for (ptr = str; *ptr && *ptr != '/'; ptr++)
|
||
+ ;
|
||
+
|
||
+ /* If not found, return -1. */
|
||
+ if (! *ptr)
|
||
+ return -1;
|
||
+
|
||
+ /* Terminate the string STR. */
|
||
+ *ptr++ = 0;
|
||
+
|
||
+ /* If STR contains the prefix "blink-", then set the `blink' bit
|
||
+ in COLOR. */
|
||
+ if (substring ("blink-", str) <= 0)
|
||
+ {
|
||
+ color = 0x80;
|
||
+ str += 6;
|
||
+ }
|
||
+
|
||
+ /* Search for the color name. */
|
||
+ for (i = 0; i < 16; i++)
|
||
+ if (grub_strcmp (color_list[i], str) == 0)
|
||
+ {
|
||
+ color |= i;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (i == 16)
|
||
+ return -1;
|
||
+
|
||
+ str = ptr;
|
||
+ nul_terminate (str);
|
||
+
|
||
+ /* Search for the color name. */
|
||
+ for (i = 0; i < 8; i++)
|
||
+ if (grub_strcmp (color_list[i], str) == 0)
|
||
+ {
|
||
+ color |= i << 4;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (i == 8)
|
||
+ return -1;
|
||
+
|
||
+ return color;
|
||
+ }
|
||
+
|
||
+ normal = arg;
|
||
+ highlight = skip_to (0, arg);
|
||
+
|
||
+ new_normal_color = color_number (normal);
|
||
+ if (new_normal_color < 0 && ! safe_parse_maxint (&normal, &new_normal_color))
|
||
+ return 1;
|
||
+
|
||
+ /* The second argument is optional, so set highlight_color
|
||
+ to inverted NORMAL_COLOR. */
|
||
+ if (! *highlight)
|
||
+ new_highlight_color = ((new_normal_color >> 4)
|
||
+ | ((new_normal_color & 0xf) << 4));
|
||
+ else
|
||
+ {
|
||
+ new_highlight_color = color_number (highlight);
|
||
+ if (new_highlight_color < 0
|
||
+ && ! safe_parse_maxint (&highlight, &new_highlight_color))
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ if (current_term->setcolor)
|
||
+ current_term->setcolor (new_normal_color, new_highlight_color);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_color =
|
||
+{
|
||
+ "color",
|
||
+ color_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "color NORMAL [HIGHLIGHT]",
|
||
+ "Change the menu colors. The color NORMAL is used for most"
|
||
+ " lines in the menu, and the color HIGHLIGHT is used to highlight the"
|
||
+ " line where the cursor points. If you omit HIGHLIGHT, then the"
|
||
+ " inverted color of NORMAL is used for the highlighted line."
|
||
+ " The format of a color is \"FG/BG\". FG and BG are symbolic color names."
|
||
+ " A symbolic color name must be one of these: black, blue, green,"
|
||
+ " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
|
||
+ " light-green, light-cyan, light-red, light-magenta, yellow and white."
|
||
+ " But only the first eight names can be used for BG. You can prefix"
|
||
+ " \"blink-\" to FG if you want a blinking foreground color."
|
||
+};
|
||
+
|
||
+
|
||
+/* configfile */
|
||
+static int
|
||
+configfile_func (char *arg, int flags)
|
||
+{
|
||
+ char *new_config = config_file;
|
||
+
|
||
+ /* Check if the file ARG is present. */
|
||
+ if (! grub_open (arg))
|
||
+ return 1;
|
||
+
|
||
+ grub_close ();
|
||
+
|
||
+ /* Copy ARG to CONFIG_FILE. */
|
||
+ while ((*new_config++ = *arg++) != 0)
|
||
+ ;
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+ /* Force to load the configuration file. */
|
||
+ use_config_file = 1;
|
||
+#endif
|
||
+
|
||
+ /* Make sure that the user will not be authoritative. */
|
||
+ auth = 0;
|
||
+
|
||
+ /* Restart cmain. */
|
||
+ grub_longjmp (restart_env, 0);
|
||
+
|
||
+ /* Never reach here. */
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_configfile =
|
||
+{
|
||
+ "configfile",
|
||
+ configfile_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "configfile FILE",
|
||
+ "Load FILE as the configuration file."
|
||
+};
|
||
+
|
||
+
|
||
+/* debug */
|
||
+static int
|
||
+debug_func (char *arg, int flags)
|
||
+{
|
||
+ if (debug)
|
||
+ {
|
||
+ debug = 0;
|
||
+ grub_printf (" Debug mode is turned off\n");
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ debug = 1;
|
||
+ grub_printf (" Debug mode is turned on\n");
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_debug =
|
||
+{
|
||
+ "debug",
|
||
+ debug_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "debug",
|
||
+ "Turn on/off the debug mode."
|
||
+};
|
||
+
|
||
+
|
||
+/* default */
|
||
+static int
|
||
+default_func (char *arg, int flags)
|
||
+{
|
||
+#ifndef SUPPORT_DISKLESS
|
||
+ if (grub_strcmp (arg, "saved") == 0)
|
||
+ {
|
||
+ default_entry = saved_entryno;
|
||
+ return 0;
|
||
+ }
|
||
+#endif /* SUPPORT_DISKLESS */
|
||
+
|
||
+ if (! safe_parse_maxint (&arg, &default_entry))
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_default =
|
||
+{
|
||
+ "default",
|
||
+ default_func,
|
||
+ BUILTIN_MENU,
|
||
+#if 0
|
||
+ "default [NUM | `saved']",
|
||
+ "Set the default entry to entry number NUM (if not specified, it is"
|
||
+ " 0, the first entry) or the entry number saved by savedefault."
|
||
+#endif
|
||
+};
|
||
+
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+/* device */
|
||
+static int
|
||
+device_func (char *arg, int flags)
|
||
+{
|
||
+ char *drive = arg;
|
||
+ char *device;
|
||
+
|
||
+ /* Get the drive number from DRIVE. */
|
||
+ if (! set_device (drive))
|
||
+ return 1;
|
||
+
|
||
+ /* Get the device argument. */
|
||
+ device = skip_to (0, drive);
|
||
+
|
||
+ /* Terminate DEVICE. */
|
||
+ nul_terminate (device);
|
||
+
|
||
+ if (! *device || ! check_device (device))
|
||
+ {
|
||
+ errnum = ERR_FILE_NOT_FOUND;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ assign_device_name (current_drive, device);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_device =
|
||
+{
|
||
+ "device",
|
||
+ device_func,
|
||
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "device DRIVE DEVICE",
|
||
+ "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command"
|
||
+ " can be used only in the grub shell."
|
||
+};
|
||
+#endif /* GRUB_UTIL */
|
||
+
|
||
+
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+/* dhcp */
|
||
+static int
|
||
+dhcp_func (char *arg, int flags)
|
||
+{
|
||
+ /* For now, this is an alias for bootp. */
|
||
+ return bootp_func (arg, flags);
|
||
+}
|
||
+
|
||
+static struct builtin builtin_dhcp =
|
||
+{
|
||
+ "dhcp",
|
||
+ dhcp_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "dhcp",
|
||
+ "Initialize a network device via DHCP."
|
||
+};
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+
|
||
+
|
||
+/* displayapm */
|
||
+static int
|
||
+displayapm_func (char *arg, int flags)
|
||
+{
|
||
+ if (mbi.flags & MB_INFO_APM_TABLE)
|
||
+ {
|
||
+ grub_printf ("APM BIOS information:\n"
|
||
+ " Version: 0x%x\n"
|
||
+ " 32-bit CS: 0x%x\n"
|
||
+ " Offset: 0x%x\n"
|
||
+ " 16-bit CS: 0x%x\n"
|
||
+ " 16-bit DS: 0x%x\n"
|
||
+ " 32-bit CS length: 0x%x\n"
|
||
+ " 16-bit CS length: 0x%x\n"
|
||
+ " 16-bit DS length: 0x%x\n",
|
||
+ (unsigned) apm_bios_info.version,
|
||
+ (unsigned) apm_bios_info.cseg,
|
||
+ apm_bios_info.offset,
|
||
+ (unsigned) apm_bios_info.cseg_16,
|
||
+ (unsigned) apm_bios_info.dseg_16,
|
||
+ (unsigned) apm_bios_info.cseg_len,
|
||
+ (unsigned) apm_bios_info.cseg_16_len,
|
||
+ (unsigned) apm_bios_info.dseg_16_len);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ grub_printf ("No APM BIOS found or probe failed\n");
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_displayapm =
|
||
+{
|
||
+ "displayapm",
|
||
+ displayapm_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "displayapm",
|
||
+ "Display APM BIOS information."
|
||
+};
|
||
+
|
||
+
|
||
+/* displaymem */
|
||
+static int
|
||
+displaymem_func (char *arg, int flags)
|
||
+{
|
||
+ if (get_eisamemsize () != -1)
|
||
+ grub_printf (" EISA Memory BIOS Interface is present\n");
|
||
+ if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0
|
||
+ || *((int *) SCRATCHADDR) != 0)
|
||
+ grub_printf (" Address Map BIOS Interface is present\n");
|
||
+
|
||
+ grub_printf (" Lower memory: %uK, "
|
||
+ "Upper memory (to first chipset hole): %uK\n",
|
||
+ mbi.mem_lower, mbi.mem_upper);
|
||
+
|
||
+ if (mbi.flags & MB_INFO_MEM_MAP)
|
||
+ {
|
||
+ struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr;
|
||
+ int end_addr = mbi.mmap_addr + mbi.mmap_length;
|
||
+
|
||
+ grub_printf (" [Address Range Descriptor entries "
|
||
+ "immediately follow (values are 64-bit)]\n");
|
||
+ while (end_addr > (int) map)
|
||
+ {
|
||
+ char *str;
|
||
+
|
||
+ if (map->Type == MB_ARD_MEMORY)
|
||
+ str = "Usable RAM";
|
||
+ else
|
||
+ str = "Reserved";
|
||
+ grub_printf (" %s: Base Address: 0x%x X 4GB + 0x%x,\n"
|
||
+ " Length: 0x%x X 4GB + 0x%x bytes\n",
|
||
+ str,
|
||
+ (unsigned long) (map->BaseAddr >> 32),
|
||
+ (unsigned long) (map->BaseAddr & 0xFFFFFFFF),
|
||
+ (unsigned long) (map->Length >> 32),
|
||
+ (unsigned long) (map->Length & 0xFFFFFFFF));
|
||
+
|
||
+ map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size));
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_displaymem =
|
||
+{
|
||
+ "displaymem",
|
||
+ displaymem_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "displaymem",
|
||
+ "Display what GRUB thinks the system address space map of the"
|
||
+ " machine is, including all regions of physical RAM installed."
|
||
+};
|
||
+
|
||
+
|
||
+/* dump FROM TO */
|
||
+#ifdef GRUB_UTIL
|
||
+static int
|
||
+dump_func (char *arg, int flags)
|
||
+{
|
||
+ char *from, *to;
|
||
+ FILE *fp;
|
||
+ char c;
|
||
+
|
||
+ from = arg;
|
||
+ to = skip_to (0, arg);
|
||
+ if (! *from || ! *to)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ nul_terminate (from);
|
||
+ nul_terminate (to);
|
||
+
|
||
+ if (! grub_open (from))
|
||
+ return 1;
|
||
+
|
||
+ fp = fopen (to, "w");
|
||
+ if (! fp)
|
||
+ {
|
||
+ errnum = ERR_WRITE;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ while (grub_read (&c, 1))
|
||
+ if (fputc (c, fp) == EOF)
|
||
+ {
|
||
+ errnum = ERR_WRITE;
|
||
+ fclose (fp);
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ if (fclose (fp) == EOF)
|
||
+ {
|
||
+ errnum = ERR_WRITE;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ grub_close ();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_dump =
|
||
+ {
|
||
+ "dump",
|
||
+ dump_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "dump FROM TO",
|
||
+ "Dump the contents of the file FROM to the file TO. FROM must be"
|
||
+ " a GRUB file and TO must be an OS file."
|
||
+ };
|
||
+#endif /* GRUB_UTIL */
|
||
+
|
||
+
|
||
+static char embed_info[32];
|
||
+/* embed */
|
||
+/* Embed a Stage 1.5 in the first cylinder after MBR or in the
|
||
+ bootloader block in a FFS. */
|
||
+static int
|
||
+embed_func (char *arg, int flags)
|
||
+{
|
||
+ char *stage1_5;
|
||
+ char *device;
|
||
+ char *stage1_5_buffer = (char *) RAW_ADDR (0x100000);
|
||
+ int len, size;
|
||
+ int sector;
|
||
+
|
||
+ stage1_5 = arg;
|
||
+ device = skip_to (0, stage1_5);
|
||
+
|
||
+ /* Open a Stage 1.5. */
|
||
+ if (! grub_open (stage1_5))
|
||
+ return 1;
|
||
+
|
||
+ /* Read the whole of the Stage 1.5. */
|
||
+ len = grub_read (stage1_5_buffer, -1);
|
||
+ grub_close ();
|
||
+
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+
|
||
+ size = (len + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
||
+
|
||
+ /* Get the device where the Stage 1.5 will be embedded. */
|
||
+ set_device (device);
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+
|
||
+ if (current_partition == 0xFFFFFF)
|
||
+ {
|
||
+ /* Embed it after the MBR. */
|
||
+
|
||
+ char mbr[SECTOR_SIZE];
|
||
+ char ezbios_check[2*SECTOR_SIZE];
|
||
+ int i;
|
||
+
|
||
+ /* Open the partition. */
|
||
+ if (! open_partition ())
|
||
+ return 1;
|
||
+
|
||
+ /* No floppy has MBR. */
|
||
+ if (! (current_drive & 0x80))
|
||
+ {
|
||
+ errnum = ERR_DEV_VALUES;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Read the MBR of CURRENT_DRIVE. */
|
||
+ if (! rawread (current_drive, PC_MBR_SECTOR, 0, SECTOR_SIZE, mbr))
|
||
+ return 1;
|
||
+
|
||
+ /* Sanity check. */
|
||
+ if (! PC_MBR_CHECK_SIG (mbr))
|
||
+ {
|
||
+ errnum = ERR_BAD_PART_TABLE;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Check if the disk can store the Stage 1.5. */
|
||
+ for (i = 0; i < 4; i++)
|
||
+ if (PC_SLICE_TYPE (mbr, i) && PC_SLICE_START (mbr, i) - 1 < size)
|
||
+ {
|
||
+ errnum = ERR_NO_DISK_SPACE;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Check for EZ-BIOS signature. It should be in the third
|
||
+ * sector, but due to remapping it can appear in the second, so
|
||
+ * load and check both.
|
||
+ */
|
||
+ if (! rawread (current_drive, 1, 0, 2 * SECTOR_SIZE, ezbios_check))
|
||
+ return 1;
|
||
+
|
||
+ if (! memcmp (ezbios_check + 3, "AERMH", 5)
|
||
+ || ! memcmp (ezbios_check + 512 + 3, "AERMH", 5))
|
||
+ {
|
||
+ /* The space after the MBR is used by EZ-BIOS which we must
|
||
+ * not overwrite.
|
||
+ */
|
||
+ errnum = ERR_NO_DISK_SPACE;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ sector = 1;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Embed it in the bootloader block in the filesystem. */
|
||
+ int start_sector;
|
||
+
|
||
+ /* Open the partition. */
|
||
+ if (! open_device ())
|
||
+ return 1;
|
||
+
|
||
+ /* Check if the current slice supports embedding. */
|
||
+ if (fsys_table[fsys_type].embed_func == 0
|
||
+ || ! fsys_table[fsys_type].embed_func (&start_sector, size))
|
||
+ {
|
||
+ errnum = ERR_DEV_VALUES;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ sector = part_start + start_sector;
|
||
+ }
|
||
+
|
||
+ /* Clear the cache. */
|
||
+ buf_track = -1;
|
||
+
|
||
+ /* Now perform the embedding. */
|
||
+ if (! devwrite (sector - part_start, size, stage1_5_buffer))
|
||
+ return 1;
|
||
+
|
||
+ grub_printf (" %d sectors are embedded.\n", size);
|
||
+ grub_sprintf (embed_info, "%d+%d", sector - part_start, size);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_embed =
|
||
+{
|
||
+ "embed",
|
||
+ embed_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "embed STAGE1_5 DEVICE",
|
||
+ "Embed the Stage 1.5 STAGE1_5 in the sectors after MBR if DEVICE"
|
||
+ " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition."
|
||
+ " Print the number of sectors which STAGE1_5 occupies if successful."
|
||
+};
|
||
+
|
||
+
|
||
+/* fallback */
|
||
+static int
|
||
+fallback_func (char *arg, int flags)
|
||
+{
|
||
+ int i = 0;
|
||
+
|
||
+ while (*arg)
|
||
+ {
|
||
+ int entry;
|
||
+ int j;
|
||
+
|
||
+ if (! safe_parse_maxint (&arg, &entry))
|
||
+ return 1;
|
||
+
|
||
+ /* Remove duplications to prevent infinite looping. */
|
||
+ for (j = 0; j < i; j++)
|
||
+ if (entry == fallback_entries[j])
|
||
+ break;
|
||
+ if (j != i)
|
||
+ continue;
|
||
+
|
||
+ fallback_entries[i++] = entry;
|
||
+ if (i == MAX_FALLBACK_ENTRIES)
|
||
+ break;
|
||
+
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+
|
||
+ if (i < MAX_FALLBACK_ENTRIES)
|
||
+ fallback_entries[i] = -1;
|
||
+
|
||
+ fallback_entryno = (i == 0) ? -1 : 0;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_fallback =
|
||
+{
|
||
+ "fallback",
|
||
+ fallback_func,
|
||
+ BUILTIN_MENU,
|
||
+#if 0
|
||
+ "fallback NUM...",
|
||
+ "Go into unattended boot mode: if the default boot entry has any"
|
||
+ " errors, instead of waiting for the user to do anything, it"
|
||
+ " immediately starts over using the NUM entry (same numbering as the"
|
||
+ " `default' command). This obviously won't help if the machine"
|
||
+ " was rebooted by a kernel that GRUB loaded."
|
||
+#endif
|
||
+};
|
||
+
|
||
+
|
||
+/* find */
|
||
+/* Search for the filename ARG in all of partitions. */
|
||
+static int
|
||
+find_func (char *arg, int flags)
|
||
+{
|
||
+ char *filename = arg;
|
||
+ unsigned long drive;
|
||
+ unsigned long tmp_drive = saved_drive;
|
||
+ unsigned long tmp_partition = saved_partition;
|
||
+ int got_file = 0;
|
||
+
|
||
+ /* Floppies. */
|
||
+ for (drive = 0; drive < 8; drive++)
|
||
+ {
|
||
+ current_drive = drive;
|
||
+ current_partition = 0xFFFFFF;
|
||
+
|
||
+ if (open_device ())
|
||
+ {
|
||
+ saved_drive = current_drive;
|
||
+ saved_partition = current_partition;
|
||
+ if (grub_open (filename))
|
||
+ {
|
||
+ grub_close ();
|
||
+ grub_printf (" (fd%d)\n", drive);
|
||
+ got_file = 1;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ errnum = ERR_NONE;
|
||
+ }
|
||
+
|
||
+ /* Hard disks. */
|
||
+ for (drive = 0x80; drive < 0x88; drive++)
|
||
+ {
|
||
+ unsigned long part = 0xFFFFFF;
|
||
+ unsigned long start, len, offset, ext_offset;
|
||
+ int type, entry;
|
||
+ char buf[SECTOR_SIZE];
|
||
+
|
||
+ current_drive = drive;
|
||
+ while (next_partition (drive, 0xFFFFFF, &part, &type,
|
||
+ &start, &len, &offset, &entry,
|
||
+ &ext_offset, buf))
|
||
+ {
|
||
+ if (type != PC_SLICE_TYPE_NONE
|
||
+ && ! IS_PC_SLICE_TYPE_BSD (type)
|
||
+ && ! IS_PC_SLICE_TYPE_EXTENDED (type))
|
||
+ {
|
||
+ current_partition = part;
|
||
+ if (open_device ())
|
||
+ {
|
||
+ saved_drive = current_drive;
|
||
+ saved_partition = current_partition;
|
||
+ if (grub_open (filename))
|
||
+ {
|
||
+ int bsd_part = (part >> 8) & 0xFF;
|
||
+ int pc_slice = part >> 16;
|
||
+
|
||
+ grub_close ();
|
||
+
|
||
+ if (bsd_part == 0xFF)
|
||
+ grub_printf (" (hd%d,%d)\n",
|
||
+ drive - 0x80, pc_slice);
|
||
+ else
|
||
+ grub_printf (" (hd%d,%d,%c)\n",
|
||
+ drive - 0x80, pc_slice, bsd_part + 'a');
|
||
+
|
||
+ got_file = 1;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* We want to ignore any error here. */
|
||
+ errnum = ERR_NONE;
|
||
+ }
|
||
+
|
||
+ /* next_partition always sets ERRNUM in the last call, so clear
|
||
+ it. */
|
||
+ errnum = ERR_NONE;
|
||
+ }
|
||
+
|
||
+ saved_drive = tmp_drive;
|
||
+ saved_partition = tmp_partition;
|
||
+
|
||
+ if (got_file)
|
||
+ {
|
||
+ errnum = ERR_NONE;
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ errnum = ERR_FILE_NOT_FOUND;
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_find =
|
||
+{
|
||
+ "find",
|
||
+ find_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "find FILENAME",
|
||
+ "Search for the filename FILENAME in all of partitions and print the list of"
|
||
+ " the devices which contain the file."
|
||
+};
|
||
+
|
||
+
|
||
+/* fstest */
|
||
+static int
|
||
+fstest_func (char *arg, int flags)
|
||
+{
|
||
+ if (disk_read_hook)
|
||
+ {
|
||
+ disk_read_hook = NULL;
|
||
+ printf (" Filesystem tracing is now off\n");
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ disk_read_hook = disk_read_print_func;
|
||
+ printf (" Filesystem tracing is now on\n");
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_fstest =
|
||
+{
|
||
+ "fstest",
|
||
+ fstest_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "fstest",
|
||
+ "Toggle filesystem test mode."
|
||
+};
|
||
+
|
||
+
|
||
+/* geometry */
|
||
+static int
|
||
+geometry_func (char *arg, int flags)
|
||
+{
|
||
+ struct geometry geom;
|
||
+ char *msg;
|
||
+ char *device = arg;
|
||
+#ifdef GRUB_UTIL
|
||
+ char *ptr;
|
||
+#endif
|
||
+
|
||
+ /* Get the device number. */
|
||
+ set_device (device);
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+
|
||
+ /* Check for the geometry. */
|
||
+ if (get_diskinfo (current_drive, &geom))
|
||
+ {
|
||
+ errnum = ERR_NO_DISK;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Attempt to read the first sector, because some BIOSes turns out not
|
||
+ to support LBA even though they set the bit 0 in the support
|
||
+ bitmap, only after reading something actually. */
|
||
+ if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG))
|
||
+ {
|
||
+ errnum = ERR_READ;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+ ptr = skip_to (0, device);
|
||
+ if (*ptr)
|
||
+ {
|
||
+ char *cylinder, *head, *sector, *total_sector;
|
||
+ int num_cylinder, num_head, num_sector, num_total_sector;
|
||
+
|
||
+ cylinder = ptr;
|
||
+ head = skip_to (0, cylinder);
|
||
+ sector = skip_to (0, head);
|
||
+ total_sector = skip_to (0, sector);
|
||
+ if (! safe_parse_maxint (&cylinder, &num_cylinder)
|
||
+ || ! safe_parse_maxint (&head, &num_head)
|
||
+ || ! safe_parse_maxint (§or, &num_sector))
|
||
+ return 1;
|
||
+
|
||
+ disks[current_drive].cylinders = num_cylinder;
|
||
+ disks[current_drive].heads = num_head;
|
||
+ disks[current_drive].sectors = num_sector;
|
||
+
|
||
+ if (safe_parse_maxint (&total_sector, &num_total_sector))
|
||
+ disks[current_drive].total_sectors = num_total_sector;
|
||
+ else
|
||
+ disks[current_drive].total_sectors
|
||
+ = num_cylinder * num_head * num_sector;
|
||
+ errnum = 0;
|
||
+
|
||
+ geom = disks[current_drive];
|
||
+ buf_drive = -1;
|
||
+ }
|
||
+#endif /* GRUB_UTIL */
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+ msg = device_map[current_drive];
|
||
+#else
|
||
+ if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)
|
||
+ msg = "LBA";
|
||
+ else
|
||
+ msg = "CHS";
|
||
+#endif
|
||
+
|
||
+ grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, "
|
||
+ "The number of sectors = %d, %s\n",
|
||
+ current_drive,
|
||
+ geom.cylinders, geom.heads, geom.sectors,
|
||
+ geom.total_sectors, msg);
|
||
+ real_open_partition (1);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_geometry =
|
||
+{
|
||
+ "geometry",
|
||
+ geometry_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "geometry DRIVE [CYLINDER HEAD SECTOR [TOTAL_SECTOR]]",
|
||
+ "Print the information for a drive DRIVE. In the grub shell, you can"
|
||
+ " set the geometry of the drive arbitrarily. The number of the cylinders,"
|
||
+ " the one of the heads, the one of the sectors and the one of the total"
|
||
+ " sectors are set to CYLINDER, HEAD, SECTOR and TOTAL_SECTOR,"
|
||
+ " respectively. If you omit TOTAL_SECTOR, then it will be calculated based"
|
||
+ " on the C/H/S values automatically."
|
||
+};
|
||
+
|
||
+
|
||
+/* halt */
|
||
+static int
|
||
+halt_func (char *arg, int flags)
|
||
+{
|
||
+ int no_apm;
|
||
+
|
||
+ no_apm = (grub_memcmp (arg, "--no-apm", 8) == 0);
|
||
+ grub_halt (no_apm);
|
||
+
|
||
+ /* Never reach here. */
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_halt =
|
||
+{
|
||
+ "halt",
|
||
+ halt_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "halt [--no-apm]",
|
||
+ "Halt your system. If APM is avaiable on it, turn off the power using"
|
||
+ " the APM BIOS, unless you specify the option `--no-apm'."
|
||
+};
|
||
+
|
||
+
|
||
+/* help */
|
||
+#define MAX_SHORT_DOC_LEN 39
|
||
+#define MAX_LONG_DOC_LEN 66
|
||
+
|
||
+static int
|
||
+help_func (char *arg, int flags)
|
||
+{
|
||
+ int all = 0;
|
||
+
|
||
+ if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0)
|
||
+ {
|
||
+ all = 1;
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+
|
||
+ if (! *arg)
|
||
+ {
|
||
+ /* Invoked with no argument. Print the list of the short docs. */
|
||
+ struct builtin **builtin;
|
||
+ int left = 1;
|
||
+
|
||
+ for (builtin = builtin_table; *builtin != 0; builtin++)
|
||
+ {
|
||
+ int len;
|
||
+ int i;
|
||
+
|
||
+ /* If this cannot be used in the command-line interface,
|
||
+ skip this. */
|
||
+ if (! ((*builtin)->flags & BUILTIN_CMDLINE))
|
||
+ continue;
|
||
+
|
||
+ /* If this doesn't need to be listed automatically and "--all"
|
||
+ is not specified, skip this. */
|
||
+ if (! all && ! ((*builtin)->flags & BUILTIN_HELP_LIST))
|
||
+ continue;
|
||
+
|
||
+ len = grub_strlen ((*builtin)->short_doc);
|
||
+ /* If the length of SHORT_DOC is too long, truncate it. */
|
||
+ if (len > MAX_SHORT_DOC_LEN - 1)
|
||
+ len = MAX_SHORT_DOC_LEN - 1;
|
||
+
|
||
+ for (i = 0; i < len; i++)
|
||
+ grub_putchar ((*builtin)->short_doc[i]);
|
||
+
|
||
+ for (; i < MAX_SHORT_DOC_LEN; i++)
|
||
+ grub_putchar (' ');
|
||
+
|
||
+ if (! left)
|
||
+ grub_putchar ('\n');
|
||
+
|
||
+ left = ! left;
|
||
+ }
|
||
+
|
||
+ /* If the last entry was at the left column, no newline was printed
|
||
+ at the end. */
|
||
+ if (! left)
|
||
+ grub_putchar ('\n');
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Invoked with one or more patterns. */
|
||
+ do
|
||
+ {
|
||
+ struct builtin **builtin;
|
||
+ char *next_arg;
|
||
+
|
||
+ /* Get the next argument. */
|
||
+ next_arg = skip_to (0, arg);
|
||
+
|
||
+ /* Terminate ARG. */
|
||
+ nul_terminate (arg);
|
||
+
|
||
+ for (builtin = builtin_table; *builtin; builtin++)
|
||
+ {
|
||
+ /* Skip this if this is only for the configuration file. */
|
||
+ if (! ((*builtin)->flags & BUILTIN_CMDLINE))
|
||
+ continue;
|
||
+
|
||
+ if (substring (arg, (*builtin)->name) < 1)
|
||
+ {
|
||
+ char *doc = (*builtin)->long_doc;
|
||
+
|
||
+ /* At first, print the name and the short doc. */
|
||
+ grub_printf ("%s: %s\n",
|
||
+ (*builtin)->name, (*builtin)->short_doc);
|
||
+
|
||
+ /* Print the long doc. */
|
||
+ while (*doc)
|
||
+ {
|
||
+ int len = grub_strlen (doc);
|
||
+ int i;
|
||
+
|
||
+ /* If LEN is too long, fold DOC. */
|
||
+ if (len > MAX_LONG_DOC_LEN)
|
||
+ {
|
||
+ /* Fold this line at the position of a space. */
|
||
+ for (len = MAX_LONG_DOC_LEN; len > 0; len--)
|
||
+ if (doc[len - 1] == ' ')
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ grub_printf (" ");
|
||
+ for (i = 0; i < len; i++)
|
||
+ grub_putchar (*doc++);
|
||
+ grub_putchar ('\n');
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ arg = next_arg;
|
||
+ }
|
||
+ while (*arg);
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_help =
|
||
+{
|
||
+ "help",
|
||
+ help_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "help [--all] [PATTERN ...]",
|
||
+ "Display helpful information about builtin commands. Not all commands"
|
||
+ " aren't shown without the option `--all'."
|
||
+};
|
||
+
|
||
+
|
||
+/* hiddenmenu */
|
||
+static int
|
||
+hiddenmenu_func (char *arg, int flags)
|
||
+{
|
||
+ show_menu = 0;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_hiddenmenu =
|
||
+{
|
||
+ "hiddenmenu",
|
||
+ hiddenmenu_func,
|
||
+ BUILTIN_MENU,
|
||
+#if 0
|
||
+ "hiddenmenu",
|
||
+ "Hide the menu."
|
||
+#endif
|
||
+};
|
||
+
|
||
+
|
||
+/* hide */
|
||
+static int
|
||
+hide_func (char *arg, int flags)
|
||
+{
|
||
+ if (! set_device (arg))
|
||
+ return 1;
|
||
+
|
||
+ if (! set_partition_hidden_flag (1))
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_hide =
|
||
+{
|
||
+ "hide",
|
||
+ hide_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "hide PARTITION",
|
||
+ "Hide PARTITION by setting the \"hidden\" bit in"
|
||
+ " its partition type code."
|
||
+};
|
||
+
|
||
+
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+/* ifconfig */
|
||
+static int
|
||
+ifconfig_func (char *arg, int flags)
|
||
+{
|
||
+ char *svr = 0, *ip = 0, *gw = 0, *sm = 0;
|
||
+
|
||
+ if (! eth_probe ())
|
||
+ {
|
||
+ grub_printf ("No ethernet card found.\n");
|
||
+ errnum = ERR_DEV_VALUES;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ while (*arg)
|
||
+ {
|
||
+ if (! grub_memcmp ("--server=", arg, sizeof ("--server=") - 1))
|
||
+ svr = arg + sizeof("--server=") - 1;
|
||
+ else if (! grub_memcmp ("--address=", arg, sizeof ("--address=") - 1))
|
||
+ ip = arg + sizeof ("--address=") - 1;
|
||
+ else if (! grub_memcmp ("--gateway=", arg, sizeof ("--gateway=") - 1))
|
||
+ gw = arg + sizeof ("--gateway=") - 1;
|
||
+ else if (! grub_memcmp ("--mask=", arg, sizeof("--mask=") - 1))
|
||
+ sm = arg + sizeof ("--mask=") - 1;
|
||
+ else
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+
|
||
+ if (! ifconfig (ip, sm, gw, svr))
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ print_network_configuration ();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_ifconfig =
|
||
+{
|
||
+ "ifconfig",
|
||
+ ifconfig_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "ifconfig [--address=IP] [--gateway=IP] [--mask=MASK] [--server=IP]",
|
||
+ "Configure the IP address, the netmask, the gateway and the server"
|
||
+ " address or print current network configuration."
|
||
+};
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+
|
||
+
|
||
+/* impsprobe */
|
||
+static int
|
||
+impsprobe_func (char *arg, int flags)
|
||
+{
|
||
+#ifdef GRUB_UTIL
|
||
+ /* In the grub shell, we cannot probe IMPS. */
|
||
+ errnum = ERR_UNRECOGNIZED;
|
||
+ return 1;
|
||
+#else /* ! GRUB_UTIL */
|
||
+ if (!imps_probe ())
|
||
+ printf (" No MPS information found or probe failed\n");
|
||
+
|
||
+ return 0;
|
||
+#endif /* ! GRUB_UTIL */
|
||
+}
|
||
+
|
||
+static struct builtin builtin_impsprobe =
|
||
+{
|
||
+ "impsprobe",
|
||
+ impsprobe_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "impsprobe",
|
||
+ "Probe the Intel Multiprocessor Specification 1.1 or 1.4"
|
||
+ " configuration table and boot the various CPUs which are found into"
|
||
+ " a tight loop."
|
||
+};
|
||
+
|
||
+
|
||
+/* initrd */
|
||
+static int
|
||
+initrd_func (char *arg, int flags)
|
||
+{
|
||
+ switch (kernel_type)
|
||
+ {
|
||
+ case KERNEL_TYPE_LINUX:
|
||
+ case KERNEL_TYPE_BIG_LINUX:
|
||
+ if (! load_initrd (arg))
|
||
+ return 1;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ errnum = ERR_NEED_LX_KERNEL;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_initrd =
|
||
+{
|
||
+ "initrd",
|
||
+ initrd_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "initrd FILE [ARG ...]",
|
||
+ "Load an initial ramdisk FILE for a Linux format boot image and set the"
|
||
+ " appropriate parameters in the Linux setup area in memory."
|
||
+};
|
||
+
|
||
+
|
||
+/* install */
|
||
+static int
|
||
+install_func (char *arg, int flags)
|
||
+{
|
||
+ char *stage1_file, *dest_dev, *file, *addr;
|
||
+ char *stage1_buffer = (char *) RAW_ADDR (0x100000);
|
||
+ char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
|
||
+ char *old_sect = stage2_buffer + SECTOR_SIZE;
|
||
+ char *stage2_first_buffer = old_sect + SECTOR_SIZE;
|
||
+ char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
|
||
+ /* XXX: Probably SECTOR_SIZE is reasonable. */
|
||
+ char *config_filename = stage2_second_buffer + SECTOR_SIZE;
|
||
+ char *dummy = config_filename + SECTOR_SIZE;
|
||
+ int new_drive = GRUB_INVALID_DRIVE;
|
||
+ int dest_drive, dest_partition, dest_sector;
|
||
+ int src_drive, src_partition, src_part_start;
|
||
+ int i;
|
||
+ struct geometry dest_geom, src_geom;
|
||
+ int saved_sector;
|
||
+ int stage2_first_sector, stage2_second_sector;
|
||
+ char *ptr;
|
||
+ int installaddr, installlist;
|
||
+ /* Point to the location of the name of a configuration file in Stage 2. */
|
||
+ char *config_file_location;
|
||
+ /* If FILE is a Stage 1.5? */
|
||
+ int is_stage1_5 = 0;
|
||
+ /* Must call grub_close? */
|
||
+ int is_open = 0;
|
||
+ /* If LBA is forced? */
|
||
+ int is_force_lba = 0;
|
||
+ /* Was the last sector full? */
|
||
+ int last_length = SECTOR_SIZE;
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+ /* If the Stage 2 is in a partition mounted by an OS, this will store
|
||
+ the filename under the OS. */
|
||
+ char *stage2_os_file = 0;
|
||
+#endif /* GRUB_UTIL */
|
||
+
|
||
+ auto void disk_read_savesect_func (int sector, int offset, int length);
|
||
+ auto void disk_read_blocklist_func (int sector, int offset, int length);
|
||
+
|
||
+ /* Save the first sector of Stage2 in STAGE2_SECT. */
|
||
+ auto void disk_read_savesect_func (int sector, int offset, int length)
|
||
+ {
|
||
+ if (debug)
|
||
+ printf ("[%d]", sector);
|
||
+
|
||
+ /* ReiserFS has files which sometimes contain data not aligned
|
||
+ on sector boundaries. Returning an error is better than
|
||
+ silently failing. */
|
||
+ if (offset != 0 || length != SECTOR_SIZE)
|
||
+ errnum = ERR_UNALIGNED;
|
||
+
|
||
+ saved_sector = sector;
|
||
+ }
|
||
+
|
||
+ /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
|
||
+ INSTALLSECT. */
|
||
+ auto void disk_read_blocklist_func (int sector, int offset, int length)
|
||
+ {
|
||
+ if (debug)
|
||
+ printf("[%d]", sector);
|
||
+
|
||
+ if (offset != 0 || last_length != SECTOR_SIZE)
|
||
+ {
|
||
+ /* We found a non-sector-aligned data block. */
|
||
+ errnum = ERR_UNALIGNED;
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ last_length = length;
|
||
+
|
||
+ if (*((unsigned long *) (installlist - 4))
|
||
+ + *((unsigned short *) installlist) != sector
|
||
+ || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
|
||
+ {
|
||
+ installlist -= 8;
|
||
+
|
||
+ if (*((unsigned long *) (installlist - 8)))
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ else
|
||
+ {
|
||
+ *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
|
||
+ *((unsigned long *) (installlist - 4)) = sector;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ *((unsigned short *) installlist) += 1;
|
||
+ installaddr += 512;
|
||
+ }
|
||
+
|
||
+ /* First, check the GNU-style long option. */
|
||
+ while (1)
|
||
+ {
|
||
+ if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
|
||
+ {
|
||
+ is_force_lba = 1;
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+#ifdef GRUB_UTIL
|
||
+ else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
|
||
+ {
|
||
+ stage2_os_file = arg + sizeof ("--stage2=") - 1;
|
||
+ arg = skip_to (0, arg);
|
||
+ nul_terminate (stage2_os_file);
|
||
+ }
|
||
+#endif /* GRUB_UTIL */
|
||
+ else
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ stage1_file = arg;
|
||
+ dest_dev = skip_to (0, stage1_file);
|
||
+ if (*dest_dev == 'd')
|
||
+ {
|
||
+ new_drive = 0;
|
||
+ dest_dev = skip_to (0, dest_dev);
|
||
+ }
|
||
+ file = skip_to (0, dest_dev);
|
||
+ addr = skip_to (0, file);
|
||
+
|
||
+ /* Get the installation address. */
|
||
+ if (! safe_parse_maxint (&addr, &installaddr))
|
||
+ {
|
||
+ /* ADDR is not specified. */
|
||
+ installaddr = 0;
|
||
+ ptr = addr;
|
||
+ errnum = 0;
|
||
+ }
|
||
+ else
|
||
+ ptr = skip_to (0, addr);
|
||
+
|
||
+#ifndef NO_DECOMPRESSION
|
||
+ /* Do not decompress Stage 1 or Stage 2. */
|
||
+ no_decompression = 1;
|
||
+#endif
|
||
+
|
||
+ /* Read Stage 1. */
|
||
+ is_open = grub_open (stage1_file);
|
||
+ if (! is_open
|
||
+ || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE)
|
||
+ goto fail;
|
||
+
|
||
+ /* Read the old sector from DEST_DEV. */
|
||
+ if (! set_device (dest_dev)
|
||
+ || ! open_partition ()
|
||
+ || ! devread (0, 0, SECTOR_SIZE, old_sect))
|
||
+ goto fail;
|
||
+
|
||
+ /* Store the information for the destination device. */
|
||
+ dest_drive = current_drive;
|
||
+ dest_partition = current_partition;
|
||
+ dest_geom = buf_geom;
|
||
+ dest_sector = part_start;
|
||
+
|
||
+ /* Copy the possible DOS BPB, 59 bytes at byte offset 3. */
|
||
+ grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET,
|
||
+ old_sect + BOOTSEC_BPB_OFFSET,
|
||
+ BOOTSEC_BPB_LENGTH);
|
||
+
|
||
+ /* If for a hard disk, copy the possible MBR/extended part table. */
|
||
+ if (dest_drive & 0x80)
|
||
+ grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC,
|
||
+ old_sect + STAGE1_WINDOWS_NT_MAGIC,
|
||
+ STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC);
|
||
+
|
||
+ /* Check for the version and the signature of Stage 1. */
|
||
+ if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION
|
||
+ || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET))
|
||
+ != BOOTSEC_SIGNATURE))
|
||
+ {
|
||
+ errnum = ERR_BAD_VERSION;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* This below is not true any longer. But should we leave this alone? */
|
||
+
|
||
+ /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe
|
||
+ routine. */
|
||
+ if (! (dest_drive & 0x80)
|
||
+ && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) == 0x80
|
||
+ || stage1_buffer[BOOTSEC_PART_OFFSET] == 0))
|
||
+ {
|
||
+ errnum = ERR_BAD_VERSION;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ grub_close ();
|
||
+
|
||
+ /* Open Stage 2. */
|
||
+ is_open = grub_open (file);
|
||
+ if (! is_open)
|
||
+ goto fail;
|
||
+
|
||
+ src_drive = current_drive;
|
||
+ src_partition = current_partition;
|
||
+ src_part_start = part_start;
|
||
+ src_geom = buf_geom;
|
||
+
|
||
+ if (! new_drive)
|
||
+ new_drive = src_drive;
|
||
+ else if (src_drive != dest_drive)
|
||
+ grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
|
||
+ " be installed on a\ndifferent drive than the drive where"
|
||
+ " the Stage 2 resides.\n");
|
||
+
|
||
+ /* Set the boot drive. */
|
||
+ *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
|
||
+
|
||
+ /* Set the "force LBA" flag. */
|
||
+ *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba;
|
||
+
|
||
+ /* If DEST_DRIVE is a hard disk, enable the workaround, which is
|
||
+ for buggy BIOSes which don't pass boot drive correctly. Instead,
|
||
+ they pass 0x00 or 0x01 even when booted from 0x80. */
|
||
+ if (dest_drive & BIOS_FLAG_FIXED_DISK)
|
||
+ /* Replace the jmp (2 bytes) with double nop's. */
|
||
+ *((unsigned short *) (stage1_buffer + STAGE1_BOOT_DRIVE_CHECK))
|
||
+ = 0x9090;
|
||
+
|
||
+ /* Read the first sector of Stage 2. */
|
||
+ disk_read_hook = disk_read_savesect_func;
|
||
+ if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
|
||
+ goto fail;
|
||
+
|
||
+ stage2_first_sector = saved_sector;
|
||
+
|
||
+ /* Read the second sector of Stage 2. */
|
||
+ if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
|
||
+ goto fail;
|
||
+
|
||
+ stage2_second_sector = saved_sector;
|
||
+
|
||
+ /* Check for the version of Stage 2. */
|
||
+ if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
|
||
+ != COMPAT_VERSION)
|
||
+ {
|
||
+ errnum = ERR_BAD_VERSION;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* Check for the Stage 2 id. */
|
||
+ if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2)
|
||
+ is_stage1_5 = 1;
|
||
+
|
||
+ /* If INSTALLADDR is not specified explicitly in the command-line,
|
||
+ determine it by the Stage 2 id. */
|
||
+ if (! installaddr)
|
||
+ {
|
||
+ if (! is_stage1_5)
|
||
+ /* Stage 2. */
|
||
+ installaddr = 0x8000;
|
||
+ else
|
||
+ /* Stage 1.5. */
|
||
+ installaddr = 0x2000;
|
||
+ }
|
||
+
|
||
+ *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
|
||
+ = stage2_first_sector;
|
||
+ *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
|
||
+ = installaddr;
|
||
+ *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
|
||
+ = installaddr >> 4;
|
||
+
|
||
+ i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
|
||
+ while (*((unsigned long *) i))
|
||
+ {
|
||
+ if (i < (int) stage2_first_buffer
|
||
+ || (*((int *) (i - 4)) & 0x80000000)
|
||
+ || *((unsigned short *) i) >= 0xA00
|
||
+ || *((short *) (i + 2)) == 0)
|
||
+ {
|
||
+ errnum = ERR_BAD_VERSION;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ *((int *) i) = 0;
|
||
+ *((int *) (i - 4)) = 0;
|
||
+ i -= 8;
|
||
+ }
|
||
+
|
||
+ installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
|
||
+ installaddr += SECTOR_SIZE;
|
||
+
|
||
+ /* Read the whole of Stage2 except for the first sector. */
|
||
+ grub_seek (SECTOR_SIZE);
|
||
+
|
||
+ disk_read_hook = disk_read_blocklist_func;
|
||
+ if (! grub_read (dummy, -1))
|
||
+ goto fail;
|
||
+
|
||
+ disk_read_hook = 0;
|
||
+
|
||
+ /* Find a string for the configuration filename. */
|
||
+ config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS;
|
||
+ while (*(config_file_location++))
|
||
+ ;
|
||
+
|
||
+ /* Set the "force LBA" flag for Stage2. */
|
||
+ *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA))
|
||
+ = is_force_lba;
|
||
+
|
||
+ if (*ptr == 'p')
|
||
+ {
|
||
+ *((long *) (stage2_second_buffer + STAGE2_INSTALLPART))
|
||
+ = src_partition;
|
||
+ if (is_stage1_5)
|
||
+ {
|
||
+ /* Reset the device information in FILE if it is a Stage 1.5. */
|
||
+ unsigned long device = 0xFFFFFFFF;
|
||
+
|
||
+ grub_memmove (config_file_location, (char *) &device,
|
||
+ sizeof (device));
|
||
+ }
|
||
+
|
||
+ ptr = skip_to (0, ptr);
|
||
+ }
|
||
+
|
||
+ if (*ptr)
|
||
+ {
|
||
+ grub_strcpy (config_filename, ptr);
|
||
+ nul_terminate (config_filename);
|
||
+
|
||
+ if (! is_stage1_5)
|
||
+ /* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION. */
|
||
+ grub_strcpy (config_file_location, ptr);
|
||
+ else
|
||
+ {
|
||
+ char *real_config;
|
||
+ unsigned long device;
|
||
+
|
||
+ /* Translate the external device syntax to the internal device
|
||
+ syntax. */
|
||
+ if (! (real_config = set_device (ptr)))
|
||
+ {
|
||
+ /* The Stage 2 PTR does not contain the device name, so
|
||
+ use the root device instead. */
|
||
+ errnum = ERR_NONE;
|
||
+ current_drive = saved_drive;
|
||
+ current_partition = saved_partition;
|
||
+ real_config = ptr;
|
||
+ }
|
||
+
|
||
+ if (current_drive == src_drive)
|
||
+ {
|
||
+ /* If the drive where the Stage 2 resides is the same as
|
||
+ the one where the Stage 1.5 resides, do not embed the
|
||
+ drive number. */
|
||
+ current_drive = GRUB_INVALID_DRIVE;
|
||
+ }
|
||
+
|
||
+ device = (current_drive << 24) | current_partition;
|
||
+ grub_memmove (config_file_location, (char *) &device,
|
||
+ sizeof (device));
|
||
+ grub_strcpy (config_file_location + sizeof (device),
|
||
+ real_config);
|
||
+ }
|
||
+
|
||
+ /* If a Stage 1.5 is used, then we need to modify the Stage2. */
|
||
+ if (is_stage1_5)
|
||
+ {
|
||
+ char *real_config_filename = skip_to (0, ptr);
|
||
+
|
||
+ is_open = grub_open (config_filename);
|
||
+ if (! is_open)
|
||
+ goto fail;
|
||
+
|
||
+ /* Skip the first sector. */
|
||
+ grub_seek (SECTOR_SIZE);
|
||
+
|
||
+ disk_read_hook = disk_read_savesect_func;
|
||
+ if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
|
||
+ goto fail;
|
||
+
|
||
+ disk_read_hook = 0;
|
||
+ grub_close ();
|
||
+ is_open = 0;
|
||
+
|
||
+ /* Sanity check. */
|
||
+ if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2)
|
||
+ {
|
||
+ errnum = ERR_BAD_VERSION;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* Set the "force LBA" flag for Stage2. */
|
||
+ *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba;
|
||
+
|
||
+ /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2. */
|
||
+ if (*real_config_filename)
|
||
+ {
|
||
+ /* Specified */
|
||
+ char *location;
|
||
+
|
||
+ /* Find a string for the configuration filename. */
|
||
+ location = stage2_buffer + STAGE2_VER_STR_OFFS;
|
||
+ while (*(location++))
|
||
+ ;
|
||
+
|
||
+ /* Copy the name. */
|
||
+ grub_strcpy (location, real_config_filename);
|
||
+ }
|
||
+
|
||
+ /* Write it to the disk. */
|
||
+ buf_track = -1;
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+ /* In the grub shell, access the Stage 2 via the OS filesystem
|
||
+ service, if possible. */
|
||
+ if (stage2_os_file)
|
||
+ {
|
||
+ FILE *fp;
|
||
+
|
||
+ fp = fopen (stage2_os_file, "r+");
|
||
+ if (! fp)
|
||
+ {
|
||
+ errnum = ERR_FILE_NOT_FOUND;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
|
||
+ {
|
||
+ fclose (fp);
|
||
+ errnum = ERR_BAD_VERSION;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ if (fwrite (stage2_buffer, 1, SECTOR_SIZE, fp)
|
||
+ != SECTOR_SIZE)
|
||
+ {
|
||
+ fclose (fp);
|
||
+ errnum = ERR_WRITE;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ fclose (fp);
|
||
+ }
|
||
+ else
|
||
+#endif /* GRUB_UTIL */
|
||
+ {
|
||
+ if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
|
||
+ goto fail;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Clear the cache. */
|
||
+ buf_track = -1;
|
||
+
|
||
+ /* Write the modified sectors of Stage2 to the disk. */
|
||
+#ifdef GRUB_UTIL
|
||
+ if (! is_stage1_5 && stage2_os_file)
|
||
+ {
|
||
+ FILE *fp;
|
||
+
|
||
+ fp = fopen (stage2_os_file, "r+");
|
||
+ if (! fp)
|
||
+ {
|
||
+ errnum = ERR_FILE_NOT_FOUND;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
|
||
+ {
|
||
+ fclose (fp);
|
||
+ errnum = ERR_WRITE;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
|
||
+ {
|
||
+ fclose (fp);
|
||
+ errnum = ERR_WRITE;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ fclose (fp);
|
||
+ }
|
||
+ else
|
||
+#endif /* GRUB_UTIL */
|
||
+ {
|
||
+ /* The first. */
|
||
+ current_drive = src_drive;
|
||
+ current_partition = src_partition;
|
||
+
|
||
+ if (! open_partition ())
|
||
+ goto fail;
|
||
+
|
||
+ if (! devwrite (stage2_first_sector - src_part_start, 1,
|
||
+ stage2_first_buffer))
|
||
+ goto fail;
|
||
+
|
||
+ if (! devwrite (stage2_second_sector - src_part_start, 1,
|
||
+ stage2_second_buffer))
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* Write the modified sector of Stage 1 to the disk. */
|
||
+ current_drive = dest_drive;
|
||
+ current_partition = dest_partition;
|
||
+ if (! open_partition ())
|
||
+ goto fail;
|
||
+
|
||
+ devwrite (0, 1, stage1_buffer);
|
||
+
|
||
+ fail:
|
||
+ if (is_open)
|
||
+ grub_close ();
|
||
+
|
||
+ disk_read_hook = 0;
|
||
+
|
||
+#ifndef NO_DECOMPRESSION
|
||
+ no_decompression = 0;
|
||
+#endif
|
||
+
|
||
+ return errnum;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_install =
|
||
+{
|
||
+ "install",
|
||
+ install_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
|
||
+ "Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2"
|
||
+ " as a Stage 2. If the option `d' is present, the Stage 1 will always"
|
||
+ " look for the disk where STAGE2 was installed, rather than using"
|
||
+ " the booting drive. The Stage 2 will be loaded at address ADDR, which"
|
||
+ " will be determined automatically if you don't specify it. If"
|
||
+ " the option `p' or CONFIG_FILE is present, then the first block"
|
||
+ " of Stage 2 is patched with new values of the partition and name"
|
||
+ " of the configuration file used by the true Stage 2 (for a Stage 1.5,"
|
||
+ " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage"
|
||
+ " 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is"
|
||
+ " patched with the configuration filename REAL_CONFIG_FILE."
|
||
+ " If the option `--force-lba' is specified, disable some sanity checks"
|
||
+ " for LBA mode. If the option `--stage2' is specified, rewrite the Stage"
|
||
+ " 2 via your OS's filesystem instead of the raw device."
|
||
+};
|
||
+
|
||
+
|
||
+/* ioprobe */
|
||
+static int
|
||
+ioprobe_func (char *arg, int flags)
|
||
+{
|
||
+#ifdef GRUB_UTIL
|
||
+
|
||
+ errnum = ERR_UNRECOGNIZED;
|
||
+ return 1;
|
||
+
|
||
+#else /* ! GRUB_UTIL */
|
||
+
|
||
+ unsigned short *port;
|
||
+
|
||
+ /* Get the drive number. */
|
||
+ set_device (arg);
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+
|
||
+ /* Clean out IO_MAP. */
|
||
+ grub_memset ((char *) io_map, 0, IO_MAP_SIZE * sizeof (unsigned short));
|
||
+
|
||
+ /* Track the int13 handler. */
|
||
+ track_int13 (current_drive);
|
||
+
|
||
+ /* Print out the result. */
|
||
+ for (port = io_map; *port != 0; port++)
|
||
+ grub_printf (" 0x%x", (unsigned int) *port);
|
||
+
|
||
+ return 0;
|
||
+
|
||
+#endif /* ! GRUB_UTIL */
|
||
+}
|
||
+
|
||
+static struct builtin builtin_ioprobe =
|
||
+{
|
||
+ "ioprobe",
|
||
+ ioprobe_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "ioprobe DRIVE",
|
||
+ "Probe I/O ports used for the drive DRIVE."
|
||
+};
|
||
+
|
||
+
|
||
+/* kernel */
|
||
+static int
|
||
+kernel_func (char *arg, int flags)
|
||
+{
|
||
+ int len;
|
||
+ kernel_t suggested_type = KERNEL_TYPE_NONE;
|
||
+ unsigned long load_flags = 0;
|
||
+
|
||
+#ifndef AUTO_LINUX_MEM_OPT
|
||
+ load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
|
||
+#endif
|
||
+
|
||
+ /* Deal with GNU-style long options. */
|
||
+ while (1)
|
||
+ {
|
||
+ /* If the option `--type=TYPE' is specified, convert the string to
|
||
+ a kernel type. */
|
||
+ if (grub_memcmp (arg, "--type=", 7) == 0)
|
||
+ {
|
||
+ arg += 7;
|
||
+
|
||
+ if (grub_memcmp (arg, "netbsd", 6) == 0)
|
||
+ suggested_type = KERNEL_TYPE_NETBSD;
|
||
+ else if (grub_memcmp (arg, "freebsd", 7) == 0)
|
||
+ suggested_type = KERNEL_TYPE_FREEBSD;
|
||
+ else if (grub_memcmp (arg, "openbsd", 7) == 0)
|
||
+ /* XXX: For now, OpenBSD is identical to NetBSD, from GRUB's
|
||
+ point of view. */
|
||
+ suggested_type = KERNEL_TYPE_NETBSD;
|
||
+ else if (grub_memcmp (arg, "linux", 5) == 0)
|
||
+ suggested_type = KERNEL_TYPE_LINUX;
|
||
+ else if (grub_memcmp (arg, "biglinux", 8) == 0)
|
||
+ suggested_type = KERNEL_TYPE_BIG_LINUX;
|
||
+ else if (grub_memcmp (arg, "multiboot", 9) == 0)
|
||
+ suggested_type = KERNEL_TYPE_MULTIBOOT;
|
||
+ else
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+ /* If the `--no-mem-option' is specified, don't pass a Linux's mem
|
||
+ option automatically. If the kernel is another type, this flag
|
||
+ has no effect. */
|
||
+ else if (grub_memcmp (arg, "--no-mem-option", 15) == 0)
|
||
+ load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
|
||
+ else
|
||
+ break;
|
||
+
|
||
+ /* Try the next. */
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+
|
||
+ len = grub_strlen (arg);
|
||
+
|
||
+ /* Reset MB_CMDLINE. */
|
||
+ mb_cmdline = (char *) MB_CMDLINE_BUF;
|
||
+ if (len + 1 > MB_CMDLINE_BUFLEN)
|
||
+ {
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Copy the command-line to MB_CMDLINE. */
|
||
+ grub_memmove (mb_cmdline, arg, len + 1);
|
||
+ kernel_type = load_image (arg, mb_cmdline, suggested_type, load_flags);
|
||
+ if (kernel_type == KERNEL_TYPE_NONE)
|
||
+ return 1;
|
||
+
|
||
+ mb_cmdline += len + 1;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_kernel =
|
||
+{
|
||
+ "kernel",
|
||
+ kernel_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
|
||
+ "Attempt to load the primary boot image from FILE. The rest of the"
|
||
+ " line is passed verbatim as the \"kernel command line\". Any modules"
|
||
+ " must be reloaded after using this command. The option --type is used"
|
||
+ " to suggest what type of kernel to be loaded. TYPE must be either of"
|
||
+ " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
|
||
+ " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
|
||
+ " Linux's mem option automatically."
|
||
+};
|
||
+
|
||
+
|
||
+/* lock */
|
||
+static int
|
||
+lock_func (char *arg, int flags)
|
||
+{
|
||
+ if (! auth && password)
|
||
+ {
|
||
+ errnum = ERR_PRIVILEGED;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_lock =
|
||
+{
|
||
+ "lock",
|
||
+ lock_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "lock",
|
||
+ "Break a command execution unless the user is authenticated."
|
||
+};
|
||
+
|
||
+
|
||
+/* makeactive */
|
||
+static int
|
||
+makeactive_func (char *arg, int flags)
|
||
+{
|
||
+ if (! make_saved_active ())
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_makeactive =
|
||
+{
|
||
+ "makeactive",
|
||
+ makeactive_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "makeactive",
|
||
+ "Set the active partition on the root disk to GRUB's root device."
|
||
+ " This command is limited to _primary_ PC partitions on a hard disk."
|
||
+};
|
||
+
|
||
+
|
||
+/* map */
|
||
+/* Map FROM_DRIVE to TO_DRIVE. */
|
||
+static int
|
||
+map_func (char *arg, int flags)
|
||
+{
|
||
+ char *to_drive;
|
||
+ char *from_drive;
|
||
+ unsigned long to, from;
|
||
+ int i;
|
||
+
|
||
+ to_drive = arg;
|
||
+ from_drive = skip_to (0, arg);
|
||
+
|
||
+ /* Get the drive number for TO_DRIVE. */
|
||
+ set_device (to_drive);
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+ to = current_drive;
|
||
+
|
||
+ /* Get the drive number for FROM_DRIVE. */
|
||
+ set_device (from_drive);
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+ from = current_drive;
|
||
+
|
||
+ /* Search for an empty slot in BIOS_DRIVE_MAP. */
|
||
+ for (i = 0; i < DRIVE_MAP_SIZE; i++)
|
||
+ {
|
||
+ /* Perhaps the user wants to override the map. */
|
||
+ if ((bios_drive_map[i] & 0xff) == from)
|
||
+ break;
|
||
+
|
||
+ if (! bios_drive_map[i])
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (i == DRIVE_MAP_SIZE)
|
||
+ {
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ if (to == from)
|
||
+ /* If TO is equal to FROM, delete the entry. */
|
||
+ grub_memmove ((char *) &bios_drive_map[i], (char *) &bios_drive_map[i + 1],
|
||
+ sizeof (unsigned short) * (DRIVE_MAP_SIZE - i));
|
||
+ else
|
||
+ bios_drive_map[i] = from | (to << 8);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_map =
|
||
+{
|
||
+ "map",
|
||
+ map_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "map TO_DRIVE FROM_DRIVE",
|
||
+ "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
|
||
+ " when you chain-load some operating systems, such as DOS, if such an"
|
||
+ " OS resides at a non-first drive."
|
||
+};
|
||
+
|
||
+
|
||
+#ifdef USE_MD5_PASSWORDS
|
||
+/* md5crypt */
|
||
+static int
|
||
+md5crypt_func (char *arg, int flags)
|
||
+{
|
||
+ char crypted[36];
|
||
+ char key[32];
|
||
+ unsigned int seed;
|
||
+ int i;
|
||
+ const char *const seedchars =
|
||
+ "./0123456789ABCDEFGHIJKLMNOPQRST"
|
||
+ "UVWXYZabcdefghijklmnopqrstuvwxyz";
|
||
+
|
||
+ /* First create a salt. */
|
||
+
|
||
+ /* The magical prefix. */
|
||
+ grub_memset (crypted, 0, sizeof (crypted));
|
||
+ grub_memmove (crypted, "$1$", 3);
|
||
+
|
||
+ /* Create the length of a salt. */
|
||
+ seed = currticks ();
|
||
+
|
||
+ /* Generate a salt. */
|
||
+ for (i = 0; i < 8 && seed; i++)
|
||
+ {
|
||
+ /* FIXME: This should be more random. */
|
||
+ crypted[3 + i] = seedchars[seed & 0x3f];
|
||
+ seed >>= 6;
|
||
+ }
|
||
+
|
||
+ /* A salt must be terminated with `$', if it is less than 8 chars. */
|
||
+ crypted[3 + i] = '$';
|
||
+
|
||
+#ifdef DEBUG_MD5CRYPT
|
||
+ grub_printf ("salt = %s\n", crypted);
|
||
+#endif
|
||
+
|
||
+ /* Get a password. */
|
||
+ grub_memset (key, 0, sizeof (key));
|
||
+ get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
|
||
+
|
||
+ /* Crypt the key. */
|
||
+ make_md5_password (key, crypted);
|
||
+
|
||
+ grub_printf ("Encrypted: %s\n", crypted);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_md5crypt =
|
||
+{
|
||
+ "md5crypt",
|
||
+ md5crypt_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "md5crypt",
|
||
+ "Generate a password in MD5 format."
|
||
+};
|
||
+#endif /* USE_MD5_PASSWORDS */
|
||
+
|
||
+
|
||
+/* module */
|
||
+static int
|
||
+module_func (char *arg, int flags)
|
||
+{
|
||
+ int len = grub_strlen (arg);
|
||
+
|
||
+ switch (kernel_type)
|
||
+ {
|
||
+ case KERNEL_TYPE_MULTIBOOT:
|
||
+ if (mb_cmdline + len + 1 > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN)
|
||
+ {
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ return 1;
|
||
+ }
|
||
+ grub_memmove (mb_cmdline, arg, len + 1);
|
||
+ if (! load_module (arg, mb_cmdline))
|
||
+ return 1;
|
||
+ mb_cmdline += len + 1;
|
||
+ break;
|
||
+
|
||
+ case KERNEL_TYPE_LINUX:
|
||
+ case KERNEL_TYPE_BIG_LINUX:
|
||
+ if (! load_initrd (arg))
|
||
+ return 1;
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ errnum = ERR_NEED_MB_KERNEL;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_module =
|
||
+{
|
||
+ "module",
|
||
+ module_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "module FILE [ARG ...]",
|
||
+ "Load a boot module FILE for a Multiboot format boot image (no"
|
||
+ " interpretation of the file contents is made, so users of this"
|
||
+ " command must know what the kernel in question expects). The"
|
||
+ " rest of the line is passed as the \"module command line\", like"
|
||
+ " the `kernel' command."
|
||
+};
|
||
+
|
||
+
|
||
+/* modulenounzip */
|
||
+static int
|
||
+modulenounzip_func (char *arg, int flags)
|
||
+{
|
||
+ int ret;
|
||
+
|
||
+#ifndef NO_DECOMPRESSION
|
||
+ no_decompression = 1;
|
||
+#endif
|
||
+
|
||
+ ret = module_func (arg, flags);
|
||
+
|
||
+#ifndef NO_DECOMPRESSION
|
||
+ no_decompression = 0;
|
||
+#endif
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_modulenounzip =
|
||
+{
|
||
+ "modulenounzip",
|
||
+ modulenounzip_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "modulenounzip FILE [ARG ...]",
|
||
+ "The same as `module', except that automatic decompression is"
|
||
+ " disabled."
|
||
+};
|
||
+
|
||
+
|
||
+/* pager [on|off] */
|
||
+static int
|
||
+pager_func (char *arg, int flags)
|
||
+{
|
||
+ /* If ARG is empty, toggle the flag. */
|
||
+ if (! *arg)
|
||
+ use_pager = ! use_pager;
|
||
+ else if (grub_memcmp (arg, "on", 2) == 0)
|
||
+ use_pager = 1;
|
||
+ else if (grub_memcmp (arg, "off", 3) == 0)
|
||
+ use_pager = 0;
|
||
+ else
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ grub_printf (" Internal pager is now %s\n", use_pager ? "on" : "off");
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_pager =
|
||
+{
|
||
+ "pager",
|
||
+ pager_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "pager [FLAG]",
|
||
+ "Toggle pager mode with no argument. If FLAG is given and its value"
|
||
+ " is `on', turn on the mode. If FLAG is `off', turn off the mode."
|
||
+};
|
||
+
|
||
+
|
||
+/* partnew PART TYPE START LEN */
|
||
+static int
|
||
+partnew_func (char *arg, int flags)
|
||
+{
|
||
+ int new_type, new_start, new_len;
|
||
+ int start_cl, start_ch, start_dh;
|
||
+ int end_cl, end_ch, end_dh;
|
||
+ int entry;
|
||
+ char mbr[512];
|
||
+
|
||
+ /* Convert a LBA address to a CHS address in the INT 13 format. */
|
||
+ auto void lba_to_chs (int lba, int *cl, int *ch, int *dh);
|
||
+ void lba_to_chs (int lba, int *cl, int *ch, int *dh)
|
||
+ {
|
||
+ int cylinder, head, sector;
|
||
+
|
||
+ sector = lba % buf_geom.sectors + 1;
|
||
+ head = (lba / buf_geom.sectors) % buf_geom.heads;
|
||
+ cylinder = lba / (buf_geom.sectors * buf_geom.heads);
|
||
+
|
||
+ if (cylinder >= buf_geom.cylinders)
|
||
+ cylinder = buf_geom.cylinders - 1;
|
||
+
|
||
+ *cl = sector | ((cylinder & 0x300) >> 2);
|
||
+ *ch = cylinder & 0xFF;
|
||
+ *dh = head;
|
||
+ }
|
||
+
|
||
+ /* Get the drive and the partition. */
|
||
+ if (! set_device (arg))
|
||
+ return 1;
|
||
+
|
||
+ /* The drive must be a hard disk. */
|
||
+ if (! (current_drive & 0x80))
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* The partition must a primary partition. */
|
||
+ if ((current_partition >> 16) > 3
|
||
+ || (current_partition & 0xFFFF) != 0xFFFF)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ entry = current_partition >> 16;
|
||
+
|
||
+ /* Get the new partition type. */
|
||
+ arg = skip_to (0, arg);
|
||
+ if (! safe_parse_maxint (&arg, &new_type))
|
||
+ return 1;
|
||
+
|
||
+ /* The partition type is unsigned char. */
|
||
+ if (new_type > 0xFF)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Get the new partition start. */
|
||
+ arg = skip_to (0, arg);
|
||
+ if (! safe_parse_maxint (&arg, &new_start))
|
||
+ return 1;
|
||
+
|
||
+ /* Get the new partition length. */
|
||
+ arg = skip_to (0, arg);
|
||
+ if (! safe_parse_maxint (&arg, &new_len))
|
||
+ return 1;
|
||
+
|
||
+ /* Read the MBR. */
|
||
+ if (! rawread (current_drive, 0, 0, SECTOR_SIZE, mbr))
|
||
+ return 1;
|
||
+
|
||
+ /* Check if the new partition will fit in the disk. */
|
||
+ if (new_start + new_len > buf_geom.total_sectors)
|
||
+ {
|
||
+ errnum = ERR_GEOM;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Store the partition information in the MBR. */
|
||
+ lba_to_chs (new_start, &start_cl, &start_ch, &start_dh);
|
||
+ lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh);
|
||
+
|
||
+ PC_SLICE_FLAG (mbr, entry) = 0;
|
||
+ PC_SLICE_HEAD (mbr, entry) = start_dh;
|
||
+ PC_SLICE_SEC (mbr, entry) = start_cl;
|
||
+ PC_SLICE_CYL (mbr, entry) = start_ch;
|
||
+ PC_SLICE_TYPE (mbr, entry) = new_type;
|
||
+ PC_SLICE_EHEAD (mbr, entry) = end_dh;
|
||
+ PC_SLICE_ESEC (mbr, entry) = end_cl;
|
||
+ PC_SLICE_ECYL (mbr, entry) = end_ch;
|
||
+ PC_SLICE_START (mbr, entry) = new_start;
|
||
+ PC_SLICE_LENGTH (mbr, entry) = new_len;
|
||
+
|
||
+ /* Make sure that the MBR has a valid signature. */
|
||
+ PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE;
|
||
+
|
||
+ /* Write back the MBR to the disk. */
|
||
+ buf_track = -1;
|
||
+ if (! rawwrite (current_drive, 0, mbr))
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_partnew =
|
||
+{
|
||
+ "partnew",
|
||
+ partnew_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "partnew PART TYPE START LEN",
|
||
+ "Create a primary partition at the starting address START with the"
|
||
+ " length LEN, with the type TYPE. START and LEN are in sector units."
|
||
+};
|
||
+
|
||
+
|
||
+/* parttype PART TYPE */
|
||
+static int
|
||
+parttype_func (char *arg, int flags)
|
||
+{
|
||
+ int new_type;
|
||
+ unsigned long part = 0xFFFFFF;
|
||
+ unsigned long start, len, offset, ext_offset;
|
||
+ int entry, type;
|
||
+ char mbr[512];
|
||
+
|
||
+ /* Get the drive and the partition. */
|
||
+ if (! set_device (arg))
|
||
+ return 1;
|
||
+
|
||
+ /* The drive must be a hard disk. */
|
||
+ if (! (current_drive & 0x80))
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* The partition must be a PC slice. */
|
||
+ if ((current_partition >> 16) == 0xFF
|
||
+ || (current_partition & 0xFFFF) != 0xFFFF)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Get the new partition type. */
|
||
+ arg = skip_to (0, arg);
|
||
+ if (! safe_parse_maxint (&arg, &new_type))
|
||
+ return 1;
|
||
+
|
||
+ /* The partition type is unsigned char. */
|
||
+ if (new_type > 0xFF)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Look for the partition. */
|
||
+ while (next_partition (current_drive, 0xFFFFFF, &part, &type,
|
||
+ &start, &len, &offset, &entry,
|
||
+ &ext_offset, mbr))
|
||
+ {
|
||
+ if (part == current_partition)
|
||
+ {
|
||
+ /* Found. */
|
||
+
|
||
+ /* Set the type to NEW_TYPE. */
|
||
+ PC_SLICE_TYPE (mbr, entry) = new_type;
|
||
+
|
||
+ /* Write back the MBR to the disk. */
|
||
+ buf_track = -1;
|
||
+ if (! rawwrite (current_drive, offset, mbr))
|
||
+ return 1;
|
||
+
|
||
+ /* Succeed. */
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* The partition was not found. ERRNUM was set by next_partition. */
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_parttype =
|
||
+{
|
||
+ "parttype",
|
||
+ parttype_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "parttype PART TYPE",
|
||
+ "Change the type of the partition PART to TYPE."
|
||
+};
|
||
+
|
||
+
|
||
+/* password */
|
||
+static int
|
||
+password_func (char *arg, int flags)
|
||
+{
|
||
+ int len;
|
||
+ password_t type = PASSWORD_PLAIN;
|
||
+
|
||
+#ifdef USE_MD5_PASSWORDS
|
||
+ if (grub_memcmp (arg, "--md5", 5) == 0)
|
||
+ {
|
||
+ type = PASSWORD_MD5;
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+#endif
|
||
+ if (grub_memcmp (arg, "--", 2) == 0)
|
||
+ {
|
||
+ type = PASSWORD_UNSUPPORTED;
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+
|
||
+ if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0)
|
||
+ {
|
||
+ /* Do password check! */
|
||
+ char entered[32];
|
||
+
|
||
+ /* Wipe out any previously entered password */
|
||
+ entered[0] = 0;
|
||
+ get_cmdline ("Password: ", entered, 31, '*', 0);
|
||
+
|
||
+ nul_terminate (arg);
|
||
+ if (check_password (entered, arg, type) != 0)
|
||
+ {
|
||
+ errnum = ERR_PRIVILEGED;
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ len = grub_strlen (arg);
|
||
+
|
||
+ /* PASSWORD NUL NUL ... */
|
||
+ if (len + 2 > PASSWORD_BUFLEN)
|
||
+ {
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Copy the password and clear the rest of the buffer. */
|
||
+ password = (char *) PASSWORD_BUF;
|
||
+ grub_memmove (password, arg, len);
|
||
+ grub_memset (password + len, 0, PASSWORD_BUFLEN - len);
|
||
+ password_type = type;
|
||
+ }
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_password =
|
||
+{
|
||
+ "password",
|
||
+ password_func,
|
||
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
|
||
+ "password [--md5] PASSWD [FILE]",
|
||
+ "If used in the first section of a menu file, disable all"
|
||
+ " interactive editing control (menu entry editor and"
|
||
+ " command line). If the password PASSWD is entered, it loads the"
|
||
+ " FILE as a new config file and restarts the GRUB Stage 2. If you"
|
||
+ " omit the argument FILE, then GRUB just unlocks privileged"
|
||
+ " instructions. You can also use it in the script section, in"
|
||
+ " which case it will ask for the password, before continueing."
|
||
+ " The option --md5 tells GRUB that PASSWD is encrypted with"
|
||
+ " md5crypt."
|
||
+};
|
||
+
|
||
+
|
||
+/* pause */
|
||
+static int
|
||
+pause_func (char *arg, int flags)
|
||
+{
|
||
+ printf("%s\n", arg);
|
||
+
|
||
+ /* If ESC is returned, then abort this entry. */
|
||
+ if (ASCII_CHAR (getkey ()) == 27)
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_pause =
|
||
+{
|
||
+ "pause",
|
||
+ pause_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
|
||
+ "pause [MESSAGE ...]",
|
||
+ "Print MESSAGE, then wait until a key is pressed."
|
||
+};
|
||
+
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+/* quit */
|
||
+static int
|
||
+quit_func (char *arg, int flags)
|
||
+{
|
||
+ stop ();
|
||
+
|
||
+ /* Never reach here. */
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_quit =
|
||
+{
|
||
+ "quit",
|
||
+ quit_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "quit",
|
||
+ "Exit from the GRUB shell."
|
||
+};
|
||
+#endif /* GRUB_UTIL */
|
||
+
|
||
+
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+/* rarp */
|
||
+static int
|
||
+rarp_func (char *arg, int flags)
|
||
+{
|
||
+ if (! rarp ())
|
||
+ {
|
||
+ if (errnum == ERR_NONE)
|
||
+ errnum = ERR_DEV_VALUES;
|
||
+
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Notify the configuration. */
|
||
+ print_network_configuration ();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_rarp =
|
||
+{
|
||
+ "rarp",
|
||
+ rarp_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "rarp",
|
||
+ "Initialize a network device via RARP."
|
||
+};
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+
|
||
+
|
||
+static int
|
||
+read_func (char *arg, int flags)
|
||
+{
|
||
+ int addr;
|
||
+
|
||
+ if (! safe_parse_maxint (&arg, &addr))
|
||
+ return 1;
|
||
+
|
||
+ grub_printf ("Address 0x%x: Value 0x%x\n",
|
||
+ addr, *((unsigned *) RAW_ADDR (addr)));
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_read =
|
||
+{
|
||
+ "read",
|
||
+ read_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "read ADDR",
|
||
+ "Read a 32-bit value from memory at address ADDR and"
|
||
+ " display it in hex format."
|
||
+};
|
||
+
|
||
+
|
||
+/* reboot */
|
||
+static int
|
||
+reboot_func (char *arg, int flags)
|
||
+{
|
||
+ grub_reboot ();
|
||
+
|
||
+ /* Never reach here. */
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_reboot =
|
||
+{
|
||
+ "reboot",
|
||
+ reboot_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "reboot",
|
||
+ "Reboot your system."
|
||
+};
|
||
+
|
||
+
|
||
+/* Print the root device information. */
|
||
+static void
|
||
+print_root_device (void)
|
||
+{
|
||
+ if (saved_drive == NETWORK_DRIVE)
|
||
+ {
|
||
+ /* Network drive. */
|
||
+ grub_printf (" (nd):");
|
||
+ }
|
||
+ else if (saved_drive & 0x80)
|
||
+ {
|
||
+ /* Hard disk drive. */
|
||
+ grub_printf (" (hd%d", saved_drive - 0x80);
|
||
+
|
||
+ if ((saved_partition & 0xFF0000) != 0xFF0000)
|
||
+ grub_printf (",%d", saved_partition >> 16);
|
||
+
|
||
+ if ((saved_partition & 0x00FF00) != 0x00FF00)
|
||
+ grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a');
|
||
+
|
||
+ grub_printf ("):");
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Floppy disk drive. */
|
||
+ grub_printf (" (fd%d):", saved_drive);
|
||
+ }
|
||
+
|
||
+ /* Print the filesystem information. */
|
||
+ current_partition = saved_partition;
|
||
+ current_drive = saved_drive;
|
||
+ print_fsys_type ();
|
||
+}
|
||
+
|
||
+static int
|
||
+real_root_func (char *arg, int attempt_mount)
|
||
+{
|
||
+ int hdbias = 0;
|
||
+ char *biasptr;
|
||
+ char *next;
|
||
+
|
||
+ /* If ARG is empty, just print the current root device. */
|
||
+ if (! *arg)
|
||
+ {
|
||
+ print_root_device ();
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* Call set_device to get the drive and the partition in ARG. */
|
||
+ next = set_device (arg);
|
||
+ if (! next)
|
||
+ return 1;
|
||
+
|
||
+ /* Ignore ERR_FSYS_MOUNT. */
|
||
+ if (attempt_mount)
|
||
+ {
|
||
+ if (! open_device () && errnum != ERR_FSYS_MOUNT)
|
||
+ return 1;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* This is necessary, because the location of a partition table
|
||
+ must be set appropriately. */
|
||
+ if (open_partition ())
|
||
+ {
|
||
+ set_bootdev (0);
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Clear ERRNUM. */
|
||
+ errnum = 0;
|
||
+ saved_partition = current_partition;
|
||
+ saved_drive = current_drive;
|
||
+
|
||
+ if (attempt_mount)
|
||
+ {
|
||
+ /* BSD and chainloading evil hacks !! */
|
||
+ biasptr = skip_to (0, next);
|
||
+ safe_parse_maxint (&biasptr, &hdbias);
|
||
+ errnum = 0;
|
||
+ bootdev = set_bootdev (hdbias);
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+
|
||
+ /* Print the type of the filesystem. */
|
||
+ print_fsys_type ();
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int
|
||
+root_func (char *arg, int flags)
|
||
+{
|
||
+ return real_root_func (arg, 1);
|
||
+}
|
||
+
|
||
+static struct builtin builtin_root =
|
||
+{
|
||
+ "root",
|
||
+ root_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "root [DEVICE [HDBIAS]]",
|
||
+ "Set the current \"root device\" to the device DEVICE, then"
|
||
+ " attempt to mount it to get the partition size (for passing the"
|
||
+ " partition descriptor in `ES:ESI', used by some chain-loaded"
|
||
+ " bootloaders), the BSD drive-type (for booting BSD kernels using"
|
||
+ " their native boot format), and correctly determine "
|
||
+ " the PC partition where a BSD sub-partition is located. The"
|
||
+ " optional HDBIAS parameter is a number to tell a BSD kernel"
|
||
+ " how many BIOS drive numbers are on controllers before the current"
|
||
+ " one. For example, if there is an IDE disk and a SCSI disk, and your"
|
||
+ " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."
|
||
+};
|
||
+
|
||
+
|
||
+/* rootnoverify */
|
||
+static int
|
||
+rootnoverify_func (char *arg, int flags)
|
||
+{
|
||
+ return real_root_func (arg, 0);
|
||
+}
|
||
+
|
||
+static struct builtin builtin_rootnoverify =
|
||
+{
|
||
+ "rootnoverify",
|
||
+ rootnoverify_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "rootnoverify [DEVICE [HDBIAS]]",
|
||
+ "Similar to `root', but don't attempt to mount the partition. This"
|
||
+ " is useful for when an OS is outside of the area of the disk that"
|
||
+ " GRUB can read, but setting the correct root device is still"
|
||
+ " desired. Note that the items mentioned in `root' which"
|
||
+ " derived from attempting the mount will NOT work correctly."
|
||
+};
|
||
+
|
||
+
|
||
+/* savedefault */
|
||
+static int
|
||
+savedefault_func (char *arg, int flags)
|
||
+{
|
||
+#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
|
||
+ unsigned long tmp_drive = saved_drive;
|
||
+ unsigned long tmp_partition = saved_partition;
|
||
+ char *default_file = (char *) DEFAULT_FILE_BUF;
|
||
+ char buf[10];
|
||
+ char sect[SECTOR_SIZE];
|
||
+ int entryno;
|
||
+ int sector_count = 0;
|
||
+ int saved_sectors[2];
|
||
+ int saved_offsets[2];
|
||
+ int saved_lengths[2];
|
||
+
|
||
+ /* Save sector information about at most two sectors. */
|
||
+ auto void disk_read_savesect_func (int sector, int offset, int length);
|
||
+ void disk_read_savesect_func (int sector, int offset, int length)
|
||
+ {
|
||
+ if (sector_count < 2)
|
||
+ {
|
||
+ saved_sectors[sector_count] = sector;
|
||
+ saved_offsets[sector_count] = offset;
|
||
+ saved_lengths[sector_count] = length;
|
||
+ }
|
||
+ sector_count++;
|
||
+ }
|
||
+
|
||
+ /* This command is only useful when you boot an entry from the menu
|
||
+ interface. */
|
||
+ if (! (flags & BUILTIN_SCRIPT))
|
||
+ {
|
||
+ errnum = ERR_UNRECOGNIZED;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Determine a saved entry number. */
|
||
+ if (*arg)
|
||
+ {
|
||
+ if (grub_memcmp (arg, "fallback", sizeof ("fallback") - 1) == 0)
|
||
+ {
|
||
+ int i;
|
||
+ int index = 0;
|
||
+
|
||
+ for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
|
||
+ {
|
||
+ if (fallback_entries[i] < 0)
|
||
+ break;
|
||
+ if (fallback_entries[i] == current_entryno)
|
||
+ {
|
||
+ index = i + 1;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (index >= MAX_FALLBACK_ENTRIES || fallback_entries[index] < 0)
|
||
+ {
|
||
+ /* This is the last. */
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ entryno = fallback_entries[index];
|
||
+ }
|
||
+ else if (! safe_parse_maxint (&arg, &entryno))
|
||
+ return 1;
|
||
+ }
|
||
+ else
|
||
+ entryno = current_entryno;
|
||
+
|
||
+ /* Open the default file. */
|
||
+ saved_drive = boot_drive;
|
||
+ saved_partition = install_partition;
|
||
+ if (grub_open (default_file))
|
||
+ {
|
||
+ int len;
|
||
+
|
||
+ disk_read_hook = disk_read_savesect_func;
|
||
+ len = grub_read (buf, sizeof (buf));
|
||
+ disk_read_hook = 0;
|
||
+ grub_close ();
|
||
+
|
||
+ if (len != sizeof (buf))
|
||
+ {
|
||
+ /* This is too small. Do not modify the file manually, please! */
|
||
+ errnum = ERR_READ;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ if (sector_count > 2)
|
||
+ {
|
||
+ /* Is this possible?! Too fragmented! */
|
||
+ errnum = ERR_FSYS_CORRUPT;
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* Set up a string to be written. */
|
||
+ grub_memset (buf, '\n', sizeof (buf));
|
||
+ grub_sprintf (buf, "%d", entryno);
|
||
+
|
||
+ if (saved_lengths[0] < sizeof (buf))
|
||
+ {
|
||
+ /* The file is anchored to another file and the first few bytes
|
||
+ are spanned in two sectors. Uggh... */
|
||
+ if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
|
||
+ sect))
|
||
+ goto fail;
|
||
+ grub_memmove (sect + saved_offsets[0], buf, saved_lengths[0]);
|
||
+ if (! rawwrite (current_drive, saved_sectors[0], sect))
|
||
+ goto fail;
|
||
+
|
||
+ if (! rawread (current_drive, saved_sectors[1], 0, SECTOR_SIZE,
|
||
+ sect))
|
||
+ goto fail;
|
||
+ grub_memmove (sect + saved_offsets[1],
|
||
+ buf + saved_lengths[0],
|
||
+ sizeof (buf) - saved_lengths[0]);
|
||
+ if (! rawwrite (current_drive, saved_sectors[1], sect))
|
||
+ goto fail;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* This is a simple case. It fits into a single sector. */
|
||
+ if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
|
||
+ sect))
|
||
+ goto fail;
|
||
+ grub_memmove (sect + saved_offsets[0], buf, sizeof (buf));
|
||
+ if (! rawwrite (current_drive, saved_sectors[0], sect))
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* Clear the cache. */
|
||
+ buf_track = -1;
|
||
+ }
|
||
+
|
||
+ fail:
|
||
+ saved_drive = tmp_drive;
|
||
+ saved_partition = tmp_partition;
|
||
+ return errnum;
|
||
+#else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
|
||
+ errnum = ERR_UNRECOGNIZED;
|
||
+ return 1;
|
||
+#endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
|
||
+}
|
||
+
|
||
+static struct builtin builtin_savedefault =
|
||
+{
|
||
+ "savedefault",
|
||
+ savedefault_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "savedefault [NUM | `fallback']",
|
||
+ "Save the current entry as the default boot entry if no argument is"
|
||
+ " specified. If a number is specified, this number is saved. If"
|
||
+ " `fallback' is used, next fallback entry is saved."
|
||
+};
|
||
+
|
||
+
|
||
+#ifdef SUPPORT_SERIAL
|
||
+/* serial */
|
||
+static int
|
||
+serial_func (char *arg, int flags)
|
||
+{
|
||
+ unsigned short port = serial_hw_get_port (0);
|
||
+ unsigned int speed = 9600;
|
||
+ int word_len = UART_8BITS_WORD;
|
||
+ int parity = UART_NO_PARITY;
|
||
+ int stop_bit_len = UART_1_STOP_BIT;
|
||
+
|
||
+ /* Process GNU-style long options.
|
||
+ FIXME: We should implement a getopt-like function, to avoid
|
||
+ duplications. */
|
||
+ while (1)
|
||
+ {
|
||
+ if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0)
|
||
+ {
|
||
+ char *p = arg + sizeof ("--unit=") - 1;
|
||
+ int unit;
|
||
+
|
||
+ if (! safe_parse_maxint (&p, &unit))
|
||
+ return 1;
|
||
+
|
||
+ if (unit < 0 || unit > 3)
|
||
+ {
|
||
+ errnum = ERR_DEV_VALUES;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ port = serial_hw_get_port (unit);
|
||
+ }
|
||
+ else if (grub_memcmp (arg, "--speed=", sizeof ("--speed=") - 1) == 0)
|
||
+ {
|
||
+ char *p = arg + sizeof ("--speed=") - 1;
|
||
+ int num;
|
||
+
|
||
+ if (! safe_parse_maxint (&p, &num))
|
||
+ return 1;
|
||
+
|
||
+ speed = (unsigned int) num;
|
||
+ }
|
||
+ else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0)
|
||
+ {
|
||
+ char *p = arg + sizeof ("--port=") - 1;
|
||
+ int num;
|
||
+
|
||
+ if (! safe_parse_maxint (&p, &num))
|
||
+ return 1;
|
||
+
|
||
+ port = (unsigned short) num;
|
||
+ }
|
||
+ else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0)
|
||
+ {
|
||
+ char *p = arg + sizeof ("--word=") - 1;
|
||
+ int len;
|
||
+
|
||
+ if (! safe_parse_maxint (&p, &len))
|
||
+ return 1;
|
||
+
|
||
+ switch (len)
|
||
+ {
|
||
+ case 5: word_len = UART_5BITS_WORD; break;
|
||
+ case 6: word_len = UART_6BITS_WORD; break;
|
||
+ case 7: word_len = UART_7BITS_WORD; break;
|
||
+ case 8: word_len = UART_8BITS_WORD; break;
|
||
+ default:
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+ else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0)
|
||
+ {
|
||
+ char *p = arg + sizeof ("--stop=") - 1;
|
||
+ int len;
|
||
+
|
||
+ if (! safe_parse_maxint (&p, &len))
|
||
+ return 1;
|
||
+
|
||
+ switch (len)
|
||
+ {
|
||
+ case 1: stop_bit_len = UART_1_STOP_BIT; break;
|
||
+ case 2: stop_bit_len = UART_2_STOP_BITS; break;
|
||
+ default:
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+ else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0)
|
||
+ {
|
||
+ char *p = arg + sizeof ("--parity=") - 1;
|
||
+
|
||
+ if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0)
|
||
+ parity = UART_NO_PARITY;
|
||
+ else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0)
|
||
+ parity = UART_ODD_PARITY;
|
||
+ else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0)
|
||
+ parity = UART_EVEN_PARITY;
|
||
+ else
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+# ifdef GRUB_UTIL
|
||
+ /* In the grub shell, don't use any port number but open a tty
|
||
+ device instead. */
|
||
+ else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0)
|
||
+ {
|
||
+ char *p = arg + sizeof ("--device=") - 1;
|
||
+ char dev[256]; /* XXX */
|
||
+ char *q = dev;
|
||
+
|
||
+ while (*p && ! grub_isspace (*p))
|
||
+ *q++ = *p++;
|
||
+
|
||
+ *q = 0;
|
||
+ serial_set_device (dev);
|
||
+ }
|
||
+# endif /* GRUB_UTIL */
|
||
+ else
|
||
+ break;
|
||
+
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+
|
||
+ /* Initialize the serial unit. */
|
||
+ if (! serial_hw_init (port, speed, word_len, parity, stop_bit_len))
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_serial =
|
||
+{
|
||
+ "serial",
|
||
+ serial_func,
|
||
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "serial [--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]",
|
||
+ "Initialize a serial device. UNIT is a digit that specifies which serial"
|
||
+ " device is used (e.g. 0 == COM1). If you need to specify the port number,"
|
||
+ " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length,"
|
||
+ " PARITY is the type of parity, which is one of `no', `odd' and `even'."
|
||
+ " STOP is the length of stop bit(s). The option --device can be used only"
|
||
+ " in the grub shell, which specifies the file name of a tty device. The"
|
||
+ " default values are COM1, 9600, 8N1."
|
||
+};
|
||
+#endif /* SUPPORT_SERIAL */
|
||
+
|
||
+
|
||
+/* setkey */
|
||
+struct keysym
|
||
+{
|
||
+ char *unshifted_name; /* the name in unshifted state */
|
||
+ char *shifted_name; /* the name in shifted state */
|
||
+ unsigned char unshifted_ascii; /* the ascii code in unshifted state */
|
||
+ unsigned char shifted_ascii; /* the ascii code in shifted state */
|
||
+ unsigned char keycode; /* keyboard scancode */
|
||
+};
|
||
+
|
||
+/* The table for key symbols. If the "shifted" member of an entry is
|
||
+ NULL, the entry does not have shifted state. */
|
||
+static struct keysym keysym_table[] =
|
||
+{
|
||
+ {"escape", 0, 0x1b, 0, 0x01},
|
||
+ {"1", "exclam", '1', '!', 0x02},
|
||
+ {"2", "at", '2', '@', 0x03},
|
||
+ {"3", "numbersign", '3', '#', 0x04},
|
||
+ {"4", "dollar", '4', '$', 0x05},
|
||
+ {"5", "percent", '5', '%', 0x06},
|
||
+ {"6", "caret", '6', '^', 0x07},
|
||
+ {"7", "ampersand", '7', '&', 0x08},
|
||
+ {"8", "asterisk", '8', '*', 0x09},
|
||
+ {"9", "parenleft", '9', '(', 0x0a},
|
||
+ {"0", "parenright", '0', ')', 0x0b},
|
||
+ {"minus", "underscore", '-', '_', 0x0c},
|
||
+ {"equal", "plus", '=', '+', 0x0d},
|
||
+ {"backspace", 0, '\b', 0, 0x0e},
|
||
+ {"tab", 0, '\t', 0, 0x0f},
|
||
+ {"q", "Q", 'q', 'Q', 0x10},
|
||
+ {"w", "W", 'w', 'W', 0x11},
|
||
+ {"e", "E", 'e', 'E', 0x12},
|
||
+ {"r", "R", 'r', 'R', 0x13},
|
||
+ {"t", "T", 't', 'T', 0x14},
|
||
+ {"y", "Y", 'y', 'Y', 0x15},
|
||
+ {"u", "U", 'u', 'U', 0x16},
|
||
+ {"i", "I", 'i', 'I', 0x17},
|
||
+ {"o", "O", 'o', 'O', 0x18},
|
||
+ {"p", "P", 'p', 'P', 0x19},
|
||
+ {"bracketleft", "braceleft", '[', '{', 0x1a},
|
||
+ {"bracketright", "braceright", ']', '}', 0x1b},
|
||
+ {"enter", 0, '\n', 0, 0x1c},
|
||
+ {"control", 0, 0, 0, 0x1d},
|
||
+ {"a", "A", 'a', 'A', 0x1e},
|
||
+ {"s", "S", 's', 'S', 0x1f},
|
||
+ {"d", "D", 'd', 'D', 0x20},
|
||
+ {"f", "F", 'f', 'F', 0x21},
|
||
+ {"g", "G", 'g', 'G', 0x22},
|
||
+ {"h", "H", 'h', 'H', 0x23},
|
||
+ {"j", "J", 'j', 'J', 0x24},
|
||
+ {"k", "K", 'k', 'K', 0x25},
|
||
+ {"l", "L", 'l', 'L', 0x26},
|
||
+ {"semicolon", "colon", ';', ':', 0x27},
|
||
+ {"quote", "doublequote", '\'', '"', 0x28},
|
||
+ {"backquote", "tilde", '`', '~', 0x29},
|
||
+ {"shift", 0, 0, 0, 0x2a},
|
||
+ {"backslash", "bar", '\\', '|', 0x2b},
|
||
+ {"z", "Z", 'z', 'Z', 0x2c},
|
||
+ {"x", "X", 'x', 'X', 0x2d},
|
||
+ {"c", "C", 'c', 'C', 0x2e},
|
||
+ {"v", "V", 'v', 'V', 0x2f},
|
||
+ {"b", "B", 'b', 'B', 0x30},
|
||
+ {"n", "N", 'n', 'N', 0x31},
|
||
+ {"m", "M", 'm', 'M', 0x32},
|
||
+ {"comma", "less", ',', '<', 0x33},
|
||
+ {"period", "greater", '.', '>', 0x34},
|
||
+ {"slash", "question", '/', '?', 0x35},
|
||
+ {"alt", 0, 0, 0, 0x38},
|
||
+ {"space", 0, ' ', 0, 0x39},
|
||
+ {"capslock", 0, 0, 0, 0x3a},
|
||
+ {"F1", 0, 0, 0, 0x3b},
|
||
+ {"F2", 0, 0, 0, 0x3c},
|
||
+ {"F3", 0, 0, 0, 0x3d},
|
||
+ {"F4", 0, 0, 0, 0x3e},
|
||
+ {"F5", 0, 0, 0, 0x3f},
|
||
+ {"F6", 0, 0, 0, 0x40},
|
||
+ {"F7", 0, 0, 0, 0x41},
|
||
+ {"F8", 0, 0, 0, 0x42},
|
||
+ {"F9", 0, 0, 0, 0x43},
|
||
+ {"F10", 0, 0, 0, 0x44},
|
||
+ /* Caution: do not add NumLock here! we cannot deal with it properly. */
|
||
+ {"delete", 0, 0x7f, 0, 0x53}
|
||
+};
|
||
+
|
||
+static int
|
||
+setkey_func (char *arg, int flags)
|
||
+{
|
||
+ char *to_key, *from_key;
|
||
+ int to_code, from_code;
|
||
+ int map_in_interrupt = 0;
|
||
+
|
||
+ auto int find_key_code (char *key);
|
||
+ auto int find_ascii_code (char *key);
|
||
+
|
||
+ auto int find_key_code (char *key)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
|
||
+ {
|
||
+ if (keysym_table[i].unshifted_name &&
|
||
+ grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
|
||
+ return keysym_table[i].keycode;
|
||
+ else if (keysym_table[i].shifted_name &&
|
||
+ grub_strcmp (key, keysym_table[i].shifted_name) == 0)
|
||
+ return keysym_table[i].keycode;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ auto int find_ascii_code (char *key)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
|
||
+ {
|
||
+ if (keysym_table[i].unshifted_name &&
|
||
+ grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
|
||
+ return keysym_table[i].unshifted_ascii;
|
||
+ else if (keysym_table[i].shifted_name &&
|
||
+ grub_strcmp (key, keysym_table[i].shifted_name) == 0)
|
||
+ return keysym_table[i].shifted_ascii;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ to_key = arg;
|
||
+ from_key = skip_to (0, to_key);
|
||
+
|
||
+ if (! *to_key)
|
||
+ {
|
||
+ /* If the user specifies no argument, reset the key mappings. */
|
||
+ grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
|
||
+ grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
|
||
+
|
||
+ return 0;
|
||
+ }
|
||
+ else if (! *from_key)
|
||
+ {
|
||
+ /* The user must specify two arguments or zero argument. */
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ nul_terminate (to_key);
|
||
+ nul_terminate (from_key);
|
||
+
|
||
+ to_code = find_ascii_code (to_key);
|
||
+ from_code = find_ascii_code (from_key);
|
||
+ if (! to_code || ! from_code)
|
||
+ {
|
||
+ map_in_interrupt = 1;
|
||
+ to_code = find_key_code (to_key);
|
||
+ from_code = find_key_code (from_key);
|
||
+ if (! to_code || ! from_code)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (map_in_interrupt)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ /* Find an empty slot. */
|
||
+ for (i = 0; i < KEY_MAP_SIZE; i++)
|
||
+ {
|
||
+ if ((bios_key_map[i] & 0xff) == from_code)
|
||
+ /* Perhaps the user wants to overwrite the map. */
|
||
+ break;
|
||
+
|
||
+ if (! bios_key_map[i])
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (i == KEY_MAP_SIZE)
|
||
+ {
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ if (to_code == from_code)
|
||
+ /* If TO is equal to FROM, delete the entry. */
|
||
+ grub_memmove ((char *) &bios_key_map[i],
|
||
+ (char *) &bios_key_map[i + 1],
|
||
+ sizeof (unsigned short) * (KEY_MAP_SIZE - i));
|
||
+ else
|
||
+ bios_key_map[i] = (to_code << 8) | from_code;
|
||
+
|
||
+ /* Ugly but should work. */
|
||
+ unset_int15_handler ();
|
||
+ set_int15_handler ();
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ /* Find an empty slot. */
|
||
+ for (i = 0; i < KEY_MAP_SIZE; i++)
|
||
+ {
|
||
+ if ((ascii_key_map[i] & 0xff) == from_code)
|
||
+ /* Perhaps the user wants to overwrite the map. */
|
||
+ break;
|
||
+
|
||
+ if (! ascii_key_map[i])
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (i == KEY_MAP_SIZE)
|
||
+ {
|
||
+ errnum = ERR_WONT_FIT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ if (to_code == from_code)
|
||
+ /* If TO is equal to FROM, delete the entry. */
|
||
+ grub_memmove ((char *) &ascii_key_map[i],
|
||
+ (char *) &ascii_key_map[i + 1],
|
||
+ sizeof (unsigned short) * (KEY_MAP_SIZE - i));
|
||
+ else
|
||
+ ascii_key_map[i] = (to_code << 8) | from_code;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_setkey =
|
||
+{
|
||
+ "setkey",
|
||
+ setkey_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "setkey [TO_KEY FROM_KEY]",
|
||
+ "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY."
|
||
+ " A key must be an alphabet, a digit, or one of these: escape, exclam,"
|
||
+ " at, numbersign, dollar, percent, caret, ampersand, asterisk, parenleft,"
|
||
+ " parenright, minus, underscore, equal, plus, backspace, tab, bracketleft,"
|
||
+ " braceleft, bracketright, braceright, enter, control, semicolon, colon,"
|
||
+ " quote, doublequote, backquote, tilde, shift, backslash, bar, comma,"
|
||
+ " less, period, greater, slash, question, alt, space, capslock, FX (X"
|
||
+ " is a digit), and delete. If no argument is specified, reset key"
|
||
+ " mappings."
|
||
+};
|
||
+
|
||
+
|
||
+/* setup */
|
||
+static int
|
||
+setup_func (char *arg, int flags)
|
||
+{
|
||
+ /* Point to the string of the installed drive/partition. */
|
||
+ char *install_ptr;
|
||
+ /* Point to the string of the drive/parition where the GRUB images
|
||
+ reside. */
|
||
+ char *image_ptr;
|
||
+ unsigned long installed_drive, installed_partition;
|
||
+ unsigned long image_drive, image_partition;
|
||
+ unsigned long tmp_drive, tmp_partition;
|
||
+ char stage1[64];
|
||
+ char stage2[64];
|
||
+ char config_filename[64];
|
||
+ char real_config_filename[64];
|
||
+ char cmd_arg[256];
|
||
+ char device[16];
|
||
+ char *buffer = (char *) RAW_ADDR (0x100000);
|
||
+ int is_force_lba = 0;
|
||
+ char *stage2_arg = 0;
|
||
+ char *prefix = 0;
|
||
+
|
||
+ auto int check_file (char *file);
|
||
+ auto void sprint_device (int drive, int partition);
|
||
+ auto int embed_stage1_5 (char * stage1_5, int drive, int partition);
|
||
+
|
||
+ /* Check if the file FILE exists like Autoconf. */
|
||
+ int check_file (char *file)
|
||
+ {
|
||
+ int ret;
|
||
+
|
||
+ grub_printf (" Checking if \"%s\" exists... ", file);
|
||
+ ret = grub_open (file);
|
||
+ if (ret)
|
||
+ {
|
||
+ grub_close ();
|
||
+ grub_printf ("yes\n");
|
||
+ }
|
||
+ else
|
||
+ grub_printf ("no\n");
|
||
+
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ /* Construct a device name in DEVICE. */
|
||
+ void sprint_device (int drive, int partition)
|
||
+ {
|
||
+ grub_sprintf (device, "(%cd%d",
|
||
+ (drive & 0x80) ? 'h' : 'f',
|
||
+ drive & ~0x80);
|
||
+ if ((partition & 0xFF0000) != 0xFF0000)
|
||
+ {
|
||
+ char tmp[16];
|
||
+ grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
|
||
+ grub_strncat (device, tmp, 256);
|
||
+ }
|
||
+ if ((partition & 0x00FF00) != 0x00FF00)
|
||
+ {
|
||
+ char tmp[16];
|
||
+ grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
|
||
+ grub_strncat (device, tmp, 256);
|
||
+ }
|
||
+ grub_strncat (device, ")", 256);
|
||
+ }
|
||
+
|
||
+ int embed_stage1_5 (char *stage1_5, int drive, int partition)
|
||
+ {
|
||
+ /* We install GRUB into the MBR, so try to embed the
|
||
+ Stage 1.5 in the sectors right after the MBR. */
|
||
+ sprint_device (drive, partition);
|
||
+ grub_sprintf (cmd_arg, "%s %s", stage1_5, device);
|
||
+
|
||
+ /* Notify what will be run. */
|
||
+ grub_printf (" Running \"embed %s\"... ", cmd_arg);
|
||
+
|
||
+ embed_func (cmd_arg, flags);
|
||
+ if (! errnum)
|
||
+ {
|
||
+ /* Construct the blocklist representation. */
|
||
+ grub_sprintf (buffer, "%s%s", device, embed_info);
|
||
+ grub_printf ("succeeded\n");
|
||
+ return 1;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ grub_printf ("failed (this is not fatal)\n");
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ struct stage1_5_map {
|
||
+ char *fsys;
|
||
+ char *name;
|
||
+ };
|
||
+ struct stage1_5_map stage1_5_map[] =
|
||
+ {
|
||
+ {"ext2fs", "/e2fs_stage1_5"},
|
||
+ {"fat", "/fat_stage1_5"},
|
||
+ {"ufs2", "/ufs2_stage1_5"},
|
||
+ {"ffs", "/ffs_stage1_5"},
|
||
+ {"iso9660", "/iso9660_stage1_5"},
|
||
+ {"jfs", "/jfs_stage1_5"},
|
||
+ {"minix", "/minix_stage1_5"},
|
||
+ {"reiserfs", "/reiserfs_stage1_5"},
|
||
+ {"vstafs", "/vstafs_stage1_5"},
|
||
+ {"xfs", "/xfs_stage1_5"}
|
||
+ };
|
||
+
|
||
+ tmp_drive = saved_drive;
|
||
+ tmp_partition = saved_partition;
|
||
+
|
||
+ /* Check if the user specifies --force-lba. */
|
||
+ while (1)
|
||
+ {
|
||
+ if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
|
||
+ {
|
||
+ is_force_lba = 1;
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+ else if (grub_memcmp ("--prefix=", arg, sizeof ("--prefix=") - 1) == 0)
|
||
+ {
|
||
+ prefix = arg + sizeof ("--prefix=") - 1;
|
||
+ arg = skip_to (0, arg);
|
||
+ nul_terminate (prefix);
|
||
+ }
|
||
+#ifdef GRUB_UTIL
|
||
+ else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
|
||
+ {
|
||
+ stage2_arg = arg;
|
||
+ arg = skip_to (0, arg);
|
||
+ nul_terminate (stage2_arg);
|
||
+ }
|
||
+#endif /* GRUB_UTIL */
|
||
+ else
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ install_ptr = arg;
|
||
+ image_ptr = skip_to (0, install_ptr);
|
||
+
|
||
+ /* Make sure that INSTALL_PTR is valid. */
|
||
+ set_device (install_ptr);
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+
|
||
+ installed_drive = current_drive;
|
||
+ installed_partition = current_partition;
|
||
+
|
||
+ /* Mount the drive pointed by IMAGE_PTR. */
|
||
+ if (*image_ptr)
|
||
+ {
|
||
+ /* If the drive/partition where the images reside is specified,
|
||
+ get the drive and the partition. */
|
||
+ set_device (image_ptr);
|
||
+ if (errnum)
|
||
+ return 1;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* If omitted, use SAVED_PARTITION and SAVED_DRIVE. */
|
||
+ current_drive = saved_drive;
|
||
+ current_partition = saved_partition;
|
||
+ }
|
||
+
|
||
+ image_drive = saved_drive = current_drive;
|
||
+ image_partition = saved_partition = current_partition;
|
||
+
|
||
+ /* Open it. */
|
||
+ if (! open_device ())
|
||
+ goto fail;
|
||
+
|
||
+ /* Check if stage1 exists. If the user doesn't specify the option
|
||
+ `--prefix', attempt /boot/grub and /grub. */
|
||
+ /* NOTE: It is dangerous to run this command without `--prefix' in the
|
||
+ grub shell, since that affects `--stage2'. */
|
||
+ if (! prefix)
|
||
+ {
|
||
+ prefix = "/boot/grub";
|
||
+ grub_sprintf (stage1, "%s%s", prefix, "/stage1");
|
||
+ if (! check_file (stage1))
|
||
+ {
|
||
+ errnum = ERR_NONE;
|
||
+ prefix = "/grub";
|
||
+ grub_sprintf (stage1, "%s%s", prefix, "/stage1");
|
||
+ if (! check_file (stage1))
|
||
+ goto fail;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ grub_sprintf (stage1, "%s%s", prefix, "/stage1");
|
||
+ if (! check_file (stage1))
|
||
+ goto fail;
|
||
+ }
|
||
+
|
||
+ /* The prefix was determined. */
|
||
+ grub_sprintf (stage2, "%s%s", prefix, "/stage2");
|
||
+ grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst");
|
||
+ *real_config_filename = 0;
|
||
+
|
||
+ /* Check if stage2 exists. */
|
||
+ if (! check_file (stage2))
|
||
+ goto fail;
|
||
+
|
||
+ {
|
||
+ char *fsys = fsys_table[fsys_type].name;
|
||
+ int i;
|
||
+ int size = sizeof (stage1_5_map) / sizeof (stage1_5_map[0]);
|
||
+
|
||
+ /* Iterate finding the same filesystem name as FSYS. */
|
||
+ for (i = 0; i < size; i++)
|
||
+ if (grub_strcmp (fsys, stage1_5_map[i].fsys) == 0)
|
||
+ {
|
||
+ /* OK, check if the Stage 1.5 exists. */
|
||
+ char stage1_5[64];
|
||
+
|
||
+ grub_sprintf (stage1_5, "%s%s", prefix, stage1_5_map[i].name);
|
||
+ if (check_file (stage1_5))
|
||
+ {
|
||
+ if (embed_stage1_5 (stage1_5,
|
||
+ installed_drive, installed_partition)
|
||
+ || embed_stage1_5 (stage1_5,
|
||
+ image_drive, image_partition))
|
||
+ {
|
||
+ grub_strcpy (real_config_filename, config_filename);
|
||
+ sprint_device (image_drive, image_partition);
|
||
+ grub_sprintf (config_filename, "%s%s", device, stage2);
|
||
+ grub_strcpy (stage2, buffer);
|
||
+ }
|
||
+ }
|
||
+ errnum = 0;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Construct a string that is used by the command "install" as its
|
||
+ arguments. */
|
||
+ sprint_device (installed_drive, installed_partition);
|
||
+
|
||
+#if 1
|
||
+ /* Don't embed a drive number unnecessarily. */
|
||
+ grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s %s",
|
||
+ is_force_lba? "--force-lba " : "",
|
||
+ stage2_arg? stage2_arg : "",
|
||
+ stage2_arg? " " : "",
|
||
+ stage1,
|
||
+ (installed_drive != image_drive) ? "d " : "",
|
||
+ device,
|
||
+ stage2,
|
||
+ config_filename,
|
||
+ real_config_filename);
|
||
+#else /* NOT USED */
|
||
+ /* This code was used, because we belived some BIOSes had a problem
|
||
+ that they didn't pass a booting drive correctly. It turned out,
|
||
+ however, stage1 could trash a booting drive when checking LBA support,
|
||
+ because some BIOSes modified the register %dx in INT 13H, AH=48H.
|
||
+ So it becamed unclear whether GRUB should use a pre-defined booting
|
||
+ drive or not. If the problem still exists, it would be necessary to
|
||
+ switch back to this code. */
|
||
+ grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s %s",
|
||
+ is_force_lba? "--force-lba " : "",
|
||
+ stage2_arg? stage2_arg : "",
|
||
+ stage2_arg? " " : "",
|
||
+ stage1,
|
||
+ device,
|
||
+ stage2,
|
||
+ config_filename,
|
||
+ real_config_filename);
|
||
+#endif /* NOT USED */
|
||
+
|
||
+ /* Notify what will be run. */
|
||
+ grub_printf (" Running \"install %s\"... ", cmd_arg);
|
||
+
|
||
+ /* Make sure that SAVED_DRIVE and SAVED_PARTITION are identical
|
||
+ with IMAGE_DRIVE and IMAGE_PARTITION, respectively. */
|
||
+ saved_drive = image_drive;
|
||
+ saved_partition = image_partition;
|
||
+
|
||
+ /* Run the command. */
|
||
+ if (! install_func (cmd_arg, flags))
|
||
+ grub_printf ("succeeded\nDone.\n");
|
||
+ else
|
||
+ grub_printf ("failed\n");
|
||
+
|
||
+ fail:
|
||
+ saved_drive = tmp_drive;
|
||
+ saved_partition = tmp_partition;
|
||
+ return errnum;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_setup =
|
||
+{
|
||
+ "setup",
|
||
+ setup_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]",
|
||
+ "Set up the installation of GRUB automatically. This command uses"
|
||
+ " the more flexible command \"install\" in the backend and installs"
|
||
+ " GRUB into the device INSTALL_DEVICE. If IMAGE_DEVICE is specified,"
|
||
+ " then find the GRUB images in the device IMAGE_DEVICE, otherwise"
|
||
+ " use the current \"root device\", which can be set by the command"
|
||
+ " \"root\". If you know that your BIOS should support LBA but GRUB"
|
||
+ " doesn't work in LBA mode, specify the option `--force-lba'."
|
||
+ " If you install GRUB under the grub shell and you cannot unmount the"
|
||
+ " partition where GRUB images reside, specify the option `--stage2'"
|
||
+ " to tell GRUB the file name under your OS."
|
||
+};
|
||
+
|
||
+
|
||
+#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
|
||
+/* terminal */
|
||
+static int
|
||
+terminal_func (char *arg, int flags)
|
||
+{
|
||
+ /* The index of the default terminal in TERM_TABLE. */
|
||
+ int default_term = -1;
|
||
+ struct term_entry *prev_term = current_term;
|
||
+ int to = -1;
|
||
+ int lines = 0;
|
||
+ int no_message = 0;
|
||
+ unsigned long term_flags = 0;
|
||
+ /* XXX: Assume less than 32 terminals. */
|
||
+ unsigned long term_bitmap = 0;
|
||
+
|
||
+ /* Get GNU-style long options. */
|
||
+ while (1)
|
||
+ {
|
||
+ if (grub_memcmp (arg, "--dumb", sizeof ("--dumb") - 1) == 0)
|
||
+ term_flags |= TERM_DUMB;
|
||
+ else if (grub_memcmp (arg, "--no-echo", sizeof ("--no-echo") - 1) == 0)
|
||
+ /* ``--no-echo'' implies ``--no-edit''. */
|
||
+ term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT);
|
||
+ else if (grub_memcmp (arg, "--no-edit", sizeof ("--no-edit") - 1) == 0)
|
||
+ term_flags |= TERM_NO_EDIT;
|
||
+ else if (grub_memcmp (arg, "--timeout=", sizeof ("--timeout=") - 1) == 0)
|
||
+ {
|
||
+ char *val = arg + sizeof ("--timeout=") - 1;
|
||
+
|
||
+ if (! safe_parse_maxint (&val, &to))
|
||
+ return 1;
|
||
+ }
|
||
+ else if (grub_memcmp (arg, "--lines=", sizeof ("--lines=") - 1) == 0)
|
||
+ {
|
||
+ char *val = arg + sizeof ("--lines=") - 1;
|
||
+
|
||
+ if (! safe_parse_maxint (&val, &lines))
|
||
+ return 1;
|
||
+
|
||
+ /* Probably less than four is meaningless.... */
|
||
+ if (lines < 4)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+ }
|
||
+ else if (grub_memcmp (arg, "--silent", sizeof ("--silent") - 1) == 0)
|
||
+ no_message = 1;
|
||
+ else
|
||
+ break;
|
||
+
|
||
+ arg = skip_to (0, arg);
|
||
+ }
|
||
+
|
||
+ /* If no argument is specified, show current setting. */
|
||
+ if (! *arg)
|
||
+ {
|
||
+ grub_printf ("%s%s%s%s\n",
|
||
+ current_term->name,
|
||
+ current_term->flags & TERM_DUMB ? " (dumb)" : "",
|
||
+ current_term->flags & TERM_NO_EDIT ? " (no edit)" : "",
|
||
+ current_term->flags & TERM_NO_ECHO ? " (no echo)" : "");
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ while (*arg)
|
||
+ {
|
||
+ int i;
|
||
+ char *next = skip_to (0, arg);
|
||
+
|
||
+ nul_terminate (arg);
|
||
+
|
||
+ for (i = 0; term_table[i].name; i++)
|
||
+ {
|
||
+ if (grub_strcmp (arg, term_table[i].name) == 0)
|
||
+ {
|
||
+ if (term_table[i].flags & TERM_NEED_INIT)
|
||
+ {
|
||
+ errnum = ERR_DEV_NEED_INIT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ if (default_term < 0)
|
||
+ default_term = i;
|
||
+
|
||
+ term_bitmap |= (1 << i);
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (! term_table[i].name)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ arg = next;
|
||
+ }
|
||
+
|
||
+ /* If multiple terminals are specified, wait until the user pushes any
|
||
+ key on one of the terminals. */
|
||
+ if (term_bitmap & ~(1 << default_term))
|
||
+ {
|
||
+ int time1, time2 = -1;
|
||
+
|
||
+ /* XXX: Disable the pager. */
|
||
+ count_lines = -1;
|
||
+
|
||
+ /* Get current time. */
|
||
+ while ((time1 = getrtsecs ()) == 0xFF)
|
||
+ ;
|
||
+
|
||
+ /* Wait for a key input. */
|
||
+ while (to)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; term_table[i].name; i++)
|
||
+ {
|
||
+ if (term_bitmap & (1 << i))
|
||
+ {
|
||
+ if (term_table[i].checkkey () >= 0)
|
||
+ {
|
||
+ (void) term_table[i].getkey ();
|
||
+ default_term = i;
|
||
+
|
||
+ goto end;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Prompt the user, once per sec. */
|
||
+ if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF)
|
||
+ {
|
||
+ if (! no_message)
|
||
+ {
|
||
+ /* Need to set CURRENT_TERM to each of selected
|
||
+ terminals. */
|
||
+ for (i = 0; term_table[i].name; i++)
|
||
+ if (term_bitmap & (1 << i))
|
||
+ {
|
||
+ current_term = term_table + i;
|
||
+ grub_printf ("\rPress any key to continue.\n");
|
||
+ }
|
||
+
|
||
+ /* Restore CURRENT_TERM. */
|
||
+ current_term = prev_term;
|
||
+ }
|
||
+
|
||
+ time2 = time1;
|
||
+ if (to > 0)
|
||
+ to--;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ end:
|
||
+ current_term = term_table + default_term;
|
||
+ current_term->flags = term_flags;
|
||
+
|
||
+ if (lines)
|
||
+ max_lines = lines;
|
||
+ else
|
||
+ /* 24 would be a good default value. */
|
||
+ max_lines = 24;
|
||
+
|
||
+ /* If the interface is currently the command-line,
|
||
+ restart it to repaint the screen. */
|
||
+ if (current_term != prev_term && (flags & BUILTIN_CMDLINE))
|
||
+ grub_longjmp (restart_cmdline_env, 0);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_terminal =
|
||
+{
|
||
+ "terminal",
|
||
+ terminal_func,
|
||
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules]",
|
||
+ "Select a terminal. When multiple terminals are specified, wait until"
|
||
+ " you push any key to continue. If both console and serial are specified,"
|
||
+ " the terminal to which you input a key first will be selected. If no"
|
||
+ " argument is specified, print current setting. The option --dumb"
|
||
+ " specifies that your terminal is dumb, otherwise, vt100-compatibility"
|
||
+ " is assumed. If you specify --no-echo, input characters won't be echoed."
|
||
+ " If you specify --no-edit, the BASH-like editing feature will be disabled."
|
||
+ " If --timeout is present, this command will wait at most for SECS"
|
||
+ " seconds. The option --lines specifies the maximum number of lines."
|
||
+ " The option --silent is used to suppress messages."
|
||
+};
|
||
+#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */
|
||
+
|
||
+
|
||
+#ifdef SUPPORT_SERIAL
|
||
+static int
|
||
+terminfo_func (char *arg, int flags)
|
||
+{
|
||
+ struct terminfo term;
|
||
+
|
||
+ if (*arg)
|
||
+ {
|
||
+ struct
|
||
+ {
|
||
+ const char *name;
|
||
+ char *var;
|
||
+ }
|
||
+ options[] =
|
||
+ {
|
||
+ {"--name=", term.name},
|
||
+ {"--cursor-address=", term.cursor_address},
|
||
+ {"--clear-screen=", term.clear_screen},
|
||
+ {"--enter-standout-mode=", term.enter_standout_mode},
|
||
+ {"--exit-standout-mode=", term.exit_standout_mode}
|
||
+ };
|
||
+
|
||
+ grub_memset (&term, 0, sizeof (term));
|
||
+
|
||
+ while (*arg)
|
||
+ {
|
||
+ int i;
|
||
+ char *next = skip_to (0, arg);
|
||
+
|
||
+ nul_terminate (arg);
|
||
+
|
||
+ for (i = 0; i < sizeof (options) / sizeof (options[0]); i++)
|
||
+ {
|
||
+ const char *name = options[i].name;
|
||
+ int len = grub_strlen (name);
|
||
+
|
||
+ if (! grub_memcmp (arg, name, len))
|
||
+ {
|
||
+ grub_strcpy (options[i].var, ti_unescape_string (arg + len));
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (i == sizeof (options) / sizeof (options[0]))
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return errnum;
|
||
+ }
|
||
+
|
||
+ arg = next;
|
||
+ }
|
||
+
|
||
+ if (term.name[0] == 0 || term.cursor_address[0] == 0)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return errnum;
|
||
+ }
|
||
+
|
||
+ ti_set_term (&term);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* No option specifies printing out current settings. */
|
||
+ ti_get_term (&term);
|
||
+
|
||
+ grub_printf ("name=%s\n",
|
||
+ ti_escape_string (term.name));
|
||
+ grub_printf ("cursor_address=%s\n",
|
||
+ ti_escape_string (term.cursor_address));
|
||
+ grub_printf ("clear_screen=%s\n",
|
||
+ ti_escape_string (term.clear_screen));
|
||
+ grub_printf ("enter_standout_mode=%s\n",
|
||
+ ti_escape_string (term.enter_standout_mode));
|
||
+ grub_printf ("exit_standout_mode=%s\n",
|
||
+ ti_escape_string (term.exit_standout_mode));
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_terminfo =
|
||
+{
|
||
+ "terminfo",
|
||
+ terminfo_func,
|
||
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "terminfo [--name=NAME --cursor-address=SEQ [--clear-screen=SEQ]"
|
||
+ " [--enter-standout-mode=SEQ] [--exit-standout-mode=SEQ]]",
|
||
+
|
||
+ "Define the capabilities of your terminal. Use this command to"
|
||
+ " define escape sequences, if it is not vt100-compatible."
|
||
+ " You may use \\e for ESC and ^X for a control character."
|
||
+ " If no option is specified, the current settings are printed."
|
||
+};
|
||
+#endif /* SUPPORT_SERIAL */
|
||
+
|
||
+
|
||
+/* testload */
|
||
+static int
|
||
+testload_func (char *arg, int flags)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ kernel_type = KERNEL_TYPE_NONE;
|
||
+
|
||
+ if (! grub_open (arg))
|
||
+ return 1;
|
||
+
|
||
+ disk_read_hook = disk_read_print_func;
|
||
+
|
||
+ /* Perform filesystem test on the specified file. */
|
||
+ /* Read whole file first. */
|
||
+ grub_printf ("Whole file: ");
|
||
+
|
||
+ grub_read ((char *) RAW_ADDR (0x100000), -1);
|
||
+
|
||
+ /* Now compare two sections of the file read differently. */
|
||
+
|
||
+ for (i = 0; i < 0x10ac0; i++)
|
||
+ {
|
||
+ *((unsigned char *) RAW_ADDR (0x200000 + i)) = 0;
|
||
+ *((unsigned char *) RAW_ADDR (0x300000 + i)) = 1;
|
||
+ }
|
||
+
|
||
+ /* First partial read. */
|
||
+ grub_printf ("\nPartial read 1: ");
|
||
+
|
||
+ grub_seek (0);
|
||
+ grub_read ((char *) RAW_ADDR (0x200000), 0x7);
|
||
+ grub_read ((char *) RAW_ADDR (0x200007), 0x100);
|
||
+ grub_read ((char *) RAW_ADDR (0x200107), 0x10);
|
||
+ grub_read ((char *) RAW_ADDR (0x200117), 0x999);
|
||
+ grub_read ((char *) RAW_ADDR (0x200ab0), 0x10);
|
||
+ grub_read ((char *) RAW_ADDR (0x200ac0), 0x10000);
|
||
+
|
||
+ /* Second partial read. */
|
||
+ grub_printf ("\nPartial read 2: ");
|
||
+
|
||
+ grub_seek (0);
|
||
+ grub_read ((char *) RAW_ADDR (0x300000), 0x10000);
|
||
+ grub_read ((char *) RAW_ADDR (0x310000), 0x10);
|
||
+ grub_read ((char *) RAW_ADDR (0x310010), 0x7);
|
||
+ grub_read ((char *) RAW_ADDR (0x310017), 0x10);
|
||
+ grub_read ((char *) RAW_ADDR (0x310027), 0x999);
|
||
+ grub_read ((char *) RAW_ADDR (0x3109c0), 0x100);
|
||
+
|
||
+ grub_printf ("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
|
||
+ *((int *) RAW_ADDR (0x200000)),
|
||
+ *((int *) RAW_ADDR (0x200004)),
|
||
+ *((int *) RAW_ADDR (0x200008)),
|
||
+ *((int *) RAW_ADDR (0x20000c)));
|
||
+
|
||
+ grub_printf ("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
|
||
+ *((int *) RAW_ADDR (0x300000)),
|
||
+ *((int *) RAW_ADDR (0x300004)),
|
||
+ *((int *) RAW_ADDR (0x300008)),
|
||
+ *((int *) RAW_ADDR (0x30000c)));
|
||
+
|
||
+ for (i = 0; i < 0x10ac0; i++)
|
||
+ if (*((unsigned char *) RAW_ADDR (0x200000 + i))
|
||
+ != *((unsigned char *) RAW_ADDR (0x300000 + i)))
|
||
+ break;
|
||
+
|
||
+ grub_printf ("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos);
|
||
+ disk_read_hook = 0;
|
||
+ grub_close ();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_testload =
|
||
+{
|
||
+ "testload",
|
||
+ testload_func,
|
||
+ BUILTIN_CMDLINE,
|
||
+ "testload FILE",
|
||
+ "Read the entire contents of FILE in several different ways and"
|
||
+ " compares them, to test the filesystem code. The output is somewhat"
|
||
+ " cryptic, but if no errors are reported and the final `i=X,"
|
||
+ " filepos=Y' reading has X and Y equal, then it is definitely"
|
||
+ " consistent, and very likely works correctly subject to a"
|
||
+ " consistent offset error. If this test succeeds, then a good next"
|
||
+ " step is to try loading a kernel."
|
||
+};
|
||
+
|
||
+
|
||
+/* testvbe MODE */
|
||
+static int
|
||
+testvbe_func (char *arg, int flags)
|
||
+{
|
||
+ int mode_number;
|
||
+ struct vbe_controller controller;
|
||
+ struct vbe_mode mode;
|
||
+
|
||
+ if (! *arg)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ if (! safe_parse_maxint (&arg, &mode_number))
|
||
+ return 1;
|
||
+
|
||
+ /* Preset `VBE2'. */
|
||
+ grub_memmove (controller.signature, "VBE2", 4);
|
||
+
|
||
+ /* Detect VBE BIOS. */
|
||
+ if (get_vbe_controller_info (&controller) != 0x004F)
|
||
+ {
|
||
+ grub_printf (" VBE BIOS is not present.\n");
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (controller.version < 0x0200)
|
||
+ {
|
||
+ grub_printf (" VBE version %d.%d is not supported.\n",
|
||
+ (int) (controller.version >> 8),
|
||
+ (int) (controller.version & 0xFF));
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (get_vbe_mode_info (mode_number, &mode) != 0x004F
|
||
+ || (mode.mode_attributes & 0x0091) != 0x0091)
|
||
+ {
|
||
+ grub_printf (" Mode 0x%x is not supported.\n", mode_number);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* Now trip to the graphics mode. */
|
||
+ if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F)
|
||
+ {
|
||
+ grub_printf (" Switching to Mode 0x%x failed.\n", mode_number);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* Draw something on the screen... */
|
||
+ {
|
||
+ unsigned char *base_buf = (unsigned char *) mode.phys_base;
|
||
+ int scanline = controller.version >= 0x0300
|
||
+ ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline;
|
||
+ /* FIXME: this assumes that any depth is a modulo of 8. */
|
||
+ int bpp = mode.bits_per_pixel / 8;
|
||
+ int width = mode.x_resolution;
|
||
+ int height = mode.y_resolution;
|
||
+ int x, y;
|
||
+ unsigned color = 0;
|
||
+
|
||
+ /* Iterate drawing on the screen, until the user hits any key. */
|
||
+ while (checkkey () == -1)
|
||
+ {
|
||
+ for (y = 0; y < height; y++)
|
||
+ {
|
||
+ unsigned char *line_buf = base_buf + scanline * y;
|
||
+
|
||
+ for (x = 0; x < width; x++)
|
||
+ {
|
||
+ unsigned char *buf = line_buf + bpp * x;
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < bpp; i++, buf++)
|
||
+ *buf = (color >> (i * 8)) & 0xff;
|
||
+ }
|
||
+
|
||
+ color++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Discard the input. */
|
||
+ getkey ();
|
||
+ }
|
||
+
|
||
+ /* Back to the default text mode. */
|
||
+ if (set_vbe_mode (0x03) != 0x004F)
|
||
+ {
|
||
+ /* Why?! */
|
||
+ grub_reboot ();
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_testvbe =
|
||
+{
|
||
+ "testvbe",
|
||
+ testvbe_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "testvbe MODE",
|
||
+ "Test the VBE mode MODE. Hit any key to return."
|
||
+};
|
||
+
|
||
+
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+/* tftpserver */
|
||
+static int
|
||
+tftpserver_func (char *arg, int flags)
|
||
+{
|
||
+ if (! *arg || ! ifconfig (0, 0, 0, arg))
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ print_network_configuration ();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_tftpserver =
|
||
+{
|
||
+ "tftpserver",
|
||
+ tftpserver_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "tftpserver IPADDR",
|
||
+ "Override the TFTP server address."
|
||
+};
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+
|
||
+
|
||
+/* timeout */
|
||
+static int
|
||
+timeout_func (char *arg, int flags)
|
||
+{
|
||
+ if (! safe_parse_maxint (&arg, &grub_timeout))
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_timeout =
|
||
+{
|
||
+ "timeout",
|
||
+ timeout_func,
|
||
+ BUILTIN_MENU,
|
||
+#if 0
|
||
+ "timeout SEC",
|
||
+ "Set a timeout, in SEC seconds, before automatically booting the"
|
||
+ " default entry (normally the first entry defined)."
|
||
+#endif
|
||
+};
|
||
+
|
||
+
|
||
+/* title */
|
||
+static int
|
||
+title_func (char *arg, int flags)
|
||
+{
|
||
+ /* This function is not actually used at least currently. */
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_title =
|
||
+{
|
||
+ "title",
|
||
+ title_func,
|
||
+ BUILTIN_TITLE,
|
||
+#if 0
|
||
+ "title [NAME ...]",
|
||
+ "Start a new boot entry, and set its name to the contents of the"
|
||
+ " rest of the line, starting with the first non-space character."
|
||
+#endif
|
||
+};
|
||
+
|
||
+
|
||
+/* unhide */
|
||
+static int
|
||
+unhide_func (char *arg, int flags)
|
||
+{
|
||
+ if (! set_device (arg))
|
||
+ return 1;
|
||
+
|
||
+ if (! set_partition_hidden_flag (0))
|
||
+ return 1;
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_unhide =
|
||
+{
|
||
+ "unhide",
|
||
+ unhide_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
|
||
+ "unhide PARTITION",
|
||
+ "Unhide PARTITION by clearing the \"hidden\" bit in its"
|
||
+ " partition type code."
|
||
+};
|
||
+
|
||
+
|
||
+/* uppermem */
|
||
+static int
|
||
+uppermem_func (char *arg, int flags)
|
||
+{
|
||
+ if (! safe_parse_maxint (&arg, (int *) &mbi.mem_upper))
|
||
+ return 1;
|
||
+
|
||
+ mbi.flags &= ~MB_INFO_MEM_MAP;
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_uppermem =
|
||
+{
|
||
+ "uppermem",
|
||
+ uppermem_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "uppermem KBYTES",
|
||
+ "Force GRUB to assume that only KBYTES kilobytes of upper memory are"
|
||
+ " installed. Any system address range maps are discarded."
|
||
+};
|
||
+
|
||
+
|
||
+/* vbeprobe */
|
||
+static int
|
||
+vbeprobe_func (char *arg, int flags)
|
||
+{
|
||
+ struct vbe_controller controller;
|
||
+ unsigned short *mode_list;
|
||
+ int mode_number = -1;
|
||
+
|
||
+ auto unsigned long vbe_far_ptr_to_linear (unsigned long);
|
||
+
|
||
+ unsigned long vbe_far_ptr_to_linear (unsigned long ptr)
|
||
+ {
|
||
+ unsigned short seg = (ptr >> 16);
|
||
+ unsigned short off = (ptr & 0xFFFF);
|
||
+
|
||
+ return (seg << 4) + off;
|
||
+ }
|
||
+
|
||
+ if (*arg)
|
||
+ {
|
||
+ if (! safe_parse_maxint (&arg, &mode_number))
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Set the signature to `VBE2', to obtain VBE 3.0 information. */
|
||
+ grub_memmove (controller.signature, "VBE2", 4);
|
||
+
|
||
+ if (get_vbe_controller_info (&controller) != 0x004F)
|
||
+ {
|
||
+ grub_printf (" VBE BIOS is not present.\n");
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* Check the version. */
|
||
+ if (controller.version < 0x0200)
|
||
+ {
|
||
+ grub_printf (" VBE version %d.%d is not supported.\n",
|
||
+ (int) (controller.version >> 8),
|
||
+ (int) (controller.version & 0xFF));
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* Print some information. */
|
||
+ grub_printf (" VBE version %d.%d\n",
|
||
+ (int) (controller.version >> 8),
|
||
+ (int) (controller.version & 0xFF));
|
||
+
|
||
+ /* Iterate probing modes. */
|
||
+ for (mode_list
|
||
+ = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode);
|
||
+ *mode_list != 0xFFFF;
|
||
+ mode_list++)
|
||
+ {
|
||
+ struct vbe_mode mode;
|
||
+
|
||
+ if (get_vbe_mode_info (*mode_list, &mode) != 0x004F)
|
||
+ continue;
|
||
+
|
||
+ /* Skip this, if this is not supported or linear frame buffer
|
||
+ mode is not support. */
|
||
+ if ((mode.mode_attributes & 0x0081) != 0x0081)
|
||
+ continue;
|
||
+
|
||
+ if (mode_number == -1 || mode_number == *mode_list)
|
||
+ {
|
||
+ char *model;
|
||
+ switch (mode.memory_model)
|
||
+ {
|
||
+ case 0x00: model = "Text"; break;
|
||
+ case 0x01: model = "CGA graphics"; break;
|
||
+ case 0x02: model = "Hercules graphics"; break;
|
||
+ case 0x03: model = "Planar"; break;
|
||
+ case 0x04: model = "Packed pixel"; break;
|
||
+ case 0x05: model = "Non-chain 4, 256 color"; break;
|
||
+ case 0x06: model = "Direct Color"; break;
|
||
+ case 0x07: model = "YUV"; break;
|
||
+ default: model = "Unknown"; break;
|
||
+ }
|
||
+
|
||
+ grub_printf (" 0x%x: %s, %ux%ux%u\n",
|
||
+ (unsigned) *mode_list,
|
||
+ model,
|
||
+ (unsigned) mode.x_resolution,
|
||
+ (unsigned) mode.y_resolution,
|
||
+ (unsigned) mode.bits_per_pixel);
|
||
+
|
||
+ if (mode_number != -1)
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (mode_number != -1 && mode_number != *mode_list)
|
||
+ grub_printf (" Mode 0x%x is not found or supported.\n", mode_number);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static struct builtin builtin_vbeprobe =
|
||
+{
|
||
+ "vbeprobe",
|
||
+ vbeprobe_func,
|
||
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||
+ "vbeprobe [MODE]",
|
||
+ "Probe VBE information. If the mode number MODE is specified, show only"
|
||
+ " the information about only the mode."
|
||
+};
|
||
+
|
||
+
|
||
+/* The table of builtin commands. Sorted in dictionary order. */
|
||
+struct builtin *builtin_table[] =
|
||
+{
|
||
+ &builtin_blocklist,
|
||
+ &builtin_boot,
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+ &builtin_bootp,
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+ &builtin_cat,
|
||
+ &builtin_chainloader,
|
||
+ &builtin_cmp,
|
||
+ &builtin_color,
|
||
+ &builtin_configfile,
|
||
+ &builtin_debug,
|
||
+ &builtin_default,
|
||
+#ifdef GRUB_UTIL
|
||
+ &builtin_device,
|
||
+#endif /* GRUB_UTIL */
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+ &builtin_dhcp,
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+ &builtin_displayapm,
|
||
+ &builtin_displaymem,
|
||
+#ifdef GRUB_UTIL
|
||
+ &builtin_dump,
|
||
+#endif /* GRUB_UTIL */
|
||
+ &builtin_embed,
|
||
+ &builtin_fallback,
|
||
+ &builtin_find,
|
||
+ &builtin_fstest,
|
||
+ &builtin_geometry,
|
||
+ &builtin_halt,
|
||
+ &builtin_help,
|
||
+ &builtin_hiddenmenu,
|
||
+ &builtin_hide,
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+ &builtin_ifconfig,
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+ &builtin_impsprobe,
|
||
+ &builtin_initrd,
|
||
+ &builtin_install,
|
||
+ &builtin_ioprobe,
|
||
+ &builtin_kernel,
|
||
+ &builtin_lock,
|
||
+ &builtin_makeactive,
|
||
+ &builtin_map,
|
||
+#ifdef USE_MD5_PASSWORDS
|
||
+ &builtin_md5crypt,
|
||
+#endif /* USE_MD5_PASSWORDS */
|
||
+ &builtin_module,
|
||
+ &builtin_modulenounzip,
|
||
+ &builtin_pager,
|
||
+ &builtin_partnew,
|
||
+ &builtin_parttype,
|
||
+ &builtin_password,
|
||
+ &builtin_pause,
|
||
+#ifdef GRUB_UTIL
|
||
+ &builtin_quit,
|
||
+#endif /* GRUB_UTIL */
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+ &builtin_rarp,
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+ &builtin_read,
|
||
+ &builtin_reboot,
|
||
+ &builtin_root,
|
||
+ &builtin_rootnoverify,
|
||
+ &builtin_savedefault,
|
||
+#ifdef SUPPORT_SERIAL
|
||
+ &builtin_serial,
|
||
+#endif /* SUPPORT_SERIAL */
|
||
+ &builtin_setkey,
|
||
+ &builtin_setup,
|
||
+#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
|
||
+ &builtin_terminal,
|
||
+#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */
|
||
+#ifdef SUPPORT_SERIAL
|
||
+ &builtin_terminfo,
|
||
+#endif /* SUPPORT_SERIAL */
|
||
+ &builtin_testload,
|
||
+ &builtin_testvbe,
|
||
+#ifdef SUPPORT_NETBOOT
|
||
+ &builtin_tftpserver,
|
||
+#endif /* SUPPORT_NETBOOT */
|
||
+ &builtin_timeout,
|
||
+ &builtin_title,
|
||
+ &builtin_unhide,
|
||
+ &builtin_uppermem,
|
||
+ &builtin_vbeprobe,
|
||
+ 0
|
||
+};
|
||
diff -Nur grub-0.97/stage2/char_io.c grub-0.97-patched/stage2/char_io.c
|
||
--- grub-0.97/stage2/char_io.c 2005-02-01 21:51:23.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/char_io.c 2012-11-11 17:06:52.556085241 +0100
|
||
@@ -35,6 +35,7 @@
|
||
{
|
||
"console",
|
||
0,
|
||
+ 24,
|
||
console_putchar,
|
||
console_checkkey,
|
||
console_getkey,
|
||
@@ -43,13 +44,16 @@
|
||
console_cls,
|
||
console_setcolorstate,
|
||
console_setcolor,
|
||
- console_setcursor
|
||
+ console_setcursor,
|
||
+ 0,
|
||
+ 0
|
||
},
|
||
#ifdef SUPPORT_SERIAL
|
||
{
|
||
"serial",
|
||
/* A serial device must be initialized. */
|
||
TERM_NEED_INIT,
|
||
+ 24,
|
||
serial_putchar,
|
||
serial_checkkey,
|
||
serial_getkey,
|
||
@@ -58,6 +62,8 @@
|
||
serial_cls,
|
||
serial_setcolorstate,
|
||
0,
|
||
+ 0,
|
||
+ 0,
|
||
0
|
||
},
|
||
#endif /* SUPPORT_SERIAL */
|
||
@@ -65,6 +71,7 @@
|
||
{
|
||
"hercules",
|
||
0,
|
||
+ 24,
|
||
hercules_putchar,
|
||
console_checkkey,
|
||
console_getkey,
|
||
@@ -73,9 +80,28 @@
|
||
hercules_cls,
|
||
hercules_setcolorstate,
|
||
hercules_setcolor,
|
||
- hercules_setcursor
|
||
+ hercules_setcursor,
|
||
+ 0,
|
||
+ 0
|
||
},
|
||
#endif /* SUPPORT_HERCULES */
|
||
+#ifdef SUPPORT_GRAPHICS
|
||
+ { "graphics",
|
||
+ TERM_NEED_INIT, /* flags */
|
||
+ 30, /* number of lines */
|
||
+ graphics_putchar, /* putchar */
|
||
+ console_checkkey, /* checkkey */
|
||
+ console_getkey, /* getkey */
|
||
+ graphics_getxy, /* getxy */
|
||
+ graphics_gotoxy, /* gotoxy */
|
||
+ graphics_cls, /* cls */
|
||
+ graphics_setcolorstate, /* setcolorstate */
|
||
+ graphics_setcolor, /* setcolor */
|
||
+ graphics_setcursor, /* nocursor */
|
||
+ graphics_init, /* initialize */
|
||
+ graphics_end /* shutdown */
|
||
+ },
|
||
+#endif /* SUPPORT_GRAPHICS */
|
||
/* This must be the last entry. */
|
||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||
};
|
||
@@ -1046,13 +1072,15 @@
|
||
the following grub_printf call will print newlines. */
|
||
count_lines = -1;
|
||
|
||
+ grub_printf("\n");
|
||
if (current_term->setcolorstate)
|
||
current_term->setcolorstate (COLOR_STATE_HIGHLIGHT);
|
||
|
||
- grub_printf ("\n[Hit return to continue]");
|
||
+ grub_printf ("[Hit return to continue]");
|
||
|
||
if (current_term->setcolorstate)
|
||
current_term->setcolorstate (COLOR_STATE_NORMAL);
|
||
+
|
||
|
||
do
|
||
{
|
||
@@ -1090,7 +1118,7 @@
|
||
cls (void)
|
||
{
|
||
/* If the terminal is dumb, there is no way to clean the terminal. */
|
||
- if (current_term->flags & TERM_DUMB)
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
grub_putchar ('\n');
|
||
else
|
||
current_term->cls ();
|
||
@@ -1174,37 +1202,62 @@
|
||
}
|
||
#endif /* ! STAGE1_5 */
|
||
|
||
+#ifdef GRUB_UTIL
|
||
+# ifdef __PIC__
|
||
+# if defined(HAVE_START_SYMBOL) && defined(HAVE_END_SYMBOL)
|
||
+ extern char start[];
|
||
+ extern char end[];
|
||
+# elif defined(HAVE_USCORE_START_SYMBOL) && defined (HAVE_USCORE_END_SYMBOL)
|
||
+ extern char _start[];
|
||
+ extern char _end[];
|
||
+# endif
|
||
+# endif
|
||
+#endif
|
||
int
|
||
-memcheck (int addr, int len)
|
||
+memcheck (unsigned long addr, unsigned long len)
|
||
{
|
||
#ifdef GRUB_UTIL
|
||
- auto int start_addr (void);
|
||
- auto int end_addr (void);
|
||
+# ifdef __PIC__
|
||
+# if defined(HAVE_START_SYMBOL) && defined(HAVE_END_SYMBOL)
|
||
+ if (start <= addr && end > addr + len)
|
||
+ return ! errnum;
|
||
+# elif defined(HAVE_USCORE_START_SYMBOL) && defined (HAVE_USCORE_END_SYMBOL)
|
||
+ if (_start <= addr && _end > addr + len)
|
||
+ return ! errnum;
|
||
+# endif
|
||
+# else /* __PIC__ */
|
||
+ auto unsigned long start_addr (void);
|
||
+ auto unsigned long end_addr (void);
|
||
|
||
- auto int start_addr (void)
|
||
+ auto unsigned long start_addr (void)
|
||
{
|
||
- int ret;
|
||
-# if defined(HAVE_START_SYMBOL)
|
||
+ unsigned long ret;
|
||
+# if defined(HAVE_START_SYMBOL)
|
||
asm volatile ("movl $start, %0" : "=a" (ret));
|
||
-# elif defined(HAVE_USCORE_START_SYMBOL)
|
||
+# elif defined(HAVE_USCORE_START_SYMBOL)
|
||
asm volatile ("movl $_start, %0" : "=a" (ret));
|
||
-# endif
|
||
+# else
|
||
+ erk! /* function would return undefined data in this case - barf */
|
||
+# endif
|
||
return ret;
|
||
}
|
||
|
||
- auto int end_addr (void)
|
||
+ auto unsigned long end_addr (void)
|
||
{
|
||
- int ret;
|
||
-# if defined(HAVE_END_SYMBOL)
|
||
+ unsigned long ret;
|
||
+# if defined(HAVE_END_SYMBOL)
|
||
asm volatile ("movl $end, %0" : "=a" (ret));
|
||
-# elif defined(HAVE_USCORE_END_SYMBOL)
|
||
+# elif defined(HAVE_USCORE_END_SYMBOL)
|
||
asm volatile ("movl $_end, %0" : "=a" (ret));
|
||
-# endif
|
||
+# else
|
||
+ erk! /* function would return undefined data in this case - barf */
|
||
+# endif
|
||
return ret;
|
||
}
|
||
|
||
if (start_addr () <= addr && end_addr () > addr + len)
|
||
return ! errnum;
|
||
+# endif /* __PIC__ */
|
||
#endif /* GRUB_UTIL */
|
||
|
||
if ((addr < RAW_ADDR (0x1000))
|
||
@@ -1217,10 +1270,20 @@
|
||
return ! errnum;
|
||
}
|
||
|
||
+void
|
||
+grub_memcpy(void *dest, const void *src, int len)
|
||
+{
|
||
+ int i;
|
||
+ register char *d = (char*)dest, *s = (char*)src;
|
||
+
|
||
+ for (i = 0; i < len; i++)
|
||
+ d[i] = s[i];
|
||
+}
|
||
+
|
||
void *
|
||
grub_memmove (void *to, const void *from, int len)
|
||
{
|
||
- if (memcheck ((int) to, len))
|
||
+ if (memcheck ((unsigned long) to, len))
|
||
{
|
||
/* This assembly code is stolen from
|
||
linux-2.2.2/include/asm-i386/string.h. This is not very fast
|
||
@@ -1258,7 +1321,7 @@
|
||
{
|
||
char *p = start;
|
||
|
||
- if (memcheck ((int) start, len))
|
||
+ if (memcheck ((unsigned long) start, len))
|
||
{
|
||
while (len -- > 0)
|
||
*p ++ = c;
|
||
diff -Nur grub-0.97/stage2/char_io.c.orig grub-0.97-patched/stage2/char_io.c.orig
|
||
--- grub-0.97/stage2/char_io.c.orig 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/char_io.c.orig 2005-02-01 21:51:23.000000000 +0100
|
||
@@ -0,0 +1,1283 @@
|
||
+/* char_io.c - basic console input and output */
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License as published by
|
||
+ * the Free Software Foundation; either version 2 of the License, or
|
||
+ * (at your option) any later version.
|
||
+ *
|
||
+ * This program is distributed in the hope that it will be useful,
|
||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ * GNU General Public License for more details.
|
||
+ *
|
||
+ * You should have received a copy of the GNU General Public License
|
||
+ * along with this program; if not, write to the Free Software
|
||
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
+ */
|
||
+
|
||
+#include <shared.h>
|
||
+#include <term.h>
|
||
+
|
||
+#ifdef SUPPORT_HERCULES
|
||
+# include <hercules.h>
|
||
+#endif
|
||
+
|
||
+#ifdef SUPPORT_SERIAL
|
||
+# include <serial.h>
|
||
+#endif
|
||
+
|
||
+#ifndef STAGE1_5
|
||
+struct term_entry term_table[] =
|
||
+ {
|
||
+ {
|
||
+ "console",
|
||
+ 0,
|
||
+ console_putchar,
|
||
+ console_checkkey,
|
||
+ console_getkey,
|
||
+ console_getxy,
|
||
+ console_gotoxy,
|
||
+ console_cls,
|
||
+ console_setcolorstate,
|
||
+ console_setcolor,
|
||
+ console_setcursor
|
||
+ },
|
||
+#ifdef SUPPORT_SERIAL
|
||
+ {
|
||
+ "serial",
|
||
+ /* A serial device must be initialized. */
|
||
+ TERM_NEED_INIT,
|
||
+ serial_putchar,
|
||
+ serial_checkkey,
|
||
+ serial_getkey,
|
||
+ serial_getxy,
|
||
+ serial_gotoxy,
|
||
+ serial_cls,
|
||
+ serial_setcolorstate,
|
||
+ 0,
|
||
+ 0
|
||
+ },
|
||
+#endif /* SUPPORT_SERIAL */
|
||
+#ifdef SUPPORT_HERCULES
|
||
+ {
|
||
+ "hercules",
|
||
+ 0,
|
||
+ hercules_putchar,
|
||
+ console_checkkey,
|
||
+ console_getkey,
|
||
+ hercules_getxy,
|
||
+ hercules_gotoxy,
|
||
+ hercules_cls,
|
||
+ hercules_setcolorstate,
|
||
+ hercules_setcolor,
|
||
+ hercules_setcursor
|
||
+ },
|
||
+#endif /* SUPPORT_HERCULES */
|
||
+ /* This must be the last entry. */
|
||
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||
+ };
|
||
+
|
||
+/* This must be console. */
|
||
+struct term_entry *current_term = term_table;
|
||
+
|
||
+int max_lines = 24;
|
||
+int count_lines = -1;
|
||
+int use_pager = 1;
|
||
+#endif
|
||
+
|
||
+void
|
||
+print_error (void)
|
||
+{
|
||
+ if (errnum > ERR_NONE && errnum < MAX_ERR_NUM)
|
||
+#ifndef STAGE1_5
|
||
+ /* printf("\7\n %s\n", err_list[errnum]); */
|
||
+ printf ("\nError %u: %s\n", errnum, err_list[errnum]);
|
||
+#else /* STAGE1_5 */
|
||
+ printf ("Error %u\n", errnum);
|
||
+#endif /* STAGE1_5 */
|
||
+}
|
||
+
|
||
+char *
|
||
+convert_to_ascii (char *buf, int c,...)
|
||
+{
|
||
+ unsigned long num = *((&c) + 1), mult = 10;
|
||
+ char *ptr = buf;
|
||
+
|
||
+#ifndef STAGE1_5
|
||
+ if (c == 'x' || c == 'X')
|
||
+ mult = 16;
|
||
+
|
||
+ if ((num & 0x80000000uL) && c == 'd')
|
||
+ {
|
||
+ num = (~num) + 1;
|
||
+ *(ptr++) = '-';
|
||
+ buf++;
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ do
|
||
+ {
|
||
+ int dig = num % mult;
|
||
+ *(ptr++) = ((dig > 9) ? dig + 'a' - 10 : '0' + dig);
|
||
+ }
|
||
+ while (num /= mult);
|
||
+
|
||
+ /* reorder to correct direction!! */
|
||
+ {
|
||
+ char *ptr1 = ptr - 1;
|
||
+ char *ptr2 = buf;
|
||
+ while (ptr1 > ptr2)
|
||
+ {
|
||
+ int tmp = *ptr1;
|
||
+ *ptr1 = *ptr2;
|
||
+ *ptr2 = tmp;
|
||
+ ptr1--;
|
||
+ ptr2++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return ptr;
|
||
+}
|
||
+
|
||
+void
|
||
+grub_putstr (const char *str)
|
||
+{
|
||
+ while (*str)
|
||
+ grub_putchar (*str++);
|
||
+}
|
||
+
|
||
+void
|
||
+grub_printf (const char *format,...)
|
||
+{
|
||
+ int *dataptr = (int *) &format;
|
||
+ char c, str[16];
|
||
+
|
||
+ dataptr++;
|
||
+
|
||
+ while ((c = *(format++)) != 0)
|
||
+ {
|
||
+ if (c != '%')
|
||
+ grub_putchar (c);
|
||
+ else
|
||
+ switch (c = *(format++))
|
||
+ {
|
||
+#ifndef STAGE1_5
|
||
+ case 'd':
|
||
+ case 'x':
|
||
+ case 'X':
|
||
+#endif
|
||
+ case 'u':
|
||
+ *convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0;
|
||
+ grub_putstr (str);
|
||
+ break;
|
||
+
|
||
+#ifndef STAGE1_5
|
||
+ case 'c':
|
||
+ grub_putchar ((*(dataptr++)) & 0xff);
|
||
+ break;
|
||
+
|
||
+ case 's':
|
||
+ grub_putstr ((char *) *(dataptr++));
|
||
+ break;
|
||
+#endif
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+#ifndef STAGE1_5
|
||
+int
|
||
+grub_sprintf (char *buffer, const char *format, ...)
|
||
+{
|
||
+ /* XXX hohmuth
|
||
+ ugly hack -- should unify with printf() */
|
||
+ int *dataptr = (int *) &format;
|
||
+ char c, *ptr, str[16];
|
||
+ char *bp = buffer;
|
||
+
|
||
+ dataptr++;
|
||
+
|
||
+ while ((c = *format++) != 0)
|
||
+ {
|
||
+ if (c != '%')
|
||
+ *bp++ = c; /* putchar(c); */
|
||
+ else
|
||
+ switch (c = *(format++))
|
||
+ {
|
||
+ case 'd': case 'u': case 'x':
|
||
+ *convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0;
|
||
+
|
||
+ ptr = str;
|
||
+
|
||
+ while (*ptr)
|
||
+ *bp++ = *(ptr++); /* putchar(*(ptr++)); */
|
||
+ break;
|
||
+
|
||
+ case 'c': *bp++ = (*(dataptr++))&0xff;
|
||
+ /* putchar((*(dataptr++))&0xff); */
|
||
+ break;
|
||
+
|
||
+ case 's':
|
||
+ ptr = (char *) (*(dataptr++));
|
||
+
|
||
+ while ((c = *ptr++) != 0)
|
||
+ *bp++ = c; /* putchar(c); */
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ *bp = 0;
|
||
+ return bp - buffer;
|
||
+}
|
||
+
|
||
+
|
||
+void
|
||
+init_page (void)
|
||
+{
|
||
+ cls ();
|
||
+
|
||
+ grub_printf ("\n GNU GRUB version %s (%dK lower / %dK upper memory)\n\n",
|
||
+ version_string, mbi.mem_lower, mbi.mem_upper);
|
||
+}
|
||
+
|
||
+/* The number of the history entries. */
|
||
+static int num_history = 0;
|
||
+
|
||
+/* Get the NOth history. If NO is less than zero or greater than or
|
||
+ equal to NUM_HISTORY, return NULL. Otherwise return a valid string. */
|
||
+static char *
|
||
+get_history (int no)
|
||
+{
|
||
+ if (no < 0 || no >= num_history)
|
||
+ return 0;
|
||
+
|
||
+ return (char *) HISTORY_BUF + MAX_CMDLINE * no;
|
||
+}
|
||
+
|
||
+/* Add CMDLINE to the history buffer. */
|
||
+static void
|
||
+add_history (const char *cmdline, int no)
|
||
+{
|
||
+ grub_memmove ((char *) HISTORY_BUF + MAX_CMDLINE * (no + 1),
|
||
+ (char *) HISTORY_BUF + MAX_CMDLINE * no,
|
||
+ MAX_CMDLINE * (num_history - no));
|
||
+ grub_strcpy ((char *) HISTORY_BUF + MAX_CMDLINE * no, cmdline);
|
||
+ if (num_history < HISTORY_SIZE)
|
||
+ num_history++;
|
||
+}
|
||
+
|
||
+static int
|
||
+real_get_cmdline (char *prompt, char *cmdline, int maxlen,
|
||
+ int echo_char, int readline)
|
||
+{
|
||
+ /* This is a rather complicated function. So explain the concept.
|
||
+
|
||
+ A command-line consists of ``section''s. A section is a part of the
|
||
+ line which may be displayed on the screen, but a section is never
|
||
+ displayed with another section simultaneously.
|
||
+
|
||
+ Each section is basically 77 or less characters, but the exception
|
||
+ is the first section, which is 78 or less characters, because the
|
||
+ starting point is special. See below.
|
||
+
|
||
+ The first section contains a prompt and a command-line (or the
|
||
+ first part of a command-line when it is too long to be fit in the
|
||
+ screen). So, in the first section, the number of command-line
|
||
+ characters displayed is 78 minus the length of the prompt (or
|
||
+ less). If the command-line has more characters, `>' is put at the
|
||
+ position 78 (zero-origin), to inform the user of the hidden
|
||
+ characters.
|
||
+
|
||
+ Other sections always have `<' at the first position, since there
|
||
+ is absolutely a section before each section. If there is a section
|
||
+ after another section, this section consists of 77 characters and
|
||
+ `>' at the last position. The last section has 77 or less
|
||
+ characters and doesn't have `>'.
|
||
+
|
||
+ Each section other than the last shares some characters with the
|
||
+ previous section. This region is called ``margin''. If the cursor
|
||
+ is put at the magin which is shared by the first section and the
|
||
+ second, the first section is displayed. Otherwise, a displayed
|
||
+ section is switched to another section, only if the cursor is put
|
||
+ outside that section. */
|
||
+
|
||
+ /* XXX: These should be defined in shared.h, but I leave these here,
|
||
+ until this code is freezed. */
|
||
+#define CMDLINE_WIDTH 78
|
||
+#define CMDLINE_MARGIN 10
|
||
+
|
||
+ int xpos, lpos, c, section;
|
||
+ /* The length of PROMPT. */
|
||
+ int plen;
|
||
+ /* The length of the command-line. */
|
||
+ int llen;
|
||
+ /* The index for the history. */
|
||
+ int history = -1;
|
||
+ /* The working buffer for the command-line. */
|
||
+ char *buf = (char *) CMDLINE_BUF;
|
||
+ /* The kill buffer. */
|
||
+ char *kill_buf = (char *) KILL_BUF;
|
||
+
|
||
+ /* Nested function definitions for code simplicity. */
|
||
+
|
||
+ /* The forward declarations of nested functions are prefixed
|
||
+ with `auto'. */
|
||
+ auto void cl_refresh (int full, int len);
|
||
+ auto void cl_backward (int count);
|
||
+ auto void cl_forward (int count);
|
||
+ auto void cl_insert (const char *str);
|
||
+ auto void cl_delete (int count);
|
||
+ auto void cl_init (void);
|
||
+
|
||
+ /* Move the cursor backward. */
|
||
+ void cl_backward (int count)
|
||
+ {
|
||
+ lpos -= count;
|
||
+
|
||
+ /* If the cursor is in the first section, display the first section
|
||
+ instead of the second. */
|
||
+ if (section == 1 && plen + lpos < CMDLINE_WIDTH)
|
||
+ cl_refresh (1, 0);
|
||
+ else if (xpos - count < 1)
|
||
+ cl_refresh (1, 0);
|
||
+ else
|
||
+ {
|
||
+ xpos -= count;
|
||
+
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < count; i++)
|
||
+ grub_putchar ('\b');
|
||
+ }
|
||
+ else
|
||
+ gotoxy (xpos, getxy () & 0xFF);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Move the cursor forward. */
|
||
+ void cl_forward (int count)
|
||
+ {
|
||
+ lpos += count;
|
||
+
|
||
+ /* If the cursor goes outside, scroll the screen to the right. */
|
||
+ if (xpos + count >= CMDLINE_WIDTH)
|
||
+ cl_refresh (1, 0);
|
||
+ else
|
||
+ {
|
||
+ xpos += count;
|
||
+
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ {
|
||
+ int i;
|
||
+
|
||
+ for (i = lpos - count; i < lpos; i++)
|
||
+ {
|
||
+ if (! echo_char)
|
||
+ grub_putchar (buf[i]);
|
||
+ else
|
||
+ grub_putchar (echo_char);
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ gotoxy (xpos, getxy () & 0xFF);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Refresh the screen. If FULL is true, redraw the full line, otherwise,
|
||
+ only LEN characters from LPOS. */
|
||
+ void cl_refresh (int full, int len)
|
||
+ {
|
||
+ int i;
|
||
+ int start;
|
||
+ int pos = xpos;
|
||
+
|
||
+ if (full)
|
||
+ {
|
||
+ /* Recompute the section number. */
|
||
+ if (lpos + plen < CMDLINE_WIDTH)
|
||
+ section = 0;
|
||
+ else
|
||
+ section = ((lpos + plen - CMDLINE_WIDTH)
|
||
+ / (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN) + 1);
|
||
+
|
||
+ /* From the start to the end. */
|
||
+ len = CMDLINE_WIDTH;
|
||
+ pos = 0;
|
||
+ grub_putchar ('\r');
|
||
+
|
||
+ /* If SECTION is the first section, print the prompt, otherwise,
|
||
+ print `<'. */
|
||
+ if (section == 0)
|
||
+ {
|
||
+ grub_printf ("%s", prompt);
|
||
+ len -= plen;
|
||
+ pos += plen;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ grub_putchar ('<');
|
||
+ len--;
|
||
+ pos++;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Compute the index to start writing BUF and the resulting position
|
||
+ on the screen. */
|
||
+ if (section == 0)
|
||
+ {
|
||
+ int offset = 0;
|
||
+
|
||
+ if (! full)
|
||
+ offset = xpos - plen;
|
||
+
|
||
+ start = 0;
|
||
+ xpos = lpos + plen;
|
||
+ start += offset;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ int offset = 0;
|
||
+
|
||
+ if (! full)
|
||
+ offset = xpos - 1;
|
||
+
|
||
+ start = ((section - 1) * (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN)
|
||
+ + CMDLINE_WIDTH - plen - CMDLINE_MARGIN);
|
||
+ xpos = lpos + 1 - start;
|
||
+ start += offset;
|
||
+ }
|
||
+
|
||
+ /* Print BUF. If ECHO_CHAR is not zero, put it instead. */
|
||
+ for (i = start; i < start + len && i < llen; i++)
|
||
+ {
|
||
+ if (! echo_char)
|
||
+ grub_putchar (buf[i]);
|
||
+ else
|
||
+ grub_putchar (echo_char);
|
||
+
|
||
+ pos++;
|
||
+ }
|
||
+
|
||
+ /* Fill up the rest of the line with spaces. */
|
||
+ for (; i < start + len; i++)
|
||
+ {
|
||
+ grub_putchar (' ');
|
||
+ pos++;
|
||
+ }
|
||
+
|
||
+ /* If the cursor is at the last position, put `>' or a space,
|
||
+ depending on if there are more characters in BUF. */
|
||
+ if (pos == CMDLINE_WIDTH)
|
||
+ {
|
||
+ if (start + len < llen)
|
||
+ grub_putchar ('>');
|
||
+ else
|
||
+ grub_putchar (' ');
|
||
+
|
||
+ pos++;
|
||
+ }
|
||
+
|
||
+ /* Back to XPOS. */
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ {
|
||
+ for (i = 0; i < pos - xpos; i++)
|
||
+ grub_putchar ('\b');
|
||
+ }
|
||
+ else
|
||
+ gotoxy (xpos, getxy () & 0xFF);
|
||
+ }
|
||
+
|
||
+ /* Initialize the command-line. */
|
||
+ void cl_init (void)
|
||
+ {
|
||
+ /* Distinguish us from other lines and error messages! */
|
||
+ grub_putchar ('\n');
|
||
+
|
||
+ /* Print full line and set position here. */
|
||
+ cl_refresh (1, 0);
|
||
+ }
|
||
+
|
||
+ /* Insert STR to BUF. */
|
||
+ void cl_insert (const char *str)
|
||
+ {
|
||
+ int l = grub_strlen (str);
|
||
+
|
||
+ if (llen + l < maxlen)
|
||
+ {
|
||
+ if (lpos == llen)
|
||
+ grub_memmove (buf + lpos, str, l + 1);
|
||
+ else
|
||
+ {
|
||
+ grub_memmove (buf + lpos + l, buf + lpos, llen - lpos + 1);
|
||
+ grub_memmove (buf + lpos, str, l);
|
||
+ }
|
||
+
|
||
+ llen += l;
|
||
+ lpos += l;
|
||
+ if (xpos + l >= CMDLINE_WIDTH)
|
||
+ cl_refresh (1, 0);
|
||
+ else if (xpos + l + llen - lpos > CMDLINE_WIDTH)
|
||
+ cl_refresh (0, CMDLINE_WIDTH - xpos);
|
||
+ else
|
||
+ cl_refresh (0, l + llen - lpos);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Delete COUNT characters in BUF. */
|
||
+ void cl_delete (int count)
|
||
+ {
|
||
+ grub_memmove (buf + lpos, buf + lpos + count, llen - count + 1);
|
||
+ llen -= count;
|
||
+
|
||
+ if (xpos + llen + count - lpos > CMDLINE_WIDTH)
|
||
+ cl_refresh (0, CMDLINE_WIDTH - xpos);
|
||
+ else
|
||
+ cl_refresh (0, llen + count - lpos);
|
||
+ }
|
||
+
|
||
+ plen = grub_strlen (prompt);
|
||
+ llen = grub_strlen (cmdline);
|
||
+
|
||
+ if (maxlen > MAX_CMDLINE)
|
||
+ {
|
||
+ maxlen = MAX_CMDLINE;
|
||
+ if (llen >= MAX_CMDLINE)
|
||
+ {
|
||
+ llen = MAX_CMDLINE - 1;
|
||
+ cmdline[MAX_CMDLINE] = 0;
|
||
+ }
|
||
+ }
|
||
+ lpos = llen;
|
||
+ grub_strcpy (buf, cmdline);
|
||
+
|
||
+ cl_init ();
|
||
+
|
||
+ while ((c = ASCII_CHAR (getkey ())) != '\n' && c != '\r')
|
||
+ {
|
||
+ /* If READLINE is non-zero, handle readline-like key bindings. */
|
||
+ if (readline)
|
||
+ {
|
||
+ switch (c)
|
||
+ {
|
||
+ case 9: /* TAB lists completions */
|
||
+ {
|
||
+ int i;
|
||
+ /* POS points to the first space after a command. */
|
||
+ int pos = 0;
|
||
+ int ret;
|
||
+ char *completion_buffer = (char *) COMPLETION_BUF;
|
||
+ int equal_pos = -1;
|
||
+ int is_filename;
|
||
+
|
||
+ /* Find the first word. */
|
||
+ while (buf[pos] == ' ')
|
||
+ pos++;
|
||
+ while (buf[pos] && buf[pos] != '=' && buf[pos] != ' ')
|
||
+ pos++;
|
||
+
|
||
+ is_filename = (lpos > pos);
|
||
+
|
||
+ /* Find the position of the equal character after a
|
||
+ command, and replace it with a space. */
|
||
+ for (i = pos; buf[i] && buf[i] != ' '; i++)
|
||
+ if (buf[i] == '=')
|
||
+ {
|
||
+ equal_pos = i;
|
||
+ buf[i] = ' ';
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* Find the position of the first character in this
|
||
+ word. */
|
||
+ for (i = lpos; i > 0 && buf[i - 1] != ' '; i--)
|
||
+ ;
|
||
+
|
||
+ /* Invalidate the cache, because the user may exchange
|
||
+ removable disks. */
|
||
+ buf_drive = -1;
|
||
+
|
||
+ /* Copy this word to COMPLETION_BUFFER and do the
|
||
+ completion. */
|
||
+ grub_memmove (completion_buffer, buf + i, lpos - i);
|
||
+ completion_buffer[lpos - i] = 0;
|
||
+ ret = print_completions (is_filename, 1);
|
||
+ errnum = ERR_NONE;
|
||
+
|
||
+ if (ret >= 0)
|
||
+ {
|
||
+ /* Found, so insert COMPLETION_BUFFER. */
|
||
+ cl_insert (completion_buffer + lpos - i);
|
||
+
|
||
+ if (ret > 0)
|
||
+ {
|
||
+ /* There are more than one candidates, so print
|
||
+ the list. */
|
||
+ grub_putchar ('\n');
|
||
+ print_completions (is_filename, 0);
|
||
+ errnum = ERR_NONE;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Restore the command-line. */
|
||
+ if (equal_pos >= 0)
|
||
+ buf[equal_pos] = '=';
|
||
+
|
||
+ if (ret)
|
||
+ cl_init ();
|
||
+ }
|
||
+ break;
|
||
+ case 1: /* C-a go to beginning of line */
|
||
+ cl_backward (lpos);
|
||
+ break;
|
||
+ case 5: /* C-e go to end of line */
|
||
+ cl_forward (llen - lpos);
|
||
+ break;
|
||
+ case 6: /* C-f forward one character */
|
||
+ if (lpos < llen)
|
||
+ cl_forward (1);
|
||
+ break;
|
||
+ case 2: /* C-b backward one character */
|
||
+ if (lpos > 0)
|
||
+ cl_backward (1);
|
||
+ break;
|
||
+ case 21: /* C-u kill to beginning of line */
|
||
+ if (lpos == 0)
|
||
+ break;
|
||
+ /* Copy the string being deleted to KILL_BUF. */
|
||
+ grub_memmove (kill_buf, buf, lpos);
|
||
+ kill_buf[lpos] = 0;
|
||
+ {
|
||
+ /* XXX: Not very clever. */
|
||
+
|
||
+ int count = lpos;
|
||
+
|
||
+ cl_backward (lpos);
|
||
+ cl_delete (count);
|
||
+ }
|
||
+ break;
|
||
+ case 11: /* C-k kill to end of line */
|
||
+ if (lpos == llen)
|
||
+ break;
|
||
+ /* Copy the string being deleted to KILL_BUF. */
|
||
+ grub_memmove (kill_buf, buf + lpos, llen - lpos + 1);
|
||
+ cl_delete (llen - lpos);
|
||
+ break;
|
||
+ case 25: /* C-y yank the kill buffer */
|
||
+ cl_insert (kill_buf);
|
||
+ break;
|
||
+ case 16: /* C-p fetch the previous command */
|
||
+ {
|
||
+ char *p;
|
||
+
|
||
+ if (history < 0)
|
||
+ /* Save the working buffer. */
|
||
+ grub_strcpy (cmdline, buf);
|
||
+ else if (grub_strcmp (get_history (history), buf) != 0)
|
||
+ /* If BUF is modified, add it into the history list. */
|
||
+ add_history (buf, history);
|
||
+
|
||
+ history++;
|
||
+ p = get_history (history);
|
||
+ if (! p)
|
||
+ {
|
||
+ history--;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ grub_strcpy (buf, p);
|
||
+ llen = grub_strlen (buf);
|
||
+ lpos = llen;
|
||
+ cl_refresh (1, 0);
|
||
+ }
|
||
+ break;
|
||
+ case 14: /* C-n fetch the next command */
|
||
+ {
|
||
+ char *p;
|
||
+
|
||
+ if (history < 0)
|
||
+ {
|
||
+ break;
|
||
+ }
|
||
+ else if (grub_strcmp (get_history (history), buf) != 0)
|
||
+ /* If BUF is modified, add it into the history list. */
|
||
+ add_history (buf, history);
|
||
+
|
||
+ history--;
|
||
+ p = get_history (history);
|
||
+ if (! p)
|
||
+ p = cmdline;
|
||
+
|
||
+ grub_strcpy (buf, p);
|
||
+ llen = grub_strlen (buf);
|
||
+ lpos = llen;
|
||
+ cl_refresh (1, 0);
|
||
+ }
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* ESC, C-d and C-h are always handled. Actually C-d is not
|
||
+ functional if READLINE is zero, as the cursor cannot go
|
||
+ backward, but that's ok. */
|
||
+ switch (c)
|
||
+ {
|
||
+ case 27: /* ESC immediately return 1 */
|
||
+ return 1;
|
||
+ case 4: /* C-d delete character under cursor */
|
||
+ if (lpos == llen)
|
||
+ break;
|
||
+ cl_delete (1);
|
||
+ break;
|
||
+ case 8: /* C-h backspace */
|
||
+# ifdef GRUB_UTIL
|
||
+ case 127: /* also backspace */
|
||
+# endif
|
||
+ if (lpos > 0)
|
||
+ {
|
||
+ cl_backward (1);
|
||
+ cl_delete (1);
|
||
+ }
|
||
+ break;
|
||
+ default: /* insert printable character into line */
|
||
+ if (c >= ' ' && c <= '~')
|
||
+ {
|
||
+ char str[2];
|
||
+
|
||
+ str[0] = c;
|
||
+ str[1] = 0;
|
||
+ cl_insert (str);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ grub_putchar ('\n');
|
||
+
|
||
+ /* If ECHO_CHAR is NUL, remove the leading spaces. */
|
||
+ lpos = 0;
|
||
+ if (! echo_char)
|
||
+ while (buf[lpos] == ' ')
|
||
+ lpos++;
|
||
+
|
||
+ /* Copy the working buffer to CMDLINE. */
|
||
+ grub_memmove (cmdline, buf + lpos, llen - lpos + 1);
|
||
+
|
||
+ /* If the readline-like feature is turned on and CMDLINE is not
|
||
+ empty, add it into the history list. */
|
||
+ if (readline && lpos < llen)
|
||
+ add_history (cmdline, 0);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* Don't use this with a MAXLEN greater than 1600 or so! The problem
|
||
+ is that GET_CMDLINE depends on the everything fitting on the screen
|
||
+ at once. So, the whole screen is about 2000 characters, minus the
|
||
+ PROMPT, and space for error and status lines, etc. MAXLEN must be
|
||
+ at least 1, and PROMPT and CMDLINE must be valid strings (not NULL
|
||
+ or zero-length).
|
||
+
|
||
+ If ECHO_CHAR is nonzero, echo it instead of the typed character. */
|
||
+int
|
||
+get_cmdline (char *prompt, char *cmdline, int maxlen,
|
||
+ int echo_char, int readline)
|
||
+{
|
||
+ int old_cursor;
|
||
+ int ret;
|
||
+
|
||
+ old_cursor = setcursor (1);
|
||
+
|
||
+ /* Because it is hard to deal with different conditions simultaneously,
|
||
+ less functional cases are handled here. Assume that TERM_NO_ECHO
|
||
+ implies TERM_NO_EDIT. */
|
||
+ if (current_term->flags & (TERM_NO_ECHO | TERM_NO_EDIT))
|
||
+ {
|
||
+ char *p = cmdline;
|
||
+ int c;
|
||
+
|
||
+ /* Make sure that MAXLEN is not too large. */
|
||
+ if (maxlen > MAX_CMDLINE)
|
||
+ maxlen = MAX_CMDLINE;
|
||
+
|
||
+ /* Print only the prompt. The contents of CMDLINE is simply discarded,
|
||
+ even if it is not empty. */
|
||
+ grub_printf ("%s", prompt);
|
||
+
|
||
+ /* Gather characters until a newline is gotten. */
|
||
+ while ((c = ASCII_CHAR (getkey ())) != '\n' && c != '\r')
|
||
+ {
|
||
+ /* Return immediately if ESC is pressed. */
|
||
+ if (c == 27)
|
||
+ {
|
||
+ setcursor (old_cursor);
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
+ /* Printable characters are added into CMDLINE. */
|
||
+ if (c >= ' ' && c <= '~')
|
||
+ {
|
||
+ if (! (current_term->flags & TERM_NO_ECHO))
|
||
+ grub_putchar (c);
|
||
+
|
||
+ /* Preceding space characters must be ignored. */
|
||
+ if (c != ' ' || p != cmdline)
|
||
+ *p++ = c;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ *p = 0;
|
||
+
|
||
+ if (! (current_term->flags & TERM_NO_ECHO))
|
||
+ grub_putchar ('\n');
|
||
+
|
||
+ setcursor (old_cursor);
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* Complicated features are left to real_get_cmdline. */
|
||
+ ret = real_get_cmdline (prompt, cmdline, maxlen, echo_char, readline);
|
||
+ setcursor (old_cursor);
|
||
+ return ret;
|
||
+}
|
||
+
|
||
+int
|
||
+safe_parse_maxint (char **str_ptr, int *myint_ptr)
|
||
+{
|
||
+ char *ptr = *str_ptr;
|
||
+ int myint = 0;
|
||
+ int mult = 10, found = 0;
|
||
+
|
||
+ /*
|
||
+ * Is this a hex number?
|
||
+ */
|
||
+ if (*ptr == '0' && tolower (*(ptr + 1)) == 'x')
|
||
+ {
|
||
+ ptr += 2;
|
||
+ mult = 16;
|
||
+ }
|
||
+
|
||
+ while (1)
|
||
+ {
|
||
+ /* A bit tricky. This below makes use of the equivalence:
|
||
+ (A >= B && A <= C) <=> ((A - B) <= (C - B))
|
||
+ when C > B and A is unsigned. */
|
||
+ unsigned int digit;
|
||
+
|
||
+ digit = tolower (*ptr) - '0';
|
||
+ if (digit > 9)
|
||
+ {
|
||
+ digit -= 'a' - '0';
|
||
+ if (mult == 10 || digit > 5)
|
||
+ break;
|
||
+ digit += 10;
|
||
+ }
|
||
+
|
||
+ found = 1;
|
||
+ if (myint > ((MAXINT - digit) / mult))
|
||
+ {
|
||
+ errnum = ERR_NUMBER_OVERFLOW;
|
||
+ return 0;
|
||
+ }
|
||
+ myint = (myint * mult) + digit;
|
||
+ ptr++;
|
||
+ }
|
||
+
|
||
+ if (!found)
|
||
+ {
|
||
+ errnum = ERR_NUMBER_PARSING;
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ *str_ptr = ptr;
|
||
+ *myint_ptr = myint;
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+#endif /* STAGE1_5 */
|
||
+
|
||
+#if !defined(STAGE1_5) || defined(FSYS_FAT)
|
||
+int
|
||
+grub_tolower (int c)
|
||
+{
|
||
+ if (c >= 'A' && c <= 'Z')
|
||
+ return (c + ('a' - 'A'));
|
||
+
|
||
+ return c;
|
||
+}
|
||
+#endif /* ! STAGE1_5 || FSYS_FAT */
|
||
+
|
||
+int
|
||
+grub_isspace (int c)
|
||
+{
|
||
+ switch (c)
|
||
+ {
|
||
+ case ' ':
|
||
+ case '\t':
|
||
+ case '\r':
|
||
+ case '\n':
|
||
+ return 1;
|
||
+ default:
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#if !defined(STAGE1_5) || defined(FSYS_ISO9660)
|
||
+int
|
||
+grub_memcmp (const char *s1, const char *s2, int n)
|
||
+{
|
||
+ while (n)
|
||
+ {
|
||
+ if (*s1 < *s2)
|
||
+ return -1;
|
||
+ else if (*s1 > *s2)
|
||
+ return 1;
|
||
+ s1++;
|
||
+ s2++;
|
||
+ n--;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+#endif /* ! STAGE1_5 || FSYS_ISO9660 */
|
||
+
|
||
+#ifndef STAGE1_5
|
||
+int
|
||
+grub_strncat (char *s1, const char *s2, int n)
|
||
+{
|
||
+ int i = -1;
|
||
+
|
||
+ while (++i < n && s1[i] != 0);
|
||
+
|
||
+ while (i < n && (s1[i++] = *(s2++)) != 0);
|
||
+
|
||
+ s1[n - 1] = 0;
|
||
+
|
||
+ if (i >= n)
|
||
+ return 0;
|
||
+
|
||
+ s1[i] = 0;
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+#endif /* ! STAGE1_5 */
|
||
+
|
||
+/* XXX: This below is an evil hack. Certainly, we should change the
|
||
+ strategy to determine what should be defined and what shouldn't be
|
||
+ defined for each image. For example, it would be better to create
|
||
+ a static library supporting minimal standard C functions and link
|
||
+ each image with the library. Complicated things should be left to
|
||
+ computer, definitely. -okuji */
|
||
+#if !defined(STAGE1_5) || defined(FSYS_VSTAFS)
|
||
+int
|
||
+grub_strcmp (const char *s1, const char *s2)
|
||
+{
|
||
+ while (*s1 || *s2)
|
||
+ {
|
||
+ if (*s1 < *s2)
|
||
+ return -1;
|
||
+ else if (*s1 > *s2)
|
||
+ return 1;
|
||
+ s1 ++;
|
||
+ s2 ++;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+#endif /* ! STAGE1_5 || FSYS_VSTAFS */
|
||
+
|
||
+#ifndef STAGE1_5
|
||
+/* Wait for a keypress and return its code. */
|
||
+int
|
||
+getkey (void)
|
||
+{
|
||
+ return current_term->getkey ();
|
||
+}
|
||
+
|
||
+/* Check if a key code is available. */
|
||
+int
|
||
+checkkey (void)
|
||
+{
|
||
+ return current_term->checkkey ();
|
||
+}
|
||
+#endif /* ! STAGE1_5 */
|
||
+
|
||
+/* Display an ASCII character. */
|
||
+void
|
||
+grub_putchar (int c)
|
||
+{
|
||
+ if (c == '\n')
|
||
+ grub_putchar ('\r');
|
||
+#ifndef STAGE1_5
|
||
+ else if (c == '\t' && current_term->getxy)
|
||
+ {
|
||
+ int n;
|
||
+
|
||
+ n = 8 - ((current_term->getxy () >> 8) & 3);
|
||
+ while (n--)
|
||
+ grub_putchar (' ');
|
||
+
|
||
+ return;
|
||
+ }
|
||
+#endif /* ! STAGE1_5 */
|
||
+
|
||
+#ifdef STAGE1_5
|
||
+
|
||
+ /* In Stage 1.5, only the normal console is supported. */
|
||
+ console_putchar (c);
|
||
+
|
||
+#else /* ! STAGE1_5 */
|
||
+
|
||
+ if (c == '\n')
|
||
+ {
|
||
+ /* Internal `more'-like feature. */
|
||
+ if (count_lines >= 0)
|
||
+ {
|
||
+ count_lines++;
|
||
+ if (count_lines >= max_lines - 2)
|
||
+ {
|
||
+ int tmp;
|
||
+
|
||
+ /* It's important to disable the feature temporarily, because
|
||
+ the following grub_printf call will print newlines. */
|
||
+ count_lines = -1;
|
||
+
|
||
+ if (current_term->setcolorstate)
|
||
+ current_term->setcolorstate (COLOR_STATE_HIGHLIGHT);
|
||
+
|
||
+ grub_printf ("\n[Hit return to continue]");
|
||
+
|
||
+ if (current_term->setcolorstate)
|
||
+ current_term->setcolorstate (COLOR_STATE_NORMAL);
|
||
+
|
||
+ do
|
||
+ {
|
||
+ tmp = ASCII_CHAR (getkey ());
|
||
+ }
|
||
+ while (tmp != '\n' && tmp != '\r');
|
||
+ grub_printf ("\r \r");
|
||
+
|
||
+ /* Restart to count lines. */
|
||
+ count_lines = 0;
|
||
+ return;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ current_term->putchar (c);
|
||
+
|
||
+#endif /* ! STAGE1_5 */
|
||
+}
|
||
+
|
||
+#ifndef STAGE1_5
|
||
+void
|
||
+gotoxy (int x, int y)
|
||
+{
|
||
+ current_term->gotoxy (x, y);
|
||
+}
|
||
+
|
||
+int
|
||
+getxy (void)
|
||
+{
|
||
+ return current_term->getxy ();
|
||
+}
|
||
+
|
||
+void
|
||
+cls (void)
|
||
+{
|
||
+ /* If the terminal is dumb, there is no way to clean the terminal. */
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ grub_putchar ('\n');
|
||
+ else
|
||
+ current_term->cls ();
|
||
+}
|
||
+
|
||
+int
|
||
+setcursor (int on)
|
||
+{
|
||
+ if (current_term->setcursor)
|
||
+ return current_term->setcursor (on);
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+#endif /* ! STAGE1_5 */
|
||
+
|
||
+int
|
||
+substring (const char *s1, const char *s2)
|
||
+{
|
||
+ while (*s1 == *s2)
|
||
+ {
|
||
+ /* The strings match exactly. */
|
||
+ if (! *(s1++))
|
||
+ return 0;
|
||
+ s2 ++;
|
||
+ }
|
||
+
|
||
+ /* S1 is a substring of S2. */
|
||
+ if (*s1 == 0)
|
||
+ return -1;
|
||
+
|
||
+ /* S1 isn't a substring. */
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+#ifndef STAGE1_5
|
||
+/* Terminate the string STR with NUL. */
|
||
+int
|
||
+nul_terminate (char *str)
|
||
+{
|
||
+ int ch;
|
||
+
|
||
+ while (*str && ! grub_isspace (*str))
|
||
+ str++;
|
||
+
|
||
+ ch = *str;
|
||
+ *str = 0;
|
||
+ return ch;
|
||
+}
|
||
+
|
||
+char *
|
||
+grub_strstr (const char *s1, const char *s2)
|
||
+{
|
||
+ while (*s1)
|
||
+ {
|
||
+ const char *ptr, *tmp;
|
||
+
|
||
+ ptr = s1;
|
||
+ tmp = s2;
|
||
+
|
||
+ while (*tmp && *ptr == *tmp)
|
||
+ ptr++, tmp++;
|
||
+
|
||
+ if (tmp > s2 && ! *tmp)
|
||
+ return (char *) s1;
|
||
+
|
||
+ s1++;
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+int
|
||
+grub_strlen (const char *str)
|
||
+{
|
||
+ int len = 0;
|
||
+
|
||
+ while (*str++)
|
||
+ len++;
|
||
+
|
||
+ return len;
|
||
+}
|
||
+#endif /* ! STAGE1_5 */
|
||
+
|
||
+int
|
||
+memcheck (int addr, int len)
|
||
+{
|
||
+#ifdef GRUB_UTIL
|
||
+ auto int start_addr (void);
|
||
+ auto int end_addr (void);
|
||
+
|
||
+ auto int start_addr (void)
|
||
+ {
|
||
+ int ret;
|
||
+# if defined(HAVE_START_SYMBOL)
|
||
+ asm volatile ("movl $start, %0" : "=a" (ret));
|
||
+# elif defined(HAVE_USCORE_START_SYMBOL)
|
||
+ asm volatile ("movl $_start, %0" : "=a" (ret));
|
||
+# endif
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ auto int end_addr (void)
|
||
+ {
|
||
+ int ret;
|
||
+# if defined(HAVE_END_SYMBOL)
|
||
+ asm volatile ("movl $end, %0" : "=a" (ret));
|
||
+# elif defined(HAVE_USCORE_END_SYMBOL)
|
||
+ asm volatile ("movl $_end, %0" : "=a" (ret));
|
||
+# endif
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ if (start_addr () <= addr && end_addr () > addr + len)
|
||
+ return ! errnum;
|
||
+#endif /* GRUB_UTIL */
|
||
+
|
||
+ if ((addr < RAW_ADDR (0x1000))
|
||
+ || (addr < RAW_ADDR (0x100000)
|
||
+ && RAW_ADDR (mbi.mem_lower * 1024) < (addr + len))
|
||
+ || (addr >= RAW_ADDR (0x100000)
|
||
+ && RAW_ADDR (mbi.mem_upper * 1024) < ((addr - 0x100000) + len)))
|
||
+ errnum = ERR_WONT_FIT;
|
||
+
|
||
+ return ! errnum;
|
||
+}
|
||
+
|
||
+void *
|
||
+grub_memmove (void *to, const void *from, int len)
|
||
+{
|
||
+ if (memcheck ((int) to, len))
|
||
+ {
|
||
+ /* This assembly code is stolen from
|
||
+ linux-2.2.2/include/asm-i386/string.h. This is not very fast
|
||
+ but compact. */
|
||
+ int d0, d1, d2;
|
||
+
|
||
+ if (to < from)
|
||
+ {
|
||
+ asm volatile ("cld\n\t"
|
||
+ "rep\n\t"
|
||
+ "movsb"
|
||
+ : "=&c" (d0), "=&S" (d1), "=&D" (d2)
|
||
+ : "0" (len),"1" (from),"2" (to)
|
||
+ : "memory");
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ asm volatile ("std\n\t"
|
||
+ "rep\n\t"
|
||
+ "movsb\n\t"
|
||
+ "cld"
|
||
+ : "=&c" (d0), "=&S" (d1), "=&D" (d2)
|
||
+ : "0" (len),
|
||
+ "1" (len - 1 + (const char *) from),
|
||
+ "2" (len - 1 + (char *) to)
|
||
+ : "memory");
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return errnum ? NULL : to;
|
||
+}
|
||
+
|
||
+void *
|
||
+grub_memset (void *start, int c, int len)
|
||
+{
|
||
+ char *p = start;
|
||
+
|
||
+ if (memcheck ((int) start, len))
|
||
+ {
|
||
+ while (len -- > 0)
|
||
+ *p ++ = c;
|
||
+ }
|
||
+
|
||
+ return errnum ? NULL : start;
|
||
+}
|
||
+
|
||
+#ifndef STAGE1_5
|
||
+char *
|
||
+grub_strcpy (char *dest, const char *src)
|
||
+{
|
||
+ grub_memmove (dest, src, grub_strlen (src) + 1);
|
||
+ return dest;
|
||
+}
|
||
+#endif /* ! STAGE1_5 */
|
||
+
|
||
+#ifndef GRUB_UTIL
|
||
+# undef memcpy
|
||
+/* GCC emits references to memcpy() for struct copies etc. */
|
||
+void *memcpy (void *dest, const void *src, int n) __attribute__ ((alias ("grub_memmove")));
|
||
+#endif
|
||
diff -Nur grub-0.97/stage2/common.c grub-0.97-patched/stage2/common.c
|
||
--- grub-0.97/stage2/common.c 2004-03-27 17:25:44.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/common.c 2012-11-11 17:06:52.558085305 +0100
|
||
@@ -142,7 +142,8 @@
|
||
init_bios_info (void)
|
||
{
|
||
#ifndef STAGE1_5
|
||
- unsigned long cont, memtmp, addr;
|
||
+ unsigned long memtmp, addr;
|
||
+ volatile unsigned long cont;
|
||
int drive;
|
||
#endif
|
||
|
||
diff -Nur grub-0.97/stage2/disk_io.c grub-0.97-patched/stage2/disk_io.c
|
||
--- grub-0.97/stage2/disk_io.c 2004-05-23 18:35:24.000000000 +0200
|
||
+++ grub-0.97-patched/stage2/disk_io.c 2012-11-11 17:07:12.740730013 +0100
|
||
@@ -21,6 +21,7 @@
|
||
|
||
#include <shared.h>
|
||
#include <filesys.h>
|
||
+#include <gpt.h>
|
||
|
||
#ifdef SUPPORT_NETBOOT
|
||
# define GRUB 1
|
||
@@ -137,7 +138,7 @@
|
||
}
|
||
|
||
int
|
||
-rawread (int drive, int sector, int byte_offset, int byte_len, char *buf)
|
||
+rawread (int drive, unsigned int sector, int byte_offset, int byte_len, char *buf)
|
||
{
|
||
int slen, sectors_per_vtrack;
|
||
int sector_size_bits = log2 (buf_geom.sector_size);
|
||
@@ -261,7 +262,7 @@
|
||
*/
|
||
if (disk_read_func)
|
||
{
|
||
- int sector_num = sector;
|
||
+ unsigned int sector_num = sector;
|
||
int length = buf_geom.sector_size - byte_offset;
|
||
if (length > size)
|
||
length = size;
|
||
@@ -291,7 +292,7 @@
|
||
|
||
|
||
int
|
||
-devread (int sector, int byte_offset, int byte_len, char *buf)
|
||
+devread (unsigned int sector, int byte_offset, int byte_len, char *buf)
|
||
{
|
||
/*
|
||
* Check partition boundaries
|
||
@@ -330,7 +331,7 @@
|
||
|
||
#ifndef STAGE1_5
|
||
int
|
||
-rawwrite (int drive, int sector, char *buf)
|
||
+rawwrite (int drive, unsigned int sector, char *buf)
|
||
{
|
||
if (sector == 0)
|
||
{
|
||
@@ -363,7 +364,7 @@
|
||
}
|
||
|
||
int
|
||
-devwrite (int sector, int sector_count, char *buf)
|
||
+devwrite (unsigned int sector, int sector_count, char *buf)
|
||
{
|
||
#if defined(GRUB_UTIL) && defined(__linux__)
|
||
if (current_partition != 0xFFFFFF
|
||
@@ -502,8 +503,8 @@
|
||
set_partition_hidden_flag (int hidden)
|
||
{
|
||
unsigned long part = 0xFFFFFF;
|
||
- unsigned long start, len, offset, ext_offset;
|
||
- int entry, type;
|
||
+ unsigned long start, len, offset, ext_offset, gpt_offset;
|
||
+ int entry, type, gpt_count, gpt_size;
|
||
char mbr[512];
|
||
|
||
/* The drive must be a hard disk. */
|
||
@@ -524,8 +525,15 @@
|
||
/* Look for the partition. */
|
||
while (next_partition (current_drive, 0xFFFFFF, &part, &type,
|
||
&start, &len, &offset, &entry,
|
||
- &ext_offset, mbr))
|
||
+ &ext_offset, &gpt_offset, &gpt_count, &gpt_size, mbr))
|
||
{
|
||
+ /* The partition may not be a GPT partition. */
|
||
+ if (gpt_offset != 0)
|
||
+ {
|
||
+ errnum = ERR_BAD_ARGUMENT;
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
if (part == current_partition)
|
||
{
|
||
/* Found. */
|
||
@@ -577,11 +585,14 @@
|
||
unsigned long *partition, int *type,
|
||
unsigned long *start, unsigned long *len,
|
||
unsigned long *offset, int *entry,
|
||
- unsigned long *ext_offset, char *buf)
|
||
+ unsigned long *ext_offset,
|
||
+ unsigned long *gpt_offset, int *gpt_count,
|
||
+ int *gpt_size, char *buf)
|
||
{
|
||
/* Forward declarations. */
|
||
auto int next_bsd_partition (void);
|
||
auto int next_pc_slice (void);
|
||
+ auto int next_gpt_slice(void);
|
||
|
||
/* Get next BSD partition in current PC slice. */
|
||
int next_bsd_partition (void)
|
||
@@ -666,6 +677,40 @@
|
||
return 0;
|
||
}
|
||
|
||
+ /* If this is a GPT partition table, read it as such. */
|
||
+ if (*entry == -1 && *offset == 0 && PC_SLICE_TYPE (buf, 0) == PC_SLICE_TYPE_GPT)
|
||
+ {
|
||
+ struct grub_gpt_header *hdr = (struct grub_gpt_header *) buf;
|
||
+
|
||
+ /* Read in the GPT Partition table header. */
|
||
+ if (! rawread (drive, 1, 0, SECTOR_SIZE, buf))
|
||
+ return 0;
|
||
+
|
||
+ if (hdr->magic == GPT_HEADER_MAGIC && hdr->version == 0x10000)
|
||
+ {
|
||
+ /* Let gpt_offset point to the first entry in the GPT
|
||
+ partition table. This can also be used by callers of
|
||
+ next_partition to determine if a entry comes from a
|
||
+ GPT partition table or not. */
|
||
+ *gpt_offset = hdr->partitions;
|
||
+ *gpt_count = hdr->maxpart;
|
||
+ *gpt_size = hdr->partentry_size;
|
||
+
|
||
+ return next_gpt_slice();
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* This is not a valid header for a GPT partition table.
|
||
+ Re-read the MBR or the boot sector of the extended
|
||
+ partition. */
|
||
+ if (! rawread (drive, *offset, 0, SECTOR_SIZE, buf))
|
||
+ return 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Not a GPT partition. */
|
||
+ *gpt_offset = 0;
|
||
+
|
||
/* Increase the entry number. */
|
||
(*entry)++;
|
||
|
||
@@ -710,6 +755,43 @@
|
||
return 1;
|
||
}
|
||
|
||
+ /* Get the next GPT slice. */
|
||
+ int next_gpt_slice (void)
|
||
+ {
|
||
+ struct grub_gpt_partentry *gptentry = (struct grub_gpt_partentry *) buf;
|
||
+ /* Make GPT partitions show up as PC slices. */
|
||
+ int pc_slice_no = (*partition & 0xFF0000) >> 16;
|
||
+
|
||
+ /* If this is the first time... */
|
||
+ if (pc_slice_no == 0xFF)
|
||
+ {
|
||
+ pc_slice_no = -1;
|
||
+ *entry = -1;
|
||
+ }
|
||
+
|
||
+ do {
|
||
+ (*entry)++;
|
||
+
|
||
+ if (*entry >= *gpt_count)
|
||
+ {
|
||
+ errnum = ERR_NO_PART;
|
||
+ return 0;
|
||
+ }
|
||
+ /* Read in the GPT Partition table entry. */
|
||
+ if (! rawread (drive, (*gpt_offset) + GPT_ENTRY_SECTOR (*gpt_size, *entry), GPT_ENTRY_INDEX (*gpt_size, *entry), *gpt_size, buf))
|
||
+ return 0;
|
||
+ } while (! (gptentry->type1 && gptentry->type2));
|
||
+
|
||
+ pc_slice_no++;
|
||
+ *start = gptentry->start;
|
||
+ *len = gptentry->end - gptentry->start + 1;
|
||
+ *type = PC_SLICE_TYPE_EXT2FS;
|
||
+ *entry = pc_slice_no;
|
||
+ *partition = (*entry << 16) | 0xFFFF;
|
||
+
|
||
+ return 1;
|
||
+ }
|
||
+
|
||
/* Start the body of this function. */
|
||
|
||
#ifndef STAGE1_5
|
||
@@ -717,6 +799,9 @@
|
||
return 0;
|
||
#endif
|
||
|
||
+ if (*partition != 0xFFFFFF && *gpt_offset != 0)
|
||
+ return next_gpt_slice ();
|
||
+
|
||
/* If previous partition is a BSD partition or a PC slice which
|
||
contains BSD partitions... */
|
||
if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff))
|
||
@@ -746,6 +831,8 @@
|
||
#ifndef STAGE1_5
|
||
static unsigned long cur_part_offset;
|
||
static unsigned long cur_part_addr;
|
||
+static unsigned long cur_part_start;
|
||
+static int cur_part_entry;
|
||
#endif
|
||
|
||
/* Open a partition. */
|
||
@@ -755,6 +842,9 @@
|
||
unsigned long dest_partition = current_partition;
|
||
unsigned long part_offset;
|
||
unsigned long ext_offset;
|
||
+ unsigned long gpt_offset;
|
||
+ int gpt_count;
|
||
+ int gpt_size;
|
||
int entry;
|
||
char buf[SECTOR_SIZE];
|
||
int bsd_part, pc_slice;
|
||
@@ -766,7 +856,8 @@
|
||
int ret = next_partition (current_drive, dest_partition,
|
||
¤t_partition, ¤t_slice,
|
||
&part_start, &part_length,
|
||
- &part_offset, &entry, &ext_offset, buf);
|
||
+ &part_offset, &entry, &ext_offset,
|
||
+ &gpt_offset, &gpt_count, &gpt_size, buf);
|
||
bsd_part = (current_partition >> 8) & 0xFF;
|
||
pc_slice = current_partition >> 16;
|
||
return ret;
|
||
@@ -800,7 +891,12 @@
|
||
|
||
/* If this is the whole disk, return here. */
|
||
if (! flags && current_partition == 0xFFFFFF)
|
||
- return 1;
|
||
+ {
|
||
+#ifndef STAGE1_5
|
||
+ cur_part_offset = 0;
|
||
+#endif /* ! STAGE1_5 */
|
||
+ return 1;
|
||
+ }
|
||
|
||
if (flags)
|
||
dest_partition = 0xFFFFFF;
|
||
@@ -815,6 +911,8 @@
|
||
|
||
cur_part_offset = part_offset;
|
||
cur_part_addr = BOOT_PART_TABLE + (entry << 4);
|
||
+ cur_part_start = part_start;
|
||
+ cur_part_entry = entry;
|
||
#endif /* ! STAGE1_5 */
|
||
|
||
/* If this is a valid partition... */
|
||
@@ -1142,6 +1240,7 @@
|
||
src = (char *) SCRATCHADDR + BOOTSEC_PART_OFFSET;
|
||
while (dst < (char *) BOOT_PART_TABLE + BOOTSEC_PART_LENGTH)
|
||
*dst++ = *src++;
|
||
+ PC_SLICE_START (BOOT_PART_TABLE - PC_SLICE_OFFSET, cur_part_entry) = cur_part_start;
|
||
|
||
/* Set the active flag of the booted partition. */
|
||
for (i = 0; i < 4; i++)
|
||
diff -Nur grub-0.97/stage2/fsys_ext2fs.c grub-0.97-patched/stage2/fsys_ext2fs.c
|
||
--- grub-0.97/stage2/fsys_ext2fs.c 2004-08-08 20:19:18.000000000 +0200
|
||
+++ grub-0.97-patched/stage2/fsys_ext2fs.c 2012-11-11 17:07:12.750730331 +0100
|
||
@@ -41,6 +41,7 @@
|
||
typedef unsigned short __u16;
|
||
typedef __signed__ int __s32;
|
||
typedef unsigned int __u32;
|
||
+typedef unsigned long long __u64;
|
||
|
||
/*
|
||
* Constants relative to the data blocks, from ext2_fs.h
|
||
@@ -61,9 +62,9 @@
|
||
__u32 s_free_inodes_count; /* Free inodes count */
|
||
__u32 s_first_data_block; /* First Data Block */
|
||
__u32 s_log_block_size; /* Block size */
|
||
- __s32 s_log_frag_size; /* Fragment size */
|
||
+ __s32 s_obso_log_frag_size; /* Obsoleted Fragment size */
|
||
__u32 s_blocks_per_group; /* # Blocks per group */
|
||
- __u32 s_frags_per_group; /* # Fragments per group */
|
||
+ __u32 s_obso_frags_per_group; /* Obsoleted Fragments per group */
|
||
__u32 s_inodes_per_group; /* # Inodes per group */
|
||
__u32 s_mtime; /* Mount time */
|
||
__u32 s_wtime; /* Write time */
|
||
@@ -72,17 +73,62 @@
|
||
__u16 s_magic; /* Magic signature */
|
||
__u16 s_state; /* File system state */
|
||
__u16 s_errors; /* Behaviour when detecting errors */
|
||
- __u16 s_pad;
|
||
+ __u16 s_minor_rev_level; /* minor revision level */
|
||
__u32 s_lastcheck; /* time of last check */
|
||
__u32 s_checkinterval; /* max. time between checks */
|
||
__u32 s_creator_os; /* OS */
|
||
__u32 s_rev_level; /* Revision level */
|
||
__u16 s_def_resuid; /* Default uid for reserved blocks */
|
||
__u16 s_def_resgid; /* Default gid for reserved blocks */
|
||
- __u32 s_reserved[235]; /* Padding to the end of the block */
|
||
+ /*
|
||
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
|
||
+ *
|
||
+ * Note: the difference between the compatible feature set and
|
||
+ * the incompatible feature set is that if there is a bit set
|
||
+ * in the incompatible feature set that the kernel doesn't
|
||
+ * know about, it should refuse to mount the filesystem.
|
||
+ *
|
||
+ * e2fsck's requirements are more strict; if it doesn't know
|
||
+ * about a feature in either the compatible or incompatible
|
||
+ * feature set, it must abort and not try to meddle with
|
||
+ * things it doesn't understand...
|
||
+ */
|
||
+ __u32 s_first_ino; /* First non-reserved inode */
|
||
+ __u16 s_inode_size; /* size of inode structure */
|
||
+ __u16 s_block_group_nr; /* block group # of this superblock */
|
||
+ __u32 s_feature_compat; /* compatible feature set */
|
||
+ __u32 s_feature_incompat; /* incompatible feature set */
|
||
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
|
||
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
|
||
+ char s_volume_name[16]; /* volume name */
|
||
+ char s_last_mounted[64]; /* directory where last mounted */
|
||
+ __u32 s_algorithm_usage_bitmap; /* For compression */
|
||
+ /*
|
||
+ * Performance hints. Directory preallocation should only
|
||
+ * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
|
||
+ */
|
||
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
|
||
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
|
||
+ __u16 s_reserved_gdt_blocks;/* Per group table for online growth */
|
||
+ /*
|
||
+ * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
|
||
+ */
|
||
+ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
|
||
+ __u32 s_journal_inum; /* inode number of journal file */
|
||
+ __u32 s_journal_dev; /* device number of journal file */
|
||
+ __u32 s_last_orphan; /* start of list of inodes to delete */
|
||
+ __u32 s_hash_seed[4]; /* HTREE hash seed */
|
||
+ __u8 s_def_hash_version; /* Default hash version to use */
|
||
+ __u8 s_jnl_backup_type; /* Default type of journal backup */
|
||
+ __u16 s_desc_size; /* size of group descriptor */
|
||
+ __u32 s_default_mount_opts;
|
||
+ __u32 s_first_meta_bg; /* First metablock group */
|
||
+ __u32 s_mkfs_time; /* When the filesystem was created */
|
||
+ __u32 s_jnl_blocks[17]; /* Backup of the journal inode */
|
||
+ __u32 s_reserved[172]; /* Padding to the end of the block */
|
||
};
|
||
|
||
-struct ext2_group_desc
|
||
+struct ext4_group_desc
|
||
{
|
||
__u32 bg_block_bitmap; /* Blocks bitmap block */
|
||
__u32 bg_inode_bitmap; /* Inodes bitmap block */
|
||
@@ -90,8 +136,18 @@
|
||
__u16 bg_free_blocks_count; /* Free blocks count */
|
||
__u16 bg_free_inodes_count; /* Free inodes count */
|
||
__u16 bg_used_dirs_count; /* Directories count */
|
||
- __u16 bg_pad;
|
||
- __u32 bg_reserved[3];
|
||
+ __u16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */
|
||
+ __u32 bg_reserved[2]; /* Likely block/inode bitmap checksum */
|
||
+ __u16 bg_itable_unused; /* Unused inodes count */
|
||
+ __u16 bg_checksum; /* crc16(sb_uuid+group+desc) */
|
||
+ __u32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
|
||
+ __u32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */
|
||
+ __u32 bg_inode_table_hi; /* Inodes table block MSB */
|
||
+ __u16 bg_free_blocks_count_hi;/* Free blocks count MSB */
|
||
+ __u16 bg_free_inodes_count_hi;/* Free inodes count MSB */
|
||
+ __u16 bg_used_dirs_count_hi; /* Directories count MSB */
|
||
+ __u16 bg_itable_unused_hi; /* Unused inodes count MSB */
|
||
+ __u32 bg_reserved2[3];
|
||
};
|
||
|
||
struct ext2_inode
|
||
@@ -129,22 +185,22 @@
|
||
__u32 i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */
|
||
__u32 i_version; /* File version (for NFS) */
|
||
__u32 i_file_acl; /* File ACL */
|
||
- __u32 i_dir_acl; /* Directory ACL */
|
||
- __u32 i_faddr; /* Fragment address */
|
||
+ __u32 i_size_high;
|
||
+ __u32 i_obso_faddr; /* Obsoleted fragment address */
|
||
union
|
||
{
|
||
struct
|
||
{
|
||
- __u8 l_i_frag; /* Fragment number */
|
||
- __u8 l_i_fsize; /* Fragment size */
|
||
- __u16 i_pad1;
|
||
- __u32 l_i_reserved2[2];
|
||
+ __u16 l_i_blocks_high; /* were l_i_reserved1 */
|
||
+ __u16 l_i_file_acl_high;
|
||
+ __u16 l_i_uid_high; /* these 2 fields */
|
||
+ __u16 l_i_gid_high; /* were reserved2[0] */
|
||
+ __u32 l_i_reserved2;
|
||
}
|
||
linux2;
|
||
struct
|
||
{
|
||
- __u8 h_i_frag; /* Fragment number */
|
||
- __u8 h_i_fsize; /* Fragment size */
|
||
+ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
|
||
__u16 h_i_mode_high;
|
||
__u16 h_i_uid_high;
|
||
__u16 h_i_gid_high;
|
||
@@ -153,16 +209,36 @@
|
||
hurd2;
|
||
struct
|
||
{
|
||
- __u8 m_i_frag; /* Fragment number */
|
||
- __u8 m_i_fsize; /* Fragment size */
|
||
- __u16 m_pad1;
|
||
+ __u16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
|
||
+ __u16 m_i_file_acl_high;
|
||
__u32 m_i_reserved2[2];
|
||
}
|
||
masix2;
|
||
}
|
||
osd2; /* OS dependent 2 */
|
||
+ __u16 i_extra_isize;
|
||
+ __u16 i_pad1;
|
||
+ __u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
|
||
+ __u32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */
|
||
+ __u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
|
||
+ __u32 i_crtime; /* File Creation time */
|
||
+ __u32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
|
||
+ __u32 i_version_hi; /* high 32 bits for 64-bit version */
|
||
};
|
||
|
||
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
|
||
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 /* grub not supported*/
|
||
+#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
|
||
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
|
||
+
|
||
+#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \
|
||
+ ( sb->s_feature_incompat & mask )
|
||
+
|
||
+#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
|
||
+#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
|
||
+
|
||
+#define EXT4_MIN_DESC_SIZE 32
|
||
+
|
||
/* linux/limits.h */
|
||
#define NAME_MAX 255 /* # chars in a file name */
|
||
|
||
@@ -180,6 +256,57 @@
|
||
char name[EXT2_NAME_LEN]; /* File name */
|
||
};
|
||
|
||
+/* linux/ext4_fs_extents.h */
|
||
+/* This is the extent on-disk structure.
|
||
+ * It's used at the bottom of the tree.
|
||
+ */
|
||
+struct ext4_extent
|
||
+ {
|
||
+ __u32 ee_block; /* first logical block extent covers */
|
||
+ __u16 ee_len; /* number of blocks covered by extent */
|
||
+ __u16 ee_start_hi; /* high 16 bits of physical block */
|
||
+ __u32 ee_start_lo; /* low 32 bits of physical block */
|
||
+ };
|
||
+
|
||
+/*
|
||
+ * This is index on-disk structure.
|
||
+ * It's used at all the levels except the bottom.
|
||
+ */
|
||
+struct ext4_extent_idx
|
||
+ {
|
||
+ __u32 ei_block; /* index covers logical blocks from 'block' */
|
||
+ __u32 ei_leaf_lo; /* pointer to the physical block of the next *
|
||
+ * level. leaf or next index could be there */
|
||
+ __u16 ei_leaf_hi; /* high 16 bits of physical block */
|
||
+ __u16 ei_unused;
|
||
+ };
|
||
+
|
||
+/*
|
||
+ * Each block (leaves and indexes), even inode-stored has header.
|
||
+ */
|
||
+struct ext4_extent_header
|
||
+ {
|
||
+ __u16 eh_magic; /* probably will support different formats */
|
||
+ __u16 eh_entries; /* number of valid entries */
|
||
+ __u16 eh_max; /* capacity of store in entries */
|
||
+ __u16 eh_depth; /* has tree real underlying blocks? */
|
||
+ __u32 eh_generation; /* generation of the tree */
|
||
+ };
|
||
+
|
||
+#define EXT4_EXT_MAGIC (0xf30a)
|
||
+#define EXT_FIRST_EXTENT(__hdr__) \
|
||
+ ((struct ext4_extent *) (((char *) (__hdr__)) + \
|
||
+ sizeof(struct ext4_extent_header)))
|
||
+#define EXT_FIRST_INDEX(__hdr__) \
|
||
+ ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \
|
||
+ sizeof(struct ext4_extent_header)))
|
||
+#define EXT_LAST_EXTENT(__hdr__) \
|
||
+ (EXT_FIRST_EXTENT((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1)
|
||
+#define EXT_LAST_INDEX(__hdr__) \
|
||
+ (EXT_FIRST_INDEX((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1)
|
||
+
|
||
+
|
||
+
|
||
/* linux/ext2fs.h */
|
||
/*
|
||
* EXT2_DIR_PAD defines the directory entries boundaries
|
||
@@ -218,13 +345,30 @@
|
||
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
|
||
#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s)))
|
||
|
||
+#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
|
||
+#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
|
||
+#define EXT2_GOOD_OLD_INODE_SIZE 128
|
||
+#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
|
||
+ EXT2_GOOD_OLD_INODE_SIZE : \
|
||
+ (s)->s_inode_size)
|
||
+#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
|
||
+
|
||
/* linux/ext2_fs.h */
|
||
#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
|
||
/* kind of from ext2/super.c */
|
||
#define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s))
|
||
/* linux/ext2fs.h */
|
||
+/* sizeof(struct ext2_group_desc) is changed in ext4
|
||
+ * in kernel code, ext2/3 uses sizeof(struct ext2_group_desc) to calculate
|
||
+ * number of desc per block, while ext4 uses superblock->s_desc_size in stead
|
||
+ * superblock->s_desc_size is not available in ext2/3
|
||
+ * */
|
||
+#define EXT2_DESC_SIZE(s) \
|
||
+ (EXT4_HAS_INCOMPAT_FEATURE(s,EXT4_FEATURE_INCOMPAT_64BIT)? \
|
||
+ s->s_desc_size : EXT4_MIN_DESC_SIZE)
|
||
#define EXT2_DESC_PER_BLOCK(s) \
|
||
- (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
|
||
+ (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s))
|
||
+
|
||
/* linux/stat.h */
|
||
#define S_IFMT 00170000
|
||
#define S_IFLNK 0120000
|
||
@@ -386,6 +530,122 @@
|
||
[logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
|
||
}
|
||
|
||
+/* extent binary search index
|
||
+ * find closest index in the current level extent tree
|
||
+ * kind of from ext4_ext_binsearch_idx in ext4/extents.c
|
||
+ */
|
||
+static struct ext4_extent_idx*
|
||
+ext4_ext_binsearch_idx(struct ext4_extent_header* eh, int logical_block)
|
||
+{
|
||
+ struct ext4_extent_idx *r, *l, *m;
|
||
+ l = EXT_FIRST_INDEX(eh) + 1;
|
||
+ r = EXT_LAST_INDEX(eh);
|
||
+ while (l <= r)
|
||
+ {
|
||
+ m = l + (r - l) / 2;
|
||
+ if (logical_block < m->ei_block)
|
||
+ r = m - 1;
|
||
+ else
|
||
+ l = m + 1;
|
||
+ }
|
||
+ return (struct ext4_extent_idx*)(l - 1);
|
||
+}
|
||
+
|
||
+/* extent binary search
|
||
+ * find closest extent in the leaf level
|
||
+ * kind of from ext4_ext_binsearch in ext4/extents.c
|
||
+ */
|
||
+static struct ext4_extent*
|
||
+ext4_ext_binsearch(struct ext4_extent_header* eh, int logical_block)
|
||
+{
|
||
+ struct ext4_extent *r, *l, *m;
|
||
+ l = EXT_FIRST_EXTENT(eh) + 1;
|
||
+ r = EXT_LAST_EXTENT(eh);
|
||
+ while (l <= r)
|
||
+ {
|
||
+ m = l + (r - l) / 2;
|
||
+ if (logical_block < m->ee_block)
|
||
+ r = m - 1;
|
||
+ else
|
||
+ l = m + 1;
|
||
+ }
|
||
+ return (struct ext4_extent*)(l - 1);
|
||
+}
|
||
+
|
||
+/* Maps extents enabled logical block into physical block via an inode.
|
||
+ * EXT4_HUGE_FILE_FL should be checked before calling this.
|
||
+ */
|
||
+static int
|
||
+ext4fs_block_map (int logical_block)
|
||
+{
|
||
+ struct ext4_extent_header *eh;
|
||
+ struct ext4_extent *ex, *extent;
|
||
+ struct ext4_extent_idx *ei, *index;
|
||
+ int depth;
|
||
+ int i;
|
||
+
|
||
+#ifdef E2DEBUG
|
||
+ unsigned char *i;
|
||
+ for (i = (unsigned char *) INODE;
|
||
+ i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
|
||
+ i++)
|
||
+ {
|
||
+ printf ("%c", "0123456789abcdef"[*i >> 4]);
|
||
+ printf ("%c", "0123456789abcdef"[*i % 16]);
|
||
+ if (!((i + 1 - (unsigned char *) INODE) % 16))
|
||
+ {
|
||
+ printf ("\n");
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ printf (" ");
|
||
+ }
|
||
+ }
|
||
+ printf ("logical block %d\n", logical_block);
|
||
+#endif /* E2DEBUG */
|
||
+ eh = (struct ext4_extent_header*)INODE->i_block;
|
||
+ if (eh->eh_magic != EXT4_EXT_MAGIC)
|
||
+ {
|
||
+ errnum = ERR_FSYS_CORRUPT;
|
||
+ return -1;
|
||
+ }
|
||
+ while((depth = eh->eh_depth) != 0)
|
||
+ { /* extent index */
|
||
+ if (eh->eh_magic != EXT4_EXT_MAGIC)
|
||
+ {
|
||
+ errnum = ERR_FSYS_CORRUPT;
|
||
+ return -1;
|
||
+ }
|
||
+ ei = ext4_ext_binsearch_idx(eh, logical_block);
|
||
+ if (ei->ei_leaf_hi)
|
||
+ {/* 64bit physical block number not supported */
|
||
+ errnum = ERR_FILELENGTH;
|
||
+ return -1;
|
||
+ }
|
||
+ if (!ext2_rdfsb(ei->ei_leaf_lo, DATABLOCK1))
|
||
+ {
|
||
+ errnum = ERR_FSYS_CORRUPT;
|
||
+ return -1;
|
||
+ }
|
||
+ eh = (struct ext4_extent_header*)DATABLOCK1;
|
||
+ }
|
||
+
|
||
+ /* depth==0, we come to the leaf */
|
||
+ ex = ext4_ext_binsearch(eh, logical_block);
|
||
+ if (ex->ee_start_hi)
|
||
+ {/* 64bit physical block number not supported */
|
||
+ errnum = ERR_FILELENGTH;
|
||
+ return -1;
|
||
+ }
|
||
+ if ((ex->ee_block + ex->ee_len) < logical_block)
|
||
+ {
|
||
+ errnum = ERR_FSYS_CORRUPT;
|
||
+ return -1;
|
||
+ }
|
||
+ return ex->ee_start_lo + logical_block - ex->ee_block;
|
||
+
|
||
+}
|
||
+
|
||
/* preconditions: all preconds of ext2fs_block_map */
|
||
int
|
||
ext2fs_read (char *buf, int len)
|
||
@@ -420,6 +680,11 @@
|
||
/* find the (logical) block component of our location */
|
||
logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
|
||
offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
|
||
+ /* map extents enabled logical block number to physical fs on-dick block number */
|
||
+ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS)
|
||
+ && INODE->i_flags & EXT4_EXTENTS_FL)
|
||
+ map = ext4fs_block_map (logical_block);
|
||
+ else
|
||
map = ext2fs_block_map (logical_block);
|
||
#ifdef E2DEBUG
|
||
printf ("map=%d\n", map);
|
||
@@ -504,7 +769,7 @@
|
||
int desc; /* index within that group */
|
||
int ino_blk; /* fs pointer of the inode's information */
|
||
int str_chk = 0; /* used to hold the results of a string compare */
|
||
- struct ext2_group_desc *gdp;
|
||
+ struct ext4_group_desc *ext4_gdp;
|
||
struct ext2_inode *raw_inode; /* inode info corresponding to current_ino */
|
||
|
||
char linkbuf[PATH_MAX]; /* buffer for following symbolic links */
|
||
@@ -550,10 +815,17 @@
|
||
{
|
||
return 0;
|
||
}
|
||
- gdp = GROUP_DESC;
|
||
- ino_blk = gdp[desc].bg_inode_table +
|
||
+ ext4_gdp = (struct ext4_group_desc *)( (__u8*)GROUP_DESC +
|
||
+ desc * EXT2_DESC_SIZE(SUPERBLOCK));
|
||
+ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK, EXT4_FEATURE_INCOMPAT_64BIT)
|
||
+ && (! ext4_gdp->bg_inode_table_hi))
|
||
+ {/* 64bit itable not supported */
|
||
+ errnum = ERR_FILELENGTH;
|
||
+ return -1;
|
||
+ }
|
||
+ ino_blk = ext4_gdp->bg_inode_table +
|
||
(((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group))
|
||
- >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
|
||
+ >> log2 (EXT2_INODES_PER_BLOCK (SUPERBLOCK)));
|
||
#ifdef E2DEBUG
|
||
printf ("inode table fsblock=%d\n", ino_blk);
|
||
#endif /* E2DEBUG */
|
||
@@ -565,13 +837,12 @@
|
||
/* reset indirect blocks! */
|
||
mapblock2 = mapblock1 = -1;
|
||
|
||
- raw_inode = INODE +
|
||
- ((current_ino - 1)
|
||
- & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1));
|
||
+ raw_inode = (struct ext2_inode *)((char *)INODE +
|
||
+ ((current_ino - 1) & (EXT2_INODES_PER_BLOCK (SUPERBLOCK) - 1)) *
|
||
+ EXT2_INODE_SIZE (SUPERBLOCK));
|
||
#ifdef E2DEBUG
|
||
printf ("ipb=%d, sizeof(inode)=%d\n",
|
||
- (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)),
|
||
- sizeof (struct ext2_inode));
|
||
+ EXT2_INODES_PER_BLOCK (SUPERBLOCK), EXT2_INODE_SIZE (SUPERBLOCK));
|
||
printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode);
|
||
printf ("offset into inode table block=%d\n", (int) raw_inode - (int) INODE);
|
||
for (i = (unsigned char *) INODE; i <= (unsigned char *) raw_inode;
|
||
@@ -629,7 +900,10 @@
|
||
}
|
||
linkbuf[filemax + len] = '\0';
|
||
|
||
- /* Read the symlink data. */
|
||
+ /* Read the symlink data.
|
||
+ * Slow symlink is extents enabled
|
||
+ * But since grub_read invokes ext2fs_read, nothing to change here
|
||
+ * */
|
||
if (! ext2_is_fast_symlink ())
|
||
{
|
||
/* Read the necessary blocks, and reset the file pointer. */
|
||
@@ -640,7 +914,9 @@
|
||
}
|
||
else
|
||
{
|
||
- /* Copy the data directly from the inode. */
|
||
+ /* Copy the data directly from the inode.
|
||
+ * Fast symlink is not extents enabled
|
||
+ * */
|
||
len = filemax;
|
||
memmove (linkbuf, (char *) INODE->i_block, len);
|
||
}
|
||
@@ -674,6 +950,13 @@
|
||
errnum = ERR_BAD_FILETYPE;
|
||
return 0;
|
||
}
|
||
+ /* if file is too large, just stop and report an error*/
|
||
+ if ( (INODE->i_flags & EXT4_HUGE_FILE_FL) && !(INODE->i_size_high))
|
||
+ {
|
||
+ /* file too large, stop reading */
|
||
+ errnum = ERR_FILELENGTH;
|
||
+ return 0;
|
||
+ }
|
||
|
||
filemax = (INODE->i_size);
|
||
return 1;
|
||
@@ -728,17 +1011,28 @@
|
||
}
|
||
|
||
/* else, find the (logical) block component of our location */
|
||
+ /* ext4 logical block number the same as ext2/3 */
|
||
blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
|
||
|
||
/* we know which logical block of the directory entry we are looking
|
||
for, now we have to translate that to the physical (fs) block on
|
||
the disk */
|
||
+ /* map extents enabled logical block number to physical fs on-dick block number */
|
||
+ if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS)
|
||
+ && INODE->i_flags & EXT4_EXTENTS_FL)
|
||
+ map = ext4fs_block_map (blk);
|
||
+ else
|
||
map = ext2fs_block_map (blk);
|
||
#ifdef E2DEBUG
|
||
printf ("fs block=%d\n", map);
|
||
#endif /* E2DEBUG */
|
||
mapblock2 = -1;
|
||
- if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2))
|
||
+ if (map < 0)
|
||
+ {
|
||
+ *rest = ch;
|
||
+ return 0;
|
||
+ }
|
||
+ if (!ext2_rdfsb (map, DATABLOCK2))
|
||
{
|
||
errnum = ERR_FSYS_CORRUPT;
|
||
*rest = ch;
|
||
diff -Nur grub-0.97/stage2/gpt.h grub-0.97-patched/stage2/gpt.h
|
||
--- grub-0.97/stage2/gpt.h 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/gpt.h 2012-11-11 17:07:12.697728638 +0100
|
||
@@ -0,0 +1,68 @@
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 2002,2005,2006 Free Software Foundation, Inc.
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License as published by
|
||
+ * the Free Software Foundation; either version 2 of the License, or
|
||
+ * (at your option) any later version.
|
||
+ *
|
||
+ * This program is distributed in the hope that it will be useful,
|
||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ * GNU General Public License for more details.
|
||
+ *
|
||
+ * You should have received a copy of the GNU General Public License
|
||
+ * along with this program; if not, write to the Free Software
|
||
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
+ */
|
||
+
|
||
+#ifndef _GPT_H
|
||
+#define _GPT_H
|
||
+
|
||
+typedef signed char grub_int8_t;
|
||
+typedef signed short grub_int16_t;
|
||
+typedef signed int grub_int32_t;
|
||
+typedef signed long long int grub_int64_t;
|
||
+typedef unsigned char grub_uint8_t;
|
||
+typedef unsigned short grub_uint16_t;
|
||
+typedef unsigned int grub_uint32_t;
|
||
+typedef unsigned long long int grub_uint64_t;
|
||
+
|
||
+struct grub_gpt_header
|
||
+{
|
||
+ grub_uint64_t magic;
|
||
+ grub_uint32_t version;
|
||
+ grub_uint32_t headersize;
|
||
+ grub_uint32_t crc32;
|
||
+ grub_uint32_t unused1;
|
||
+ grub_uint64_t primary;
|
||
+ grub_uint64_t backup;
|
||
+ grub_uint64_t start;
|
||
+ grub_uint64_t end;
|
||
+ grub_uint8_t guid[16];
|
||
+ grub_uint64_t partitions;
|
||
+ grub_uint32_t maxpart;
|
||
+ grub_uint32_t partentry_size;
|
||
+ grub_uint32_t partentry_crc32;
|
||
+} __attribute__ ((packed));
|
||
+
|
||
+struct grub_gpt_partentry
|
||
+{
|
||
+ grub_uint64_t type1;
|
||
+ grub_uint64_t type2;
|
||
+ grub_uint8_t guid[16];
|
||
+ grub_uint64_t start;
|
||
+ grub_uint64_t end;
|
||
+ grub_uint8_t attrib;
|
||
+ char name[72];
|
||
+} __attribute__ ((packed));
|
||
+
|
||
+#define GPT_HEADER_MAGIC 0x5452415020494645UL
|
||
+
|
||
+#define GPT_ENTRY_SECTOR(size,entry) \
|
||
+ ((((entry) * (size) + 1) & ~(SECTOR_SIZE - 1)) >> SECTOR_BITS)
|
||
+#define GPT_ENTRY_INDEX(size,entry) \
|
||
+ ((((entry) * (size) + 1) & (SECTOR_SIZE - 1)) - 1)
|
||
+
|
||
+#endif /* _GPT_H */
|
||
diff -Nur grub-0.97/stage2/graphics.c grub-0.97-patched/stage2/graphics.c
|
||
--- grub-0.97/stage2/graphics.c 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/graphics.c 2012-11-11 17:06:33.320470847 +0100
|
||
@@ -0,0 +1,563 @@
|
||
+/* graphics.c - graphics mode support for GRUB */
|
||
+/* Implemented as a terminal type by Jeremy Katz <katzj@redhat.com> based
|
||
+ * on a patch by Paulo C<>sar Pereira de Andrade <pcpa@conectiva.com.br>
|
||
+ */
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 2001,2002 Red Hat, Inc.
|
||
+ * Portions copyright (C) 2000 Conectiva, Inc.
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License as published by
|
||
+ * the Free Software Foundation; either version 2 of the License, or
|
||
+ * (at your option) any later version.
|
||
+ *
|
||
+ * This program is distributed in the hope that it will be useful,
|
||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ * GNU General Public License for more details.
|
||
+ *
|
||
+ * You should have received a copy of the GNU General Public License
|
||
+ * along with this program; if not, write to the Free Software
|
||
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
+ */
|
||
+
|
||
+
|
||
+
|
||
+#ifdef SUPPORT_GRAPHICS
|
||
+
|
||
+#include <term.h>
|
||
+#include <shared.h>
|
||
+#include <graphics.h>
|
||
+
|
||
+int saved_videomode;
|
||
+unsigned char *font8x16;
|
||
+
|
||
+int graphics_inited = 0;
|
||
+static char splashimage[64];
|
||
+
|
||
+#define VSHADOW VSHADOW1
|
||
+unsigned char VSHADOW1[38400];
|
||
+unsigned char VSHADOW2[38400];
|
||
+unsigned char VSHADOW4[38400];
|
||
+unsigned char VSHADOW8[38400];
|
||
+
|
||
+/* constants to define the viewable area */
|
||
+const int x0 = 0;
|
||
+const int x1 = 80;
|
||
+const int y0 = 0;
|
||
+const int y1 = 30;
|
||
+
|
||
+/* text buffer has to be kept around so that we can write things as we
|
||
+ * scroll and the like */
|
||
+unsigned short text[80 * 30];
|
||
+
|
||
+/* why do these have to be kept here? */
|
||
+int foreground = (63 << 16) | (63 << 8) | (63), background = 0, border = 0;
|
||
+
|
||
+/* current position */
|
||
+static int fontx = 0;
|
||
+static int fonty = 0;
|
||
+
|
||
+/* global state so that we don't try to recursively scroll or cursor */
|
||
+static int no_scroll = 0;
|
||
+
|
||
+/* color state */
|
||
+static int graphics_standard_color = A_NORMAL;
|
||
+static int graphics_normal_color = A_NORMAL;
|
||
+static int graphics_highlight_color = A_REVERSE;
|
||
+static int graphics_current_color = A_NORMAL;
|
||
+static color_state graphics_color_state = COLOR_STATE_STANDARD;
|
||
+
|
||
+
|
||
+/* graphics local functions */
|
||
+static void graphics_setxy(int col, int row);
|
||
+static void graphics_scroll();
|
||
+
|
||
+/* FIXME: where do these really belong? */
|
||
+static inline void outb(unsigned short port, unsigned char val)
|
||
+{
|
||
+ __asm __volatile ("outb %0,%1"::"a" (val), "d" (port));
|
||
+}
|
||
+
|
||
+static void MapMask(int value) {
|
||
+ outb(0x3c4, 2);
|
||
+ outb(0x3c5, value);
|
||
+}
|
||
+
|
||
+/* bit mask register */
|
||
+static void BitMask(int value) {
|
||
+ outb(0x3ce, 8);
|
||
+ outb(0x3cf, value);
|
||
+}
|
||
+
|
||
+
|
||
+
|
||
+/* Set the splash image */
|
||
+void graphics_set_splash(char *splashfile) {
|
||
+ grub_strcpy(splashimage, splashfile);
|
||
+}
|
||
+
|
||
+/* Get the current splash image */
|
||
+char *graphics_get_splash(void) {
|
||
+ return splashimage;
|
||
+}
|
||
+
|
||
+/* Initialize a vga16 graphics display with the palette based off of
|
||
+ * the image in splashimage. If the image doesn't exist, leave graphics
|
||
+ * mode. */
|
||
+int graphics_init()
|
||
+{
|
||
+ if(!grub_file_exists(splashimage)) {
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (!graphics_inited) {
|
||
+ saved_videomode = set_videomode(0x12);
|
||
+ }
|
||
+
|
||
+ if (!read_image(splashimage)) {
|
||
+ set_videomode(saved_videomode);
|
||
+ grub_printf("failed to read image\n");
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ font8x16 = (unsigned char*)graphics_get_font();
|
||
+
|
||
+ graphics_inited = 1;
|
||
+
|
||
+ /* make sure that the highlight color is set correctly */
|
||
+ graphics_highlight_color = ((graphics_normal_color >> 4) |
|
||
+ ((graphics_normal_color & 0xf) << 4));
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+/* Leave graphics mode */
|
||
+void graphics_end(void)
|
||
+{
|
||
+ if (graphics_inited) {
|
||
+ set_videomode(saved_videomode);
|
||
+ graphics_inited = 0;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Print ch on the screen. Handle any needed scrolling or the like */
|
||
+void graphics_putchar(int ch) {
|
||
+ ch &= 0xff;
|
||
+
|
||
+ graphics_cursor(0);
|
||
+
|
||
+ if (ch == '\n') {
|
||
+ if (fonty + 1 < y1)
|
||
+ graphics_setxy(fontx, fonty + 1);
|
||
+ else
|
||
+ graphics_scroll();
|
||
+ graphics_cursor(1);
|
||
+ return;
|
||
+ } else if (ch == '\r') {
|
||
+ graphics_setxy(x0, fonty);
|
||
+ graphics_cursor(1);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ graphics_cursor(0);
|
||
+
|
||
+ text[fonty * 80 + fontx] = ch;
|
||
+ text[fonty * 80 + fontx] &= 0x00ff;
|
||
+ if (graphics_current_color & 0xf0)
|
||
+ text[fonty * 80 + fontx] |= 0x100;
|
||
+
|
||
+ graphics_cursor(0);
|
||
+
|
||
+ if ((fontx + 1) >= x1) {
|
||
+ graphics_setxy(x0, fonty);
|
||
+ if (fonty + 1 < y1)
|
||
+ graphics_setxy(x0, fonty + 1);
|
||
+ else
|
||
+ graphics_scroll();
|
||
+ } else {
|
||
+ graphics_setxy(fontx + 1, fonty);
|
||
+ }
|
||
+
|
||
+ graphics_cursor(1);
|
||
+}
|
||
+
|
||
+/* get the current location of the cursor */
|
||
+int graphics_getxy(void) {
|
||
+ return (fontx << 8) | fonty;
|
||
+}
|
||
+
|
||
+void graphics_gotoxy(int x, int y) {
|
||
+ graphics_cursor(0);
|
||
+
|
||
+ graphics_setxy(x, y);
|
||
+
|
||
+ graphics_cursor(1);
|
||
+}
|
||
+
|
||
+void graphics_cls(void) {
|
||
+ int i;
|
||
+ unsigned char *mem, *s1, *s2, *s4, *s8;
|
||
+
|
||
+ graphics_cursor(0);
|
||
+ graphics_gotoxy(x0, y0);
|
||
+
|
||
+ mem = (unsigned char*)VIDEOMEM;
|
||
+ s1 = (unsigned char*)VSHADOW1;
|
||
+ s2 = (unsigned char*)VSHADOW2;
|
||
+ s4 = (unsigned char*)VSHADOW4;
|
||
+ s8 = (unsigned char*)VSHADOW8;
|
||
+
|
||
+ for (i = 0; i < 80 * 30; i++)
|
||
+ text[i] = ' ';
|
||
+ graphics_cursor(1);
|
||
+
|
||
+ BitMask(0xff);
|
||
+
|
||
+ /* plano 1 */
|
||
+ MapMask(1);
|
||
+ grub_memcpy(mem, s1, 38400);
|
||
+
|
||
+ /* plano 2 */
|
||
+ MapMask(2);
|
||
+ grub_memcpy(mem, s2, 38400);
|
||
+
|
||
+ /* plano 3 */
|
||
+ MapMask(4);
|
||
+ grub_memcpy(mem, s4, 38400);
|
||
+
|
||
+ /* plano 4 */
|
||
+ MapMask(8);
|
||
+ grub_memcpy(mem, s8, 38400);
|
||
+
|
||
+ MapMask(15);
|
||
+
|
||
+}
|
||
+
|
||
+void graphics_setcolorstate (color_state state) {
|
||
+ switch (state) {
|
||
+ case COLOR_STATE_STANDARD:
|
||
+ graphics_current_color = graphics_standard_color;
|
||
+ break;
|
||
+ case COLOR_STATE_NORMAL:
|
||
+ graphics_current_color = graphics_normal_color;
|
||
+ break;
|
||
+ case COLOR_STATE_HIGHLIGHT:
|
||
+ graphics_current_color = graphics_highlight_color;
|
||
+ break;
|
||
+ default:
|
||
+ graphics_current_color = graphics_standard_color;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ graphics_color_state = state;
|
||
+}
|
||
+
|
||
+void graphics_setcolor (int normal_color, int highlight_color) {
|
||
+ graphics_normal_color = normal_color;
|
||
+ graphics_highlight_color = highlight_color;
|
||
+
|
||
+ graphics_setcolorstate (graphics_color_state);
|
||
+}
|
||
+
|
||
+void graphics_setcursor (int on) {
|
||
+ /* FIXME: we don't have a cursor in graphics */
|
||
+ return;
|
||
+}
|
||
+
|
||
+/* Read in the splashscreen image and set the palette up appropriately.
|
||
+ * Format of splashscreen is an xpm (can be gzipped) with 16 colors and
|
||
+ * 640x480. */
|
||
+int read_image(char *s)
|
||
+{
|
||
+ char buf[32], pal[16];
|
||
+ unsigned char c, base, mask, *s1, *s2, *s4, *s8;
|
||
+ unsigned i, len, idx, colors, x, y, width, height;
|
||
+
|
||
+ if (!grub_open(s))
|
||
+ return 0;
|
||
+
|
||
+ /* read header */
|
||
+ if (!grub_read((char*)&buf, 10) || grub_memcmp(buf, "/* XPM */\n", 10)) {
|
||
+ grub_close();
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ /* parse info */
|
||
+ while (grub_read(&c, 1)) {
|
||
+ if (c == '"')
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ while (grub_read(&c, 1) && (c == ' ' || c == '\t'))
|
||
+ ;
|
||
+
|
||
+ i = 0;
|
||
+ width = c - '0';
|
||
+ while (grub_read(&c, 1)) {
|
||
+ if (c >= '0' && c <= '9')
|
||
+ width = width * 10 + c - '0';
|
||
+ else
|
||
+ break;
|
||
+ }
|
||
+ while (grub_read(&c, 1) && (c == ' ' || c == '\t'))
|
||
+ ;
|
||
+
|
||
+ height = c - '0';
|
||
+ while (grub_read(&c, 1)) {
|
||
+ if (c >= '0' && c <= '9')
|
||
+ height = height * 10 + c - '0';
|
||
+ else
|
||
+ break;
|
||
+ }
|
||
+ while (grub_read(&c, 1) && (c == ' ' || c == '\t'))
|
||
+ ;
|
||
+
|
||
+ colors = c - '0';
|
||
+ while (grub_read(&c, 1)) {
|
||
+ if (c >= '0' && c <= '9')
|
||
+ colors = colors * 10 + c - '0';
|
||
+ else
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ base = 0;
|
||
+ while (grub_read(&c, 1) && c != '"')
|
||
+ ;
|
||
+
|
||
+ /* palette */
|
||
+ for (i = 0, idx = 1; i < colors; i++) {
|
||
+ len = 0;
|
||
+
|
||
+ while (grub_read(&c, 1) && c != '"')
|
||
+ ;
|
||
+ grub_read(&c, 1); /* char */
|
||
+ base = c;
|
||
+ grub_read(buf, 4); /* \t c # */
|
||
+
|
||
+ while (grub_read(&c, 1) && c != '"') {
|
||
+ if (len < sizeof(buf))
|
||
+ buf[len++] = c;
|
||
+ }
|
||
+
|
||
+ if (len == 6 && idx < 15) {
|
||
+ int r = ((hex(buf[0]) << 4) | hex(buf[1])) >> 2;
|
||
+ int g = ((hex(buf[2]) << 4) | hex(buf[3])) >> 2;
|
||
+ int b = ((hex(buf[4]) << 4) | hex(buf[5])) >> 2;
|
||
+
|
||
+ pal[idx] = base;
|
||
+ graphics_set_palette(idx, r, g, b);
|
||
+ ++idx;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ x = y = len = 0;
|
||
+
|
||
+ s1 = (unsigned char*)VSHADOW1;
|
||
+ s2 = (unsigned char*)VSHADOW2;
|
||
+ s4 = (unsigned char*)VSHADOW4;
|
||
+ s8 = (unsigned char*)VSHADOW8;
|
||
+
|
||
+ for (i = 0; i < 38400; i++)
|
||
+ s1[i] = s2[i] = s4[i] = s8[i] = 0;
|
||
+
|
||
+ /* parse xpm data */
|
||
+ while (y < height) {
|
||
+ while (1) {
|
||
+ if (!grub_read(&c, 1)) {
|
||
+ grub_close();
|
||
+ return 0;
|
||
+ }
|
||
+ if (c == '"')
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ while (grub_read(&c, 1) && c != '"') {
|
||
+ for (i = 1; i < 15; i++)
|
||
+ if (pal[i] == c) {
|
||
+ c = i;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ mask = 0x80 >> (x & 7);
|
||
+ if (c & 1)
|
||
+ s1[len + (x >> 3)] |= mask;
|
||
+ if (c & 2)
|
||
+ s2[len + (x >> 3)] |= mask;
|
||
+ if (c & 4)
|
||
+ s4[len + (x >> 3)] |= mask;
|
||
+ if (c & 8)
|
||
+ s8[len + (x >> 3)] |= mask;
|
||
+
|
||
+ if (++x >= 640) {
|
||
+ x = 0;
|
||
+
|
||
+ if (y < 480)
|
||
+ len += 80;
|
||
+ ++y;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ grub_close();
|
||
+
|
||
+ graphics_set_palette(0, (background >> 16), (background >> 8) & 63,
|
||
+ background & 63);
|
||
+ graphics_set_palette(15, (foreground >> 16), (foreground >> 8) & 63,
|
||
+ foreground & 63);
|
||
+ graphics_set_palette(0x11, (border >> 16), (border >> 8) & 63,
|
||
+ border & 63);
|
||
+
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+
|
||
+/* Convert a character which is a hex digit to the appropriate integer */
|
||
+int hex(int v)
|
||
+{
|
||
+ if (v >= 'A' && v <= 'F')
|
||
+ return (v - 'A' + 10);
|
||
+ if (v >= 'a' && v <= 'f')
|
||
+ return (v - 'a' + 10);
|
||
+ return (v - '0');
|
||
+}
|
||
+
|
||
+
|
||
+/* move the graphics cursor location to col, row */
|
||
+static void graphics_setxy(int col, int row) {
|
||
+ if (col >= x0 && col < x1) {
|
||
+ fontx = col;
|
||
+ cursorX = col << 3;
|
||
+ }
|
||
+ if (row >= y0 && row < y1) {
|
||
+ fonty = row;
|
||
+ cursorY = row << 4;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* scroll the screen */
|
||
+static void graphics_scroll() {
|
||
+ int i, j;
|
||
+
|
||
+ /* we don't want to scroll recursively... that would be bad */
|
||
+ if (no_scroll)
|
||
+ return;
|
||
+ no_scroll = 1;
|
||
+
|
||
+ /* move everything up a line */
|
||
+ for (j = y0 + 1; j < y1; j++) {
|
||
+ graphics_gotoxy(x0, j - 1);
|
||
+ for (i = x0; i < x1; i++) {
|
||
+ graphics_putchar(text[j * 80 + i]);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* last line should be blank */
|
||
+ graphics_gotoxy(x0, y1 - 1);
|
||
+ for (i = x0; i < x1; i++)
|
||
+ graphics_putchar(' ');
|
||
+ graphics_setxy(x0, y1 - 1);
|
||
+
|
||
+ no_scroll = 0;
|
||
+}
|
||
+
|
||
+
|
||
+void graphics_cursor(int set) {
|
||
+ unsigned char *pat, *mem, *ptr, chr[16 << 2];
|
||
+ int i, ch, invert, offset;
|
||
+
|
||
+ if (set && no_scroll)
|
||
+ return;
|
||
+
|
||
+ offset = cursorY * 80 + fontx;
|
||
+ ch = text[fonty * 80 + fontx] & 0xff;
|
||
+ invert = (text[fonty * 80 + fontx] & 0xff00) != 0;
|
||
+ pat = font8x16 + (ch << 4);
|
||
+
|
||
+ mem = (unsigned char*)VIDEOMEM + offset;
|
||
+
|
||
+ if (!set) {
|
||
+ for (i = 0; i < 16; i++) {
|
||
+ unsigned char mask = pat[i];
|
||
+
|
||
+ if (!invert) {
|
||
+ chr[i ] = ((unsigned char*)VSHADOW1)[offset];
|
||
+ chr[16 + i] = ((unsigned char*)VSHADOW2)[offset];
|
||
+ chr[32 + i] = ((unsigned char*)VSHADOW4)[offset];
|
||
+ chr[48 + i] = ((unsigned char*)VSHADOW8)[offset];
|
||
+
|
||
+ /* FIXME: if (shade) */
|
||
+ if (1) {
|
||
+ if (ch == DISP_VERT || ch == DISP_LL ||
|
||
+ ch == DISP_UR || ch == DISP_LR) {
|
||
+ unsigned char pmask = ~(pat[i] >> 1);
|
||
+
|
||
+ chr[i ] &= pmask;
|
||
+ chr[16 + i] &= pmask;
|
||
+ chr[32 + i] &= pmask;
|
||
+ chr[48 + i] &= pmask;
|
||
+ }
|
||
+ if (i > 0 && ch != DISP_VERT) {
|
||
+ unsigned char pmask = ~(pat[i - 1] >> 1);
|
||
+
|
||
+ chr[i ] &= pmask;
|
||
+ chr[16 + i] &= pmask;
|
||
+ chr[32 + i] &= pmask;
|
||
+ chr[48 + i] &= pmask;
|
||
+ if (ch == DISP_HORIZ || ch == DISP_UR || ch == DISP_LR) {
|
||
+ pmask = ~pat[i - 1];
|
||
+
|
||
+ chr[i ] &= pmask;
|
||
+ chr[16 + i] &= pmask;
|
||
+ chr[32 + i] &= pmask;
|
||
+ chr[48 + i] &= pmask;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ chr[i ] |= mask;
|
||
+ chr[16 + i] |= mask;
|
||
+ chr[32 + i] |= mask;
|
||
+ chr[48 + i] |= mask;
|
||
+
|
||
+ offset += 80;
|
||
+ }
|
||
+ else {
|
||
+ chr[i ] = mask;
|
||
+ chr[16 + i] = mask;
|
||
+ chr[32 + i] = mask;
|
||
+ chr[48 + i] = mask;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else {
|
||
+ MapMask(15);
|
||
+ ptr = mem;
|
||
+ for (i = 0; i < 16; i++, ptr += 80) {
|
||
+ cursorBuf[i] = pat[i];
|
||
+ *ptr = ~pat[i];
|
||
+ }
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ offset = 0;
|
||
+ for (i = 1; i < 16; i <<= 1, offset += 16) {
|
||
+ int j;
|
||
+
|
||
+ MapMask(i);
|
||
+ ptr = mem;
|
||
+ for (j = 0; j < 16; j++, ptr += 80)
|
||
+ *ptr = chr[j + offset];
|
||
+ }
|
||
+
|
||
+ MapMask(15);
|
||
+}
|
||
+
|
||
+int grub_file_exists(char *s) {
|
||
+ if (!grub_open(s))
|
||
+ return 0;
|
||
+ grub_close();
|
||
+ return 1;
|
||
+}
|
||
+
|
||
+#endif /* SUPPORT_GRAPHICS */
|
||
diff -Nur grub-0.97/stage2/graphics.h grub-0.97-patched/stage2/graphics.h
|
||
--- grub-0.97/stage2/graphics.h 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/graphics.h 2012-11-11 17:06:33.321470879 +0100
|
||
@@ -0,0 +1,45 @@
|
||
+/* graphics.h - graphics console interface */
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 2002 Free Software Foundation, Inc.
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License as published by
|
||
+ * the Free Software Foundation; either version 2 of the License, or
|
||
+ * (at your option) any later version.
|
||
+ *
|
||
+ * This program is distributed in the hope that it will be useful,
|
||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ * GNU General Public License for more details.
|
||
+ *
|
||
+ * You should have received a copy of the GNU General Public License
|
||
+ * along with this program; if not, write to the Free Software
|
||
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
+ */
|
||
+
|
||
+#ifndef GRAPHICS_H
|
||
+#define GRAPHICS_H
|
||
+
|
||
+/* magic constant */
|
||
+#define VIDEOMEM 0xA0000
|
||
+
|
||
+/* function prototypes */
|
||
+char *graphics_get_splash(void);
|
||
+
|
||
+int read_image(char *s);
|
||
+void graphics_cursor(int set);
|
||
+
|
||
+/* function prototypes for asm functions */
|
||
+void * graphics_get_font();
|
||
+void graphics_set_palette(int idx, int red, int green, int blue);
|
||
+void set_int1c_handler();
|
||
+void unset_int1c_handler();
|
||
+
|
||
+/* Only to check for safe opening before we start */
|
||
+int grub_file_exists(char *s);
|
||
+
|
||
+extern short cursorX, cursorY;
|
||
+extern char cursorBuf[16];
|
||
+
|
||
+#endif /* GRAPHICS_H */
|
||
diff -Nur grub-0.97/stage2/iso9660.h grub-0.97-patched/stage2/iso9660.h
|
||
--- grub-0.97/stage2/iso9660.h 2004-03-27 17:02:38.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/iso9660.h 2012-11-11 17:07:12.740730013 +0100
|
||
@@ -73,11 +73,11 @@
|
||
|
||
typedef struct __iso_16bit {
|
||
u_int16_t l, b;
|
||
-} iso_16bit_t __attribute__ ((packed));
|
||
+} iso_16bit_t;
|
||
|
||
typedef struct __iso_32bit {
|
||
u_int32_t l, b;
|
||
-} iso_32bit_t __attribute__ ((packed));
|
||
+} iso_32bit_t;
|
||
|
||
typedef u_int8_t iso_date_t[7];
|
||
|
||
diff -Nur grub-0.97/stage2/Makefile.am grub-0.97-patched/stage2/Makefile.am
|
||
--- grub-0.97/stage2/Makefile.am 2005-02-02 21:37:35.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/Makefile.am 2012-11-11 17:07:12.747730236 +0100
|
||
@@ -7,7 +7,7 @@
|
||
fat.h filesys.h freebsd.h fs.h hercules.h i386-elf.h \
|
||
imgact_aout.h iso9660.h jfs.h mb_header.h mb_info.h md5.h \
|
||
nbi.h pc_slice.h serial.h shared.h smp-imps.h term.h \
|
||
- terminfo.h tparm.h nbi.h ufs2.h vstafs.h xfs.h
|
||
+ terminfo.h tparm.h nbi.h ufs2.h vstafs.h xfs.h graphics.h
|
||
EXTRA_DIST = setjmp.S apm.S $(noinst_SCRIPTS)
|
||
|
||
# For <stage1.h>.
|
||
@@ -19,20 +19,20 @@
|
||
disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \
|
||
fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \
|
||
fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \
|
||
- terminfo.c tparm.c
|
||
-libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \
|
||
+ terminfo.c tparm.c graphics.c
|
||
+libgrub_a_CFLAGS = $(GRUB_CFLAGS) -fno-stack-protector -I$(top_srcdir)/lib \
|
||
-DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
|
||
-DFSYS_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \
|
||
-DFSYS_UFS2=1 -DFSYS_VSTAFS=1 -DFSYS_XFS=1 \
|
||
-DUSE_MD5_PASSWORDS=1 -DSUPPORT_SERIAL=1 -DSUPPORT_HERCULES=1
|
||
|
||
# Stage 2 and Stage 1.5's.
|
||
-pkglibdir = $(libdir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
|
||
+stagedir = $(libdir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
|
||
|
||
EXTRA_PROGRAMS = nbloader.exec pxeloader.exec diskless.exec
|
||
|
||
if DISKLESS_SUPPORT
|
||
-pkglib_DATA = stage2 stage2_eltorito e2fs_stage1_5 fat_stage1_5 \
|
||
+stage_DATA = stage2 stage2_eltorito e2fs_stage1_5 fat_stage1_5 \
|
||
ffs_stage1_5 iso9660_stage1_5 jfs_stage1_5 minix_stage1_5 \
|
||
reiserfs_stage1_5 ufs2_stage1_5 vstafs_stage1_5 xfs_stage1_5 \
|
||
nbgrub pxegrub
|
||
@@ -43,7 +43,7 @@
|
||
reiserfs_stage1_5.exec ufs2_stage1_5.exec vstafs_stage1_5.exec \
|
||
xfs_stage1_5.exec nbloader.exec pxeloader.exec diskless.exec
|
||
else
|
||
-pkglib_DATA = stage2 stage2_eltorito e2fs_stage1_5 fat_stage1_5 \
|
||
+stage_DATA = stage2 stage2_eltorito e2fs_stage1_5 fat_stage1_5 \
|
||
ffs_stage1_5 iso9660_stage1_5 jfs_stage1_5 minix_stage1_5 \
|
||
reiserfs_stage1_5 ufs2_stage1_5 vstafs_stage1_5 xfs_stage1_5
|
||
noinst_DATA = pre_stage2 start start_eltorito
|
||
@@ -79,8 +79,14 @@
|
||
HERCULES_FLAGS =
|
||
endif
|
||
|
||
-STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
|
||
- $(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS)
|
||
+if GRAPHICS_SUPPORT
|
||
+GRAPHICS_FLAGS = -DSUPPORT_GRAPHICS=1
|
||
+else
|
||
+GRAPHICS_FLAGS =
|
||
+endif
|
||
+
|
||
+STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-reorder-functions -fno-builtin -nostdinc \
|
||
+ $(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS) $(GRAPHICS_FLAGS)
|
||
|
||
STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000
|
||
STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1
|
||
@@ -90,7 +96,8 @@
|
||
cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \
|
||
fsys_fat.c fsys_ffs.c fsys_iso9660.c fsys_jfs.c fsys_minix.c \
|
||
fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c gunzip.c \
|
||
- hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c
|
||
+ hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c \
|
||
+ graphics.c
|
||
pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
|
||
pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
|
||
pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK)
|
||
@@ -105,7 +112,7 @@
|
||
BUILT_SOURCES = stage2_size.h
|
||
endif
|
||
|
||
-CLEANFILES = $(pkglib_DATA) $(noinst_DATA) $(BUILT_SOURCES)
|
||
+CLEANFILES = $(stage_DATA) $(noinst_DATA) $(BUILT_SOURCES)
|
||
|
||
stage2_size.h: pre_stage2
|
||
-rm -f stage2_size.h
|
||
diff -Nur grub-0.97/stage2/Makefile.am.orig grub-0.97-patched/stage2/Makefile.am.orig
|
||
--- grub-0.97/stage2/Makefile.am.orig 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/Makefile.am.orig 2005-02-02 21:37:35.000000000 +0100
|
||
@@ -0,0 +1,272 @@
|
||
+# For test target.
|
||
+TESTS = size_test
|
||
+noinst_SCRIPTS = $(TESTS)
|
||
+
|
||
+# For dist target.
|
||
+noinst_HEADERS = apic.h defs.h dir.h disk_inode.h disk_inode_ffs.h \
|
||
+ fat.h filesys.h freebsd.h fs.h hercules.h i386-elf.h \
|
||
+ imgact_aout.h iso9660.h jfs.h mb_header.h mb_info.h md5.h \
|
||
+ nbi.h pc_slice.h serial.h shared.h smp-imps.h term.h \
|
||
+ terminfo.h tparm.h nbi.h ufs2.h vstafs.h xfs.h
|
||
+EXTRA_DIST = setjmp.S apm.S $(noinst_SCRIPTS)
|
||
+
|
||
+# For <stage1.h>.
|
||
+INCLUDES = -I$(top_srcdir)/stage1
|
||
+
|
||
+# The library for /sbin/grub.
|
||
+noinst_LIBRARIES = libgrub.a
|
||
+libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
|
||
+ disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \
|
||
+ fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \
|
||
+ fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \
|
||
+ terminfo.c tparm.c
|
||
+libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \
|
||
+ -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
|
||
+ -DFSYS_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \
|
||
+ -DFSYS_UFS2=1 -DFSYS_VSTAFS=1 -DFSYS_XFS=1 \
|
||
+ -DUSE_MD5_PASSWORDS=1 -DSUPPORT_SERIAL=1 -DSUPPORT_HERCULES=1
|
||
+
|
||
+# Stage 2 and Stage 1.5's.
|
||
+pkglibdir = $(libdir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
|
||
+
|
||
+EXTRA_PROGRAMS = nbloader.exec pxeloader.exec diskless.exec
|
||
+
|
||
+if DISKLESS_SUPPORT
|
||
+pkglib_DATA = stage2 stage2_eltorito e2fs_stage1_5 fat_stage1_5 \
|
||
+ ffs_stage1_5 iso9660_stage1_5 jfs_stage1_5 minix_stage1_5 \
|
||
+ reiserfs_stage1_5 ufs2_stage1_5 vstafs_stage1_5 xfs_stage1_5 \
|
||
+ nbgrub pxegrub
|
||
+noinst_DATA = pre_stage2 start start_eltorito nbloader pxeloader diskless
|
||
+noinst_PROGRAMS = pre_stage2.exec start.exec start_eltorito.exec \
|
||
+ e2fs_stage1_5.exec fat_stage1_5.exec ffs_stage1_5.exec \
|
||
+ iso9660_stage1_5.exec jfs_stage1_5.exec minix_stage1_5.exec \
|
||
+ reiserfs_stage1_5.exec ufs2_stage1_5.exec vstafs_stage1_5.exec \
|
||
+ xfs_stage1_5.exec nbloader.exec pxeloader.exec diskless.exec
|
||
+else
|
||
+pkglib_DATA = stage2 stage2_eltorito e2fs_stage1_5 fat_stage1_5 \
|
||
+ ffs_stage1_5 iso9660_stage1_5 jfs_stage1_5 minix_stage1_5 \
|
||
+ reiserfs_stage1_5 ufs2_stage1_5 vstafs_stage1_5 xfs_stage1_5
|
||
+noinst_DATA = pre_stage2 start start_eltorito
|
||
+noinst_PROGRAMS = pre_stage2.exec start.exec start_eltorito.exec \
|
||
+ e2fs_stage1_5.exec fat_stage1_5.exec ffs_stage1_5.exec \
|
||
+ iso9660_stage1_5.exec jfs_stage1_5.exec minix_stage1_5.exec \
|
||
+ reiserfs_stage1_5.exec ufs2_stage1_5.exec vstafs_stage1_5.exec \
|
||
+ xfs_stage1_5.exec
|
||
+endif
|
||
+MOSTLYCLEANFILES = $(noinst_PROGRAMS)
|
||
+
|
||
+PRE_STAGE2_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,8200
|
||
+START_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,8000
|
||
+NBLOADER_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,0
|
||
+PXELOADER_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
|
||
+START_ELTORITO_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
|
||
+
|
||
+if NETBOOT_SUPPORT
|
||
+NETBOOT_FLAGS = -I$(top_srcdir)/netboot -DSUPPORT_NETBOOT=1
|
||
+else
|
||
+NETBOOT_FLAGS =
|
||
+endif
|
||
+
|
||
+if SERIAL_SUPPORT
|
||
+SERIAL_FLAGS = -DSUPPORT_SERIAL=1
|
||
+else
|
||
+SERIAL_FLAGS =
|
||
+endif
|
||
+
|
||
+if HERCULES_SUPPORT
|
||
+HERCULES_FLAGS = -DSUPPORT_HERCULES=1
|
||
+else
|
||
+HERCULES_FLAGS =
|
||
+endif
|
||
+
|
||
+STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
|
||
+ $(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS)
|
||
+
|
||
+STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000
|
||
+STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1
|
||
+
|
||
+# For stage2 target.
|
||
+pre_stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c char_io.c \
|
||
+ cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \
|
||
+ fsys_fat.c fsys_ffs.c fsys_iso9660.c fsys_jfs.c fsys_minix.c \
|
||
+ fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c gunzip.c \
|
||
+ hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c
|
||
+pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
|
||
+pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
|
||
+pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK)
|
||
+
|
||
+if NETBOOT_SUPPORT
|
||
+pre_stage2_exec_LDADD = ../netboot/libdrivers.a
|
||
+endif
|
||
+
|
||
+if DISKLESS_SUPPORT
|
||
+BUILT_SOURCES = stage2_size.h diskless_size.h
|
||
+else
|
||
+BUILT_SOURCES = stage2_size.h
|
||
+endif
|
||
+
|
||
+CLEANFILES = $(pkglib_DATA) $(noinst_DATA) $(BUILT_SOURCES)
|
||
+
|
||
+stage2_size.h: pre_stage2
|
||
+ -rm -f stage2_size.h
|
||
+ set dummy `ls -l pre_stage2`; \
|
||
+ echo "#define STAGE2_SIZE $$6" > stage2_size.h
|
||
+
|
||
+start_exec_SOURCES = start.S
|
||
+start_exec_CCASFLAGS = $(STAGE2_COMPILE)
|
||
+start_exec_LDFLAGS = $(START_LINK)
|
||
+
|
||
+# XXX: automake doesn't provide a way to specify dependencies for object
|
||
+# files explicitly, so we must write this by a general Makefile scheme.
|
||
+# If automake change the naming scheme for per-executable objects, this
|
||
+# will be broken.
|
||
+start_exec-start.$(OBJEXT): stage2_size.h
|
||
+
|
||
+stage2: pre_stage2 start
|
||
+ -rm -f stage2
|
||
+ cat start pre_stage2 > stage2
|
||
+
|
||
+start_eltorito_exec_SOURCES = start_eltorito.S
|
||
+start_eltorito_exec_CCASFLAGS = $(STAGE2_COMPILE)
|
||
+start_eltorito_exec_LDFLAGS = $(START_ELTORITO_LINK)
|
||
+
|
||
+start_eltorito_exec-start.$(OBJEXT): stage2_size.h
|
||
+
|
||
+stage2_eltorito: pre_stage2 start_eltorito
|
||
+ -rm -f stage2_eltorito
|
||
+ cat start_eltorito pre_stage2 > stage2_eltorito
|
||
+
|
||
+# For e2fs_stage1_5 target.
|
||
+e2fs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
|
||
+ stage1_5.c fsys_ext2fs.c bios.c
|
||
+e2fs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+e2fs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+e2fs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For fat_stage1_5 target.
|
||
+fat_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
|
||
+ stage1_5.c fsys_fat.c bios.c
|
||
+fat_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+fat_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+fat_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For ffs_stage1_5 target.
|
||
+ffs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
|
||
+ stage1_5.c fsys_ffs.c bios.c
|
||
+ffs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+ffs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+ffs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For ufs2_stage1_5 target.
|
||
+ufs2_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
|
||
+ stage1_5.c fsys_ufs2.c bios.c
|
||
+ufs2_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_UFS2=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+ufs2_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_UFS2=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+ufs2_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For minix_stage1_5 target.
|
||
+minix_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
|
||
+ stage1_5.c fsys_minix.c bios.c
|
||
+minix_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+minix_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+minix_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For reiserfs_stage1_5 target.
|
||
+reiserfs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
|
||
+ disk_io.c stage1_5.c fsys_reiserfs.c bios.c
|
||
+reiserfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+reiserfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+reiserfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For vstafs_stage1_5 target.
|
||
+vstafs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
|
||
+ disk_io.c stage1_5.c fsys_vstafs.c bios.c
|
||
+vstafs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+vstafs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+vstafs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For jfs_stage1_5 target.
|
||
+jfs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
|
||
+ disk_io.c stage1_5.c fsys_jfs.c bios.c
|
||
+jfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+jfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+jfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For xfs_stage1_5 target.
|
||
+xfs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
|
||
+ disk_io.c stage1_5.c fsys_xfs.c bios.c
|
||
+xfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+xfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+xfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For iso9660_stage1_5 target.
|
||
+iso9660_stage1_5_exec_SOURCES = start_eltorito.S asm.S common.c char_io.c \
|
||
+ disk_io.c stage1_5.c fsys_iso9660.c bios.c
|
||
+iso9660_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_ISO9660=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+iso9660_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_ISO9660=1 \
|
||
+ -DNO_BLOCK_FILES=1
|
||
+iso9660_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
|
||
+
|
||
+# For diskless target.
|
||
+diskless_exec_SOURCES = $(pre_stage2_exec_SOURCES)
|
||
+diskless_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \
|
||
+ -DSUPPORT_DISKLESS=1
|
||
+diskless_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \
|
||
+ -DSUPPORT_DISKLESS=1
|
||
+diskless_exec_LDFLAGS = $(PRE_STAGE2_LINK)
|
||
+diskless_exec_LDADD = ../netboot/libdrivers.a
|
||
+
|
||
+diskless_size.h: diskless
|
||
+ -rm -f $@
|
||
+ set dummy `ls -l $^`; \
|
||
+ echo "#define DISKLESS_SIZE $$6" > $@
|
||
+
|
||
+# For nbloader target.
|
||
+nbloader_exec_SOURCES = nbloader.S
|
||
+nbloader_exec_CCASFLAGS = $(STAGE2_COMPILE)
|
||
+nbloader_exec_LDFLAGS = $(NBLOADER_LINK)
|
||
+
|
||
+# XXX: See the comment for start_exec-start.o.
|
||
+nbloader_exec-nbloader.$(OBJEXT): diskless_size.h
|
||
+
|
||
+# For nbgrub target.
|
||
+nbgrub: nbloader diskless
|
||
+ -rm -f $@
|
||
+ cat $^ > $@
|
||
+
|
||
+# For pxeloader target.
|
||
+pxeloader_exec_SOURCES = pxeloader.S
|
||
+pxeloader_exec_CCASFLAGS = $(STAGE2_COMPILE)
|
||
+pxeloader_exec_LDFLAGS = $(PXELOADER_LINK)
|
||
+
|
||
+# XXX: See the comment for start_exec-start.o.
|
||
+pxeloader_exec-pxeloader.$(OBJEXT): diskless_size.h
|
||
+
|
||
+# For pxegrub target.
|
||
+pxegrub: pxeloader diskless
|
||
+ -rm -f $@
|
||
+ cat $^ > $@
|
||
+
|
||
+# General rule for making a raw binary.
|
||
+SUFFIXES = .exec
|
||
+.exec:
|
||
+ $(OBJCOPY) -O binary $< $@
|
||
diff -Nur grub-0.97/stage2/pc_slice.h grub-0.97-patched/stage2/pc_slice.h
|
||
--- grub-0.97/stage2/pc_slice.h 2003-07-09 13:45:53.000000000 +0200
|
||
+++ grub-0.97-patched/stage2/pc_slice.h 2012-11-11 17:07:12.698728671 +0100
|
||
@@ -115,6 +115,7 @@
|
||
#define PC_SLICE_TYPE_LINUX_EXTENDED 0x85
|
||
#define PC_SLICE_TYPE_VSTAFS 0x9e
|
||
#define PC_SLICE_TYPE_DELL_UTIL 0xde
|
||
+#define PC_SLICE_TYPE_GPT 0xee
|
||
#define PC_SLICE_TYPE_LINUX_RAID 0xfd
|
||
|
||
|
||
diff -Nur grub-0.97/stage2/shared.h grub-0.97-patched/stage2/shared.h
|
||
--- grub-0.97/stage2/shared.h 2004-06-19 18:40:09.000000000 +0200
|
||
+++ grub-0.97-patched/stage2/shared.h 2012-11-11 17:07:12.741730044 +0100
|
||
@@ -36,8 +36,8 @@
|
||
|
||
/* Maybe redirect memory requests through grub_scratch_mem. */
|
||
#ifdef GRUB_UTIL
|
||
-extern char *grub_scratch_mem;
|
||
-# define RAW_ADDR(x) ((x) + (int) grub_scratch_mem)
|
||
+extern void *grub_scratch_mem;
|
||
+# define RAW_ADDR(x) ((x) + (unsigned long) grub_scratch_mem)
|
||
# define RAW_SEG(x) (RAW_ADDR ((x) << 4) >> 4)
|
||
#else
|
||
# define RAW_ADDR(x) (x)
|
||
@@ -161,7 +161,9 @@
|
||
|
||
#define LINUX_CL_OFFSET 0x9000
|
||
#define LINUX_CL_END_OFFSET 0x90FF
|
||
-#define LINUX_SETUP_MOVE_SIZE 0x9100
|
||
+#define LINUX_CL_0202_PRM_OFFSET 0x9500
|
||
+#define LINUX_CL_0202_PRM_END_OFFSET 0x9FFF
|
||
+#define LINUX_SETUP_MOVE_SIZE 0xA000
|
||
#define LINUX_CL_MAGIC 0xA33F
|
||
|
||
/*
|
||
@@ -499,7 +501,11 @@
|
||
unsigned char linear_reserved_field_position;
|
||
unsigned long max_pixel_clock;
|
||
|
||
- unsigned char reserved3[189];
|
||
+ /* Reserved field to make structure to be 256 bytes long, VESA BIOS
|
||
+ Extension 3.0 Specification says to reserve 189 bytes here but
|
||
+ that doesn't make structure to be 256 bytes. So additional one is
|
||
+ added here. */
|
||
+ unsigned char reserved3[189 + 1];
|
||
} __attribute__ ((packed));
|
||
|
||
|
||
@@ -807,7 +813,7 @@
|
||
/* Low-level disk I/O */
|
||
int get_diskinfo (int drive, struct geometry *geometry);
|
||
int biosdisk (int subfunc, int drive, struct geometry *geometry,
|
||
- int sector, int nsec, int segment);
|
||
+ unsigned int sector, int nsec, int segment);
|
||
void stop_floppy (void);
|
||
|
||
/* Command-line interface functions. */
|
||
@@ -871,6 +877,7 @@
|
||
int grub_tolower (int c);
|
||
int grub_isspace (int c);
|
||
int grub_strncat (char *s1, const char *s2, int n);
|
||
+void grub_memcpy(void *dest, const void *src, int len);
|
||
void *grub_memmove (void *to, const void *from, int len);
|
||
void *grub_memset (void *start, int c, int len);
|
||
int grub_strncat (char *s1, const char *s2, int n);
|
||
@@ -911,7 +918,7 @@
|
||
int nul_terminate (char *str);
|
||
int get_based_digit (int c, int base);
|
||
int safe_parse_maxint (char **str_ptr, int *myint_ptr);
|
||
-int memcheck (int start, int len);
|
||
+int memcheck (unsigned long start, unsigned long len);
|
||
void grub_putstr (const char *str);
|
||
|
||
#ifndef NO_DECOMPRESSION
|
||
@@ -920,10 +927,10 @@
|
||
int gunzip_read (char *buf, int len);
|
||
#endif /* NO_DECOMPRESSION */
|
||
|
||
-int rawread (int drive, int sector, int byte_offset, int byte_len, char *buf);
|
||
-int devread (int sector, int byte_offset, int byte_len, char *buf);
|
||
-int rawwrite (int drive, int sector, char *buf);
|
||
-int devwrite (int sector, int sector_len, char *buf);
|
||
+int rawread (int drive, unsigned int sector, int byte_offset, int byte_len, char *buf);
|
||
+int devread (unsigned int sector, int byte_offset, int byte_len, char *buf);
|
||
+int rawwrite (int drive, unsigned int sector, char *buf);
|
||
+int devwrite (unsigned int sector, int sector_len, char *buf);
|
||
|
||
/* Parse a device string and initialize the global parameters. */
|
||
char *set_device (char *device);
|
||
@@ -934,7 +941,9 @@
|
||
unsigned long *partition, int *type,
|
||
unsigned long *start, unsigned long *len,
|
||
unsigned long *offset, int *entry,
|
||
- unsigned long *ext_offset, char *buf);
|
||
+ unsigned long *ext_offset,
|
||
+ unsigned long *gpt_offset, int *gpt_count,
|
||
+ int *gpt_size, char *buf);
|
||
|
||
/* Sets device to the one represented by the SAVED_* parameters. */
|
||
int make_saved_active (void);
|
||
diff -Nur grub-0.97/stage2/size_test grub-0.97-patched/stage2/size_test
|
||
--- grub-0.97/stage2/size_test 2004-05-14 21:30:52.000000000 +0200
|
||
+++ grub-0.97-patched/stage2/size_test 2012-11-11 17:06:52.554085177 +0100
|
||
@@ -36,9 +36,9 @@
|
||
}
|
||
|
||
# The bootloader area of a FFS partition is 14 sectors.
|
||
-check ffs_stage1_5 7168
|
||
-
|
||
-check ufs2_stage1_5 7168
|
||
+#check ffs_stage1_5 7168
|
||
+#
|
||
+#check ufs2_stage1_5 7168
|
||
|
||
# Stage 1.5 can be installed in the sectors immediately after MBR in the
|
||
# first cylinder, so the size is (63 - 1) sectors.
|
||
diff -Nur grub-0.97/stage2/stage2.c grub-0.97-patched/stage2/stage2.c
|
||
--- grub-0.97/stage2/stage2.c 2005-03-19 18:51:57.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/stage2.c 2012-11-11 17:07:12.742730076 +0100
|
||
@@ -233,6 +233,7 @@
|
||
{
|
||
int c, time1, time2 = -1, first_entry = 0;
|
||
char *cur_entry = 0;
|
||
+ struct term_entry *prev_term = NULL;
|
||
|
||
/*
|
||
* Main loop for menu UI.
|
||
@@ -651,7 +652,10 @@
|
||
*(new_heap++) = 0;
|
||
|
||
if (config_entries)
|
||
- run_menu (heap, NULL, new_num_entries, new_heap, 0);
|
||
+ {
|
||
+ current_entryno = first_entry + entryno;
|
||
+ run_menu (heap, NULL, new_num_entries, new_heap, 0);
|
||
+ }
|
||
else
|
||
{
|
||
cls ();
|
||
@@ -714,6 +718,15 @@
|
||
|
||
cls ();
|
||
setcursor (1);
|
||
+ /* if our terminal needed initialization, we should shut it down
|
||
+ * before booting the kernel, but we want to save what it was so
|
||
+ * we can come back if needed */
|
||
+ prev_term = current_term;
|
||
+ if (current_term->shutdown)
|
||
+ {
|
||
+ (*current_term->shutdown)();
|
||
+ current_term = term_table; /* assumption: console is first */
|
||
+ }
|
||
|
||
while (1)
|
||
{
|
||
@@ -727,7 +740,8 @@
|
||
cur_entry = get_entry (config_entries, first_entry + entryno, 1);
|
||
|
||
/* Set CURRENT_ENTRYNO for the command "savedefault". */
|
||
- current_entryno = first_entry + entryno;
|
||
+ if (config_entries)
|
||
+ current_entryno = first_entry + entryno;
|
||
|
||
if (run_script (cur_entry, heap))
|
||
{
|
||
@@ -748,6 +762,13 @@
|
||
break;
|
||
}
|
||
|
||
+ /* if we get back here, we should go back to what our term was before */
|
||
+ current_term = prev_term;
|
||
+ if (current_term->startup)
|
||
+ /* if our terminal fails to initialize, fall back to console since
|
||
+ * it should always work */
|
||
+ if ((*current_term->startup)() == 0)
|
||
+ current_term = term_table; /* we know that console is first */
|
||
show_menu = 1;
|
||
goto restart;
|
||
}
|
||
@@ -1050,6 +1071,10 @@
|
||
while (is_preset);
|
||
}
|
||
|
||
+ /* go ahead and make sure the terminal is setup */
|
||
+ if (current_term->startup)
|
||
+ (*current_term->startup)();
|
||
+
|
||
if (! num_entries)
|
||
{
|
||
/* If no acceptable config file, goto command-line, starting
|
||
diff -Nur grub-0.97/stage2/stage2.c.orig grub-0.97-patched/stage2/stage2.c.orig
|
||
--- grub-0.97/stage2/stage2.c.orig 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/stage2/stage2.c.orig 2005-03-19 18:51:57.000000000 +0100
|
||
@@ -0,0 +1,1067 @@
|
||
+/*
|
||
+ * GRUB -- GRand Unified Bootloader
|
||
+ * Copyright (C) 2000,2001,2002,2004,2005 Free Software Foundation, Inc.
|
||
+ *
|
||
+ * This program is free software; you can redistribute it and/or modify
|
||
+ * it under the terms of the GNU General Public License as published by
|
||
+ * the Free Software Foundation; either version 2 of the License, or
|
||
+ * (at your option) any later version.
|
||
+ *
|
||
+ * This program is distributed in the hope that it will be useful,
|
||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+ * GNU General Public License for more details.
|
||
+ *
|
||
+ * You should have received a copy of the GNU General Public License
|
||
+ * along with this program; if not, write to the Free Software
|
||
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
+ */
|
||
+
|
||
+#include <shared.h>
|
||
+#include <term.h>
|
||
+
|
||
+grub_jmp_buf restart_env;
|
||
+
|
||
+#if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS)
|
||
+
|
||
+# if defined(PRESET_MENU_STRING)
|
||
+static const char *preset_menu = PRESET_MENU_STRING;
|
||
+# elif defined(SUPPORT_DISKLESS)
|
||
+/* Execute the command "bootp" automatically. */
|
||
+static const char *preset_menu = "bootp\n";
|
||
+# endif /* SUPPORT_DISKLESS */
|
||
+
|
||
+static int preset_menu_offset;
|
||
+
|
||
+static int
|
||
+open_preset_menu (void)
|
||
+{
|
||
+#ifdef GRUB_UTIL
|
||
+ /* Unless the user explicitly requests to use the preset menu,
|
||
+ always opening the preset menu fails in the grub shell. */
|
||
+ if (! use_preset_menu)
|
||
+ return 0;
|
||
+#endif /* GRUB_UTIL */
|
||
+
|
||
+ preset_menu_offset = 0;
|
||
+ return preset_menu != 0;
|
||
+}
|
||
+
|
||
+static int
|
||
+read_from_preset_menu (char *buf, int maxlen)
|
||
+{
|
||
+ int len = grub_strlen (preset_menu + preset_menu_offset);
|
||
+
|
||
+ if (len > maxlen)
|
||
+ len = maxlen;
|
||
+
|
||
+ grub_memmove (buf, preset_menu + preset_menu_offset, len);
|
||
+ preset_menu_offset += len;
|
||
+
|
||
+ return len;
|
||
+}
|
||
+
|
||
+static void
|
||
+close_preset_menu (void)
|
||
+{
|
||
+ /* Disable the preset menu. */
|
||
+ preset_menu = 0;
|
||
+}
|
||
+
|
||
+#else /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */
|
||
+
|
||
+#define open_preset_menu() 0
|
||
+#define read_from_preset_menu(buf, maxlen) 0
|
||
+#define close_preset_menu()
|
||
+
|
||
+#endif /* ! PRESET_MENU_STRING && ! SUPPORT_DISKLESS */
|
||
+
|
||
+static char *
|
||
+get_entry (char *list, int num, int nested)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ for (i = 0; i < num; i++)
|
||
+ {
|
||
+ do
|
||
+ {
|
||
+ while (*(list++));
|
||
+ }
|
||
+ while (nested && *(list++));
|
||
+ }
|
||
+
|
||
+ return list;
|
||
+}
|
||
+
|
||
+/* Print an entry in a line of the menu box. */
|
||
+static void
|
||
+print_entry (int y, int highlight, char *entry)
|
||
+{
|
||
+ int x;
|
||
+
|
||
+ if (current_term->setcolorstate)
|
||
+ current_term->setcolorstate (COLOR_STATE_NORMAL);
|
||
+
|
||
+ if (highlight && current_term->setcolorstate)
|
||
+ current_term->setcolorstate (COLOR_STATE_HIGHLIGHT);
|
||
+
|
||
+ gotoxy (2, y);
|
||
+ grub_putchar (' ');
|
||
+ for (x = 3; x < 75; x++)
|
||
+ {
|
||
+ if (*entry && x <= 72)
|
||
+ {
|
||
+ if (x == 72)
|
||
+ grub_putchar (DISP_RIGHT);
|
||
+ else
|
||
+ grub_putchar (*entry++);
|
||
+ }
|
||
+ else
|
||
+ grub_putchar (' ');
|
||
+ }
|
||
+ gotoxy (74, y);
|
||
+
|
||
+ if (current_term->setcolorstate)
|
||
+ current_term->setcolorstate (COLOR_STATE_STANDARD);
|
||
+}
|
||
+
|
||
+/* Print entries in the menu box. */
|
||
+static void
|
||
+print_entries (int y, int size, int first, int entryno, char *menu_entries)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ gotoxy (77, y + 1);
|
||
+
|
||
+ if (first)
|
||
+ grub_putchar (DISP_UP);
|
||
+ else
|
||
+ grub_putchar (' ');
|
||
+
|
||
+ menu_entries = get_entry (menu_entries, first, 0);
|
||
+
|
||
+ for (i = 0; i < size; i++)
|
||
+ {
|
||
+ print_entry (y + i + 1, entryno == i, menu_entries);
|
||
+
|
||
+ while (*menu_entries)
|
||
+ menu_entries++;
|
||
+
|
||
+ if (*(menu_entries - 1))
|
||
+ menu_entries++;
|
||
+ }
|
||
+
|
||
+ gotoxy (77, y + size);
|
||
+
|
||
+ if (*menu_entries)
|
||
+ grub_putchar (DISP_DOWN);
|
||
+ else
|
||
+ grub_putchar (' ');
|
||
+
|
||
+ gotoxy (74, y + entryno + 1);
|
||
+}
|
||
+
|
||
+static void
|
||
+print_entries_raw (int size, int first, char *menu_entries)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+#define LINE_LENGTH 67
|
||
+
|
||
+ for (i = 0; i < LINE_LENGTH; i++)
|
||
+ grub_putchar ('-');
|
||
+ grub_putchar ('\n');
|
||
+
|
||
+ for (i = first; i < size; i++)
|
||
+ {
|
||
+ /* grub's printf can't %02d so ... */
|
||
+ if (i < 10)
|
||
+ grub_putchar (' ');
|
||
+ grub_printf ("%d: %s\n", i, get_entry (menu_entries, i, 0));
|
||
+ }
|
||
+
|
||
+ for (i = 0; i < LINE_LENGTH; i++)
|
||
+ grub_putchar ('-');
|
||
+ grub_putchar ('\n');
|
||
+
|
||
+#undef LINE_LENGTH
|
||
+}
|
||
+
|
||
+
|
||
+static void
|
||
+print_border (int y, int size)
|
||
+{
|
||
+ int i;
|
||
+
|
||
+ if (current_term->setcolorstate)
|
||
+ current_term->setcolorstate (COLOR_STATE_NORMAL);
|
||
+
|
||
+ gotoxy (1, y);
|
||
+
|
||
+ grub_putchar (DISP_UL);
|
||
+ for (i = 0; i < 73; i++)
|
||
+ grub_putchar (DISP_HORIZ);
|
||
+ grub_putchar (DISP_UR);
|
||
+
|
||
+ i = 1;
|
||
+ while (1)
|
||
+ {
|
||
+ gotoxy (1, y + i);
|
||
+
|
||
+ if (i > size)
|
||
+ break;
|
||
+
|
||
+ grub_putchar (DISP_VERT);
|
||
+ gotoxy (75, y + i);
|
||
+ grub_putchar (DISP_VERT);
|
||
+
|
||
+ i++;
|
||
+ }
|
||
+
|
||
+ grub_putchar (DISP_LL);
|
||
+ for (i = 0; i < 73; i++)
|
||
+ grub_putchar (DISP_HORIZ);
|
||
+ grub_putchar (DISP_LR);
|
||
+
|
||
+ if (current_term->setcolorstate)
|
||
+ current_term->setcolorstate (COLOR_STATE_STANDARD);
|
||
+}
|
||
+
|
||
+static void
|
||
+run_menu (char *menu_entries, char *config_entries, int num_entries,
|
||
+ char *heap, int entryno)
|
||
+{
|
||
+ int c, time1, time2 = -1, first_entry = 0;
|
||
+ char *cur_entry = 0;
|
||
+
|
||
+ /*
|
||
+ * Main loop for menu UI.
|
||
+ */
|
||
+
|
||
+restart:
|
||
+ /* Dumb terminal always use all entries for display
|
||
+ invariant for TERM_DUMB: first_entry == 0 */
|
||
+ if (! (current_term->flags & TERM_DUMB))
|
||
+ {
|
||
+ while (entryno > 11)
|
||
+ {
|
||
+ first_entry++;
|
||
+ entryno--;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* If the timeout was expired or wasn't set, force to show the menu
|
||
+ interface. */
|
||
+ if (grub_timeout < 0)
|
||
+ show_menu = 1;
|
||
+
|
||
+ /* If SHOW_MENU is false, don't display the menu until ESC is pressed. */
|
||
+ if (! show_menu)
|
||
+ {
|
||
+ /* Get current time. */
|
||
+ while ((time1 = getrtsecs ()) == 0xFF)
|
||
+ ;
|
||
+
|
||
+ while (1)
|
||
+ {
|
||
+ /* Check if ESC is pressed. */
|
||
+ if (checkkey () != -1 && ASCII_CHAR (getkey ()) == '\e')
|
||
+ {
|
||
+ grub_timeout = -1;
|
||
+ show_menu = 1;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* If GRUB_TIMEOUT is expired, boot the default entry. */
|
||
+ if (grub_timeout >=0
|
||
+ && (time1 = getrtsecs ()) != time2
|
||
+ && time1 != 0xFF)
|
||
+ {
|
||
+ if (grub_timeout <= 0)
|
||
+ {
|
||
+ grub_timeout = -1;
|
||
+ goto boot_entry;
|
||
+ }
|
||
+
|
||
+ time2 = time1;
|
||
+ grub_timeout--;
|
||
+
|
||
+ /* Print a message. */
|
||
+ grub_printf ("\rPress `ESC' to enter the menu... %d ",
|
||
+ grub_timeout);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Only display the menu if the user wants to see it. */
|
||
+ if (show_menu)
|
||
+ {
|
||
+ init_page ();
|
||
+ setcursor (0);
|
||
+
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ print_entries_raw (num_entries, first_entry, menu_entries);
|
||
+ else
|
||
+ print_border (3, 12);
|
||
+
|
||
+ grub_printf ("\n\
|
||
+ Use the %c and %c keys to select which entry is highlighted.\n",
|
||
+ DISP_UP, DISP_DOWN);
|
||
+
|
||
+ if (! auth && password)
|
||
+ {
|
||
+ printf ("\
|
||
+ Press enter to boot the selected OS or \'p\' to enter a\n\
|
||
+ password to unlock the next set of features.");
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if (config_entries)
|
||
+ printf ("\
|
||
+ Press enter to boot the selected OS, \'e\' to edit the\n\
|
||
+ commands before booting, or \'c\' for a command-line.");
|
||
+ else
|
||
+ printf ("\
|
||
+ Press \'b\' to boot, \'e\' to edit the selected command in the\n\
|
||
+ boot sequence, \'c\' for a command-line, \'o\' to open a new line\n\
|
||
+ after (\'O\' for before) the selected line, \'d\' to remove the\n\
|
||
+ selected line, or escape to go back to the main menu.");
|
||
+ }
|
||
+
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ grub_printf ("\n\nThe selected entry is %d ", entryno);
|
||
+ else
|
||
+ print_entries (3, 12, first_entry, entryno, menu_entries);
|
||
+ }
|
||
+
|
||
+ /* XX using RT clock now, need to initialize value */
|
||
+ while ((time1 = getrtsecs()) == 0xFF);
|
||
+
|
||
+ while (1)
|
||
+ {
|
||
+ /* Initialize to NULL just in case... */
|
||
+ cur_entry = NULL;
|
||
+
|
||
+ if (grub_timeout >= 0 && (time1 = getrtsecs()) != time2 && time1 != 0xFF)
|
||
+ {
|
||
+ if (grub_timeout <= 0)
|
||
+ {
|
||
+ grub_timeout = -1;
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* else not booting yet! */
|
||
+ time2 = time1;
|
||
+
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ grub_printf ("\r Entry %d will be booted automatically in %d seconds. ",
|
||
+ entryno, grub_timeout);
|
||
+ else
|
||
+ {
|
||
+ gotoxy (3, 22);
|
||
+ grub_printf ("The highlighted entry will be booted automatically in %d seconds. ",
|
||
+ grub_timeout);
|
||
+ gotoxy (74, 4 + entryno);
|
||
+ }
|
||
+
|
||
+ grub_timeout--;
|
||
+ }
|
||
+
|
||
+ /* Check for a keypress, however if TIMEOUT has been expired
|
||
+ (GRUB_TIMEOUT == -1) relax in GETKEY even if no key has been
|
||
+ pressed.
|
||
+ This avoids polling (relevant in the grub-shell and later on
|
||
+ in grub if interrupt driven I/O is done). */
|
||
+ if (checkkey () >= 0 || grub_timeout < 0)
|
||
+ {
|
||
+ /* Key was pressed, show which entry is selected before GETKEY,
|
||
+ since we're comming in here also on GRUB_TIMEOUT == -1 and
|
||
+ hang in GETKEY */
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ grub_printf ("\r Highlighted entry is %d: ", entryno);
|
||
+
|
||
+ c = ASCII_CHAR (getkey ());
|
||
+
|
||
+ if (grub_timeout >= 0)
|
||
+ {
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ grub_putchar ('\r');
|
||
+ else
|
||
+ gotoxy (3, 22);
|
||
+ printf (" ");
|
||
+ grub_timeout = -1;
|
||
+ fallback_entryno = -1;
|
||
+ if (! (current_term->flags & TERM_DUMB))
|
||
+ gotoxy (74, 4 + entryno);
|
||
+ }
|
||
+
|
||
+ /* We told them above (at least in SUPPORT_SERIAL) to use
|
||
+ '^' or 'v' so accept these keys. */
|
||
+ if (c == 16 || c == '^')
|
||
+ {
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ {
|
||
+ if (entryno > 0)
|
||
+ entryno--;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if (entryno > 0)
|
||
+ {
|
||
+ print_entry (4 + entryno, 0,
|
||
+ get_entry (menu_entries,
|
||
+ first_entry + entryno,
|
||
+ 0));
|
||
+ entryno--;
|
||
+ print_entry (4 + entryno, 1,
|
||
+ get_entry (menu_entries,
|
||
+ first_entry + entryno,
|
||
+ 0));
|
||
+ }
|
||
+ else if (first_entry > 0)
|
||
+ {
|
||
+ first_entry--;
|
||
+ print_entries (3, 12, first_entry, entryno,
|
||
+ menu_entries);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else if ((c == 14 || c == 'v')
|
||
+ && first_entry + entryno + 1 < num_entries)
|
||
+ {
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ entryno++;
|
||
+ else
|
||
+ {
|
||
+ if (entryno < 11)
|
||
+ {
|
||
+ print_entry (4 + entryno, 0,
|
||
+ get_entry (menu_entries,
|
||
+ first_entry + entryno,
|
||
+ 0));
|
||
+ entryno++;
|
||
+ print_entry (4 + entryno, 1,
|
||
+ get_entry (menu_entries,
|
||
+ first_entry + entryno,
|
||
+ 0));
|
||
+ }
|
||
+ else if (num_entries > 12 + first_entry)
|
||
+ {
|
||
+ first_entry++;
|
||
+ print_entries (3, 12, first_entry, entryno, menu_entries);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else if (c == 7)
|
||
+ {
|
||
+ /* Page Up */
|
||
+ first_entry -= 12;
|
||
+ if (first_entry < 0)
|
||
+ {
|
||
+ entryno += first_entry;
|
||
+ first_entry = 0;
|
||
+ if (entryno < 0)
|
||
+ entryno = 0;
|
||
+ }
|
||
+ print_entries (3, 12, first_entry, entryno, menu_entries);
|
||
+ }
|
||
+ else if (c == 3)
|
||
+ {
|
||
+ /* Page Down */
|
||
+ first_entry += 12;
|
||
+ if (first_entry + entryno + 1 >= num_entries)
|
||
+ {
|
||
+ first_entry = num_entries - 12;
|
||
+ if (first_entry < 0)
|
||
+ first_entry = 0;
|
||
+ entryno = num_entries - first_entry - 1;
|
||
+ }
|
||
+ print_entries (3, 12, first_entry, entryno, menu_entries);
|
||
+ }
|
||
+
|
||
+ if (config_entries)
|
||
+ {
|
||
+ if ((c == '\n') || (c == '\r') || (c == 6))
|
||
+ break;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if ((c == 'd') || (c == 'o') || (c == 'O'))
|
||
+ {
|
||
+ if (! (current_term->flags & TERM_DUMB))
|
||
+ print_entry (4 + entryno, 0,
|
||
+ get_entry (menu_entries,
|
||
+ first_entry + entryno,
|
||
+ 0));
|
||
+
|
||
+ /* insert after is almost exactly like insert before */
|
||
+ if (c == 'o')
|
||
+ {
|
||
+ /* But `o' differs from `O', since it may causes
|
||
+ the menu screen to scroll up. */
|
||
+ if (entryno < 11 || (current_term->flags & TERM_DUMB))
|
||
+ entryno++;
|
||
+ else
|
||
+ first_entry++;
|
||
+
|
||
+ c = 'O';
|
||
+ }
|
||
+
|
||
+ cur_entry = get_entry (menu_entries,
|
||
+ first_entry + entryno,
|
||
+ 0);
|
||
+
|
||
+ if (c == 'O')
|
||
+ {
|
||
+ grub_memmove (cur_entry + 2, cur_entry,
|
||
+ ((int) heap) - ((int) cur_entry));
|
||
+
|
||
+ cur_entry[0] = ' ';
|
||
+ cur_entry[1] = 0;
|
||
+
|
||
+ heap += 2;
|
||
+
|
||
+ num_entries++;
|
||
+ }
|
||
+ else if (num_entries > 0)
|
||
+ {
|
||
+ char *ptr = get_entry(menu_entries,
|
||
+ first_entry + entryno + 1,
|
||
+ 0);
|
||
+
|
||
+ grub_memmove (cur_entry, ptr,
|
||
+ ((int) heap) - ((int) ptr));
|
||
+ heap -= (((int) ptr) - ((int) cur_entry));
|
||
+
|
||
+ num_entries--;
|
||
+
|
||
+ if (entryno >= num_entries)
|
||
+ entryno--;
|
||
+ if (first_entry && num_entries < 12 + first_entry)
|
||
+ first_entry--;
|
||
+ }
|
||
+
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ {
|
||
+ grub_printf ("\n\n");
|
||
+ print_entries_raw (num_entries, first_entry,
|
||
+ menu_entries);
|
||
+ grub_printf ("\n");
|
||
+ }
|
||
+ else
|
||
+ print_entries (3, 12, first_entry, entryno, menu_entries);
|
||
+ }
|
||
+
|
||
+ cur_entry = menu_entries;
|
||
+ if (c == 27)
|
||
+ return;
|
||
+ if (c == 'b')
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (! auth && password)
|
||
+ {
|
||
+ if (c == 'p')
|
||
+ {
|
||
+ /* Do password check here! */
|
||
+ char entered[32];
|
||
+ char *pptr = password;
|
||
+
|
||
+ if (current_term->flags & TERM_DUMB)
|
||
+ grub_printf ("\r ");
|
||
+ else
|
||
+ gotoxy (1, 21);
|
||
+
|
||
+ /* Wipe out the previously entered password */
|
||
+ grub_memset (entered, 0, sizeof (entered));
|
||
+ get_cmdline (" Password: ", entered, 31, '*', 0);
|
||
+
|
||
+ while (! isspace (*pptr) && *pptr)
|
||
+ pptr++;
|
||
+
|
||
+ /* Make sure that PASSWORD is NUL-terminated. */
|
||
+ *pptr++ = 0;
|
||
+
|
||
+ if (! check_password (entered, password, password_type))
|
||
+ {
|
||
+ char *new_file = config_file;
|
||
+ while (isspace (*pptr))
|
||
+ pptr++;
|
||
+
|
||
+ /* If *PPTR is NUL, then allow the user to use
|
||
+ privileged instructions, otherwise, load
|
||
+ another configuration file. */
|
||
+ if (*pptr != 0)
|
||
+ {
|
||
+ while ((*(new_file++) = *(pptr++)) != 0)
|
||
+ ;
|
||
+
|
||
+ /* Make sure that the user will not have
|
||
+ authority in the next configuration. */
|
||
+ auth = 0;
|
||
+ return;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Now the user is superhuman. */
|
||
+ auth = 1;
|
||
+ goto restart;
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ grub_printf ("Failed!\n Press any key to continue...");
|
||
+ getkey ();
|
||
+ goto restart;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if (c == 'e')
|
||
+ {
|
||
+ int new_num_entries = 0, i = 0;
|
||
+ char *new_heap;
|
||
+
|
||
+ if (config_entries)
|
||
+ {
|
||
+ new_heap = heap;
|
||
+ cur_entry = get_entry (config_entries,
|
||
+ first_entry + entryno,
|
||
+ 1);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* safe area! */
|
||
+ new_heap = heap + NEW_HEAPSIZE + 1;
|
||
+ cur_entry = get_entry (menu_entries,
|
||
+ first_entry + entryno,
|
||
+ 0);
|
||
+ }
|
||
+
|
||
+ do
|
||
+ {
|
||
+ while ((*(new_heap++) = cur_entry[i++]) != 0);
|
||
+ new_num_entries++;
|
||
+ }
|
||
+ while (config_entries && cur_entry[i]);
|
||
+
|
||
+ /* this only needs to be done if config_entries is non-NULL,
|
||
+ but it doesn't hurt to do it always */
|
||
+ *(new_heap++) = 0;
|
||
+
|
||
+ if (config_entries)
|
||
+ run_menu (heap, NULL, new_num_entries, new_heap, 0);
|
||
+ else
|
||
+ {
|
||
+ cls ();
|
||
+ print_cmdline_message (0);
|
||
+
|
||
+ new_heap = heap + NEW_HEAPSIZE + 1;
|
||
+
|
||
+ saved_drive = boot_drive;
|
||
+ saved_partition = install_partition;
|
||
+ current_drive = GRUB_INVALID_DRIVE;
|
||
+
|
||
+ if (! get_cmdline (PACKAGE " edit> ", new_heap,
|
||
+ NEW_HEAPSIZE + 1, 0, 1))
|
||
+ {
|
||
+ int j = 0;
|
||
+
|
||
+ /* get length of new command */
|
||
+ while (new_heap[j++])
|
||
+ ;
|
||
+
|
||
+ if (j < 2)
|
||
+ {
|
||
+ j = 2;
|
||
+ new_heap[0] = ' ';
|
||
+ new_heap[1] = 0;
|
||
+ }
|
||
+
|
||
+ /* align rest of commands properly */
|
||
+ grub_memmove (cur_entry + j, cur_entry + i,
|
||
+ (int) heap - ((int) cur_entry + i));
|
||
+
|
||
+ /* copy command to correct area */
|
||
+ grub_memmove (cur_entry, new_heap, j);
|
||
+
|
||
+ heap += (j - i);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ goto restart;
|
||
+ }
|
||
+ if (c == 'c')
|
||
+ {
|
||
+ enter_cmdline (heap, 0);
|
||
+ goto restart;
|
||
+ }
|
||
+#ifdef GRUB_UTIL
|
||
+ if (c == 'q')
|
||
+ {
|
||
+ /* The same as ``quit''. */
|
||
+ stop ();
|
||
+ }
|
||
+#endif
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* Attempt to boot an entry. */
|
||
+
|
||
+ boot_entry:
|
||
+
|
||
+ cls ();
|
||
+ setcursor (1);
|
||
+
|
||
+ while (1)
|
||
+ {
|
||
+ if (config_entries)
|
||
+ printf (" Booting \'%s\'\n\n",
|
||
+ get_entry (menu_entries, first_entry + entryno, 0));
|
||
+ else
|
||
+ printf (" Booting command-list\n\n");
|
||
+
|
||
+ if (! cur_entry)
|
||
+ cur_entry = get_entry (config_entries, first_entry + entryno, 1);
|
||
+
|
||
+ /* Set CURRENT_ENTRYNO for the command "savedefault". */
|
||
+ current_entryno = first_entry + entryno;
|
||
+
|
||
+ if (run_script (cur_entry, heap))
|
||
+ {
|
||
+ if (fallback_entryno >= 0)
|
||
+ {
|
||
+ cur_entry = NULL;
|
||
+ first_entry = 0;
|
||
+ entryno = fallback_entries[fallback_entryno];
|
||
+ fallback_entryno++;
|
||
+ if (fallback_entryno >= MAX_FALLBACK_ENTRIES
|
||
+ || fallback_entries[fallback_entryno] < 0)
|
||
+ fallback_entryno = -1;
|
||
+ }
|
||
+ else
|
||
+ break;
|
||
+ }
|
||
+ else
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ show_menu = 1;
|
||
+ goto restart;
|
||
+}
|
||
+
|
||
+
|
||
+static int
|
||
+get_line_from_config (char *cmdline, int maxlen, int read_from_file)
|
||
+{
|
||
+ int pos = 0, literal = 0, comment = 0;
|
||
+ char c; /* since we're loading it a byte at a time! */
|
||
+
|
||
+ while (1)
|
||
+ {
|
||
+ if (read_from_file)
|
||
+ {
|
||
+ if (! grub_read (&c, 1))
|
||
+ break;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if (! read_from_preset_menu (&c, 1))
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ /* Skip all carriage returns. */
|
||
+ if (c == '\r')
|
||
+ continue;
|
||
+
|
||
+ /* Replace tabs with spaces. */
|
||
+ if (c == '\t')
|
||
+ c = ' ';
|
||
+
|
||
+ /* The previous is a backslash, then... */
|
||
+ if (literal)
|
||
+ {
|
||
+ /* If it is a newline, replace it with a space and continue. */
|
||
+ if (c == '\n')
|
||
+ {
|
||
+ c = ' ';
|
||
+
|
||
+ /* Go back to overwrite a backslash. */
|
||
+ if (pos > 0)
|
||
+ pos--;
|
||
+ }
|
||
+
|
||
+ literal = 0;
|
||
+ }
|
||
+
|
||
+ /* translate characters first! */
|
||
+ if (c == '\\' && ! literal)
|
||
+ literal = 1;
|
||
+
|
||
+ if (comment)
|
||
+ {
|
||
+ if (c == '\n')
|
||
+ comment = 0;
|
||
+ }
|
||
+ else if (! pos)
|
||
+ {
|
||
+ if (c == '#')
|
||
+ comment = 1;
|
||
+ else if ((c != ' ') && (c != '\n'))
|
||
+ cmdline[pos++] = c;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ if (c == '\n')
|
||
+ break;
|
||
+
|
||
+ if (pos < maxlen)
|
||
+ cmdline[pos++] = c;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ cmdline[pos] = 0;
|
||
+
|
||
+ return pos;
|
||
+}
|
||
+
|
||
+
|
||
+/* This is the starting function in C. */
|
||
+void
|
||
+cmain (void)
|
||
+{
|
||
+ int config_len, menu_len, num_entries;
|
||
+ char *config_entries, *menu_entries;
|
||
+ char *kill_buf = (char *) KILL_BUF;
|
||
+
|
||
+ auto void reset (void);
|
||
+ void reset (void)
|
||
+ {
|
||
+ count_lines = -1;
|
||
+ config_len = 0;
|
||
+ menu_len = 0;
|
||
+ num_entries = 0;
|
||
+ config_entries = (char *) mbi.drives_addr + mbi.drives_length;
|
||
+ menu_entries = (char *) MENU_BUF;
|
||
+ init_config ();
|
||
+ }
|
||
+
|
||
+ /* Initialize the environment for restarting Stage 2. */
|
||
+ grub_setjmp (restart_env);
|
||
+
|
||
+ /* Initialize the kill buffer. */
|
||
+ *kill_buf = 0;
|
||
+
|
||
+ /* Never return. */
|
||
+ for (;;)
|
||
+ {
|
||
+ int is_opened, is_preset;
|
||
+
|
||
+ reset ();
|
||
+
|
||
+ /* Here load the configuration file. */
|
||
+
|
||
+#ifdef GRUB_UTIL
|
||
+ if (use_config_file)
|
||
+#endif /* GRUB_UTIL */
|
||
+ {
|
||
+ char *default_file = (char *) DEFAULT_FILE_BUF;
|
||
+ int i;
|
||
+
|
||
+ /* Get a saved default entry if possible. */
|
||
+ saved_entryno = 0;
|
||
+ *default_file = 0;
|
||
+ grub_strncat (default_file, config_file, DEFAULT_FILE_BUFLEN);
|
||
+ for (i = grub_strlen(default_file); i >= 0; i--)
|
||
+ if (default_file[i] == '/')
|
||
+ {
|
||
+ i++;
|
||
+ break;
|
||
+ }
|
||
+ default_file[i] = 0;
|
||
+ grub_strncat (default_file + i, "default", DEFAULT_FILE_BUFLEN - i);
|
||
+ if (grub_open (default_file))
|
||
+ {
|
||
+ char buf[10]; /* This is good enough. */
|
||
+ char *p = buf;
|
||
+ int len;
|
||
+
|
||
+ len = grub_read (buf, sizeof (buf));
|
||
+ if (len > 0)
|
||
+ {
|
||
+ buf[sizeof (buf) - 1] = 0;
|
||
+ safe_parse_maxint (&p, &saved_entryno);
|
||
+ }
|
||
+
|
||
+ grub_close ();
|
||
+ }
|
||
+ errnum = ERR_NONE;
|
||
+
|
||
+ do
|
||
+ {
|
||
+ /* STATE 0: Before any title command.
|
||
+ STATE 1: In a title command.
|
||
+ STATE >1: In a entry after a title command. */
|
||
+ int state = 0, prev_config_len = 0, prev_menu_len = 0;
|
||
+ char *cmdline;
|
||
+
|
||
+ /* Try the preset menu first. This will succeed at most once,
|
||
+ because close_preset_menu disables the preset menu. */
|
||
+ is_opened = is_preset = open_preset_menu ();
|
||
+ if (! is_opened)
|
||
+ {
|
||
+ is_opened = grub_open (config_file);
|
||
+ errnum = ERR_NONE;
|
||
+ }
|
||
+
|
||
+ if (! is_opened)
|
||
+ break;
|
||
+
|
||
+ /* This is necessary, because the menu must be overrided. */
|
||
+ reset ();
|
||
+
|
||
+ cmdline = (char *) CMDLINE_BUF;
|
||
+ while (get_line_from_config (cmdline, NEW_HEAPSIZE,
|
||
+ ! is_preset))
|
||
+ {
|
||
+ struct builtin *builtin;
|
||
+
|
||
+ /* Get the pointer to the builtin structure. */
|
||
+ builtin = find_command (cmdline);
|
||
+ errnum = 0;
|
||
+ if (! builtin)
|
||
+ /* Unknown command. Just skip now. */
|
||
+ continue;
|
||
+
|
||
+ if (builtin->flags & BUILTIN_TITLE)
|
||
+ {
|
||
+ char *ptr;
|
||
+
|
||
+ /* the command "title" is specially treated. */
|
||
+ if (state > 1)
|
||
+ {
|
||
+ /* The next title is found. */
|
||
+ num_entries++;
|
||
+ config_entries[config_len++] = 0;
|
||
+ prev_menu_len = menu_len;
|
||
+ prev_config_len = config_len;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* The first title is found. */
|
||
+ menu_len = prev_menu_len;
|
||
+ config_len = prev_config_len;
|
||
+ }
|
||
+
|
||
+ /* Reset the state. */
|
||
+ state = 1;
|
||
+
|
||
+ /* Copy title into menu area. */
|
||
+ ptr = skip_to (1, cmdline);
|
||
+ while ((menu_entries[menu_len++] = *(ptr++)) != 0)
|
||
+ ;
|
||
+ }
|
||
+ else if (! state)
|
||
+ {
|
||
+ /* Run a command found is possible. */
|
||
+ if (builtin->flags & BUILTIN_MENU)
|
||
+ {
|
||
+ char *arg = skip_to (1, cmdline);
|
||
+ (builtin->func) (arg, BUILTIN_MENU);
|
||
+ errnum = 0;
|
||
+ }
|
||
+ else
|
||
+ /* Ignored. */
|
||
+ continue;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ char *ptr = cmdline;
|
||
+
|
||
+ state++;
|
||
+ /* Copy config file data to config area. */
|
||
+ while ((config_entries[config_len++] = *ptr++) != 0)
|
||
+ ;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (state > 1)
|
||
+ {
|
||
+ /* Finish the last entry. */
|
||
+ num_entries++;
|
||
+ config_entries[config_len++] = 0;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ menu_len = prev_menu_len;
|
||
+ config_len = prev_config_len;
|
||
+ }
|
||
+
|
||
+ menu_entries[menu_len++] = 0;
|
||
+ config_entries[config_len++] = 0;
|
||
+ grub_memmove (config_entries + config_len, menu_entries,
|
||
+ menu_len);
|
||
+ menu_entries = config_entries + config_len;
|
||
+
|
||
+ /* Make sure that all fallback entries are valid. */
|
||
+ if (fallback_entryno >= 0)
|
||
+ {
|
||
+ for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
|
||
+ {
|
||
+ if (fallback_entries[i] < 0)
|
||
+ break;
|
||
+ if (fallback_entries[i] >= num_entries)
|
||
+ {
|
||
+ grub_memmove (fallback_entries + i,
|
||
+ fallback_entries + i + 1,
|
||
+ ((MAX_FALLBACK_ENTRIES - i - 1)
|
||
+ * sizeof (int)));
|
||
+ i--;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (fallback_entries[0] < 0)
|
||
+ fallback_entryno = -1;
|
||
+ }
|
||
+ /* Check if the default entry is present. Otherwise reset
|
||
+ it to fallback if fallback is valid, or to DEFAULT_ENTRY
|
||
+ if not. */
|
||
+ if (default_entry >= num_entries)
|
||
+ {
|
||
+ if (fallback_entryno >= 0)
|
||
+ {
|
||
+ default_entry = fallback_entries[0];
|
||
+ fallback_entryno++;
|
||
+ if (fallback_entryno >= MAX_FALLBACK_ENTRIES
|
||
+ || fallback_entries[fallback_entryno] < 0)
|
||
+ fallback_entryno = -1;
|
||
+ }
|
||
+ else
|
||
+ default_entry = 0;
|
||
+ }
|
||
+
|
||
+ if (is_preset)
|
||
+ close_preset_menu ();
|
||
+ else
|
||
+ grub_close ();
|
||
+ }
|
||
+ while (is_preset);
|
||
+ }
|
||
+
|
||
+ if (! num_entries)
|
||
+ {
|
||
+ /* If no acceptable config file, goto command-line, starting
|
||
+ heap from where the config entries would have been stored
|
||
+ if there were any. */
|
||
+ enter_cmdline (config_entries, 1);
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Run menu interface. */
|
||
+ run_menu (menu_entries, config_entries, num_entries,
|
||
+ menu_entries + menu_len, default_entry);
|
||
+ }
|
||
+ }
|
||
+}
|
||
diff -Nur grub-0.97/stage2/term.h grub-0.97-patched/stage2/term.h
|
||
--- grub-0.97/stage2/term.h 2003-07-09 13:45:53.000000000 +0200
|
||
+++ grub-0.97-patched/stage2/term.h 2012-11-11 17:06:33.311470556 +0100
|
||
@@ -60,6 +60,8 @@
|
||
const char *name;
|
||
/* The feature flags defined above. */
|
||
unsigned long flags;
|
||
+ /* Default for maximum number of lines if not specified */
|
||
+ unsigned short max_lines;
|
||
/* Put a character. */
|
||
void (*putchar) (int c);
|
||
/* Check if any input character is available. */
|
||
@@ -79,6 +81,11 @@
|
||
void (*setcolor) (int normal_color, int highlight_color);
|
||
/* Turn on/off the cursor. */
|
||
int (*setcursor) (int on);
|
||
+
|
||
+ /* function to start a terminal */
|
||
+ int (*startup) (void);
|
||
+ /* function to use to shutdown a terminal */
|
||
+ void (*shutdown) (void);
|
||
};
|
||
|
||
/* This lists up available terminals. */
|
||
@@ -124,4 +131,23 @@
|
||
int hercules_setcursor (int on);
|
||
#endif
|
||
|
||
+#ifdef SUPPORT_GRAPHICS
|
||
+extern int foreground, background, border, graphics_inited;
|
||
+
|
||
+void graphics_set_splash(char *splashfile);
|
||
+int set_videomode (int mode);
|
||
+void graphics_putchar (int c);
|
||
+int graphics_getxy(void);
|
||
+void graphics_gotoxy(int x, int y);
|
||
+void graphics_cls(void);
|
||
+void graphics_setcolorstate (color_state state);
|
||
+void graphics_setcolor (int normal_color, int highlight_color);
|
||
+void graphics_setcursor (int on);
|
||
+int graphics_init(void);
|
||
+void graphics_end(void);
|
||
+
|
||
+int hex(int v);
|
||
+void graphics_set_palette(int idx, int red, int green, int blue);
|
||
+#endif /* SUPPORT_GRAPHICS */
|
||
+
|
||
#endif /* ! GRUB_TERM_HEADER */
|
||
diff -Nur grub-0.97/THANKS grub-0.97-patched/THANKS
|
||
--- grub-0.97/THANKS 2005-05-08 04:17:43.000000000 +0200
|
||
+++ grub-0.97-patched/THANKS 2012-11-11 17:07:12.709729021 +0100
|
||
@@ -121,3 +121,4 @@
|
||
Yedidyah Bar-David <didi@post.tau.ac.il>
|
||
Yury V. Umanets <umka@namesys.com>
|
||
Yuri Zaporogets <yuriz@ukr.net>
|
||
+Vitaly Fertman <vitaly@namesys.com>
|
||
diff -Nur grub-0.97/util/grub-install.in grub-0.97-patched/util/grub-install.in
|
||
--- grub-0.97/util/grub-install.in 2004-07-24 20:57:31.000000000 +0200
|
||
+++ grub-0.97-patched/util/grub-install.in 2012-11-11 17:07:12.748730268 +0100
|
||
@@ -96,24 +96,27 @@
|
||
# Break the device name into the disk part and the partition part.
|
||
case "$host_os" in
|
||
linux*)
|
||
- tmp_disk=`echo "$1" | sed -e 's%\([sh]d[a-z]\)[0-9]*$%\1%' \
|
||
+ tmp_disk=`echo "$1" | sed -e 's%\([shv]d[a-z]\)[0-9]*$%\1%' \
|
||
-e 's%\(d[0-9]*\)p[0-9]*$%\1%' \
|
||
-e 's%\(fd[0-9]*\)$%\1%' \
|
||
-e 's%/part[0-9]*$%/disc%' \
|
||
- -e 's%\(c[0-7]d[0-9]*\).*$%\1%'`
|
||
- tmp_part=`echo "$1" | sed -e 's%.*/[sh]d[a-z]\([0-9]*\)$%\1%' \
|
||
+ -e 's%\(c[0-7]d[0-9]*\).*$%\1%' \
|
||
+ -e 's%\(e[0-9]\.[0-9]*\).*$%\1%'`
|
||
+ tmp_part=`echo "$1" | sed -e 's%.*/[shv]d[a-z]\([0-9]*\)$%\1%' \
|
||
-e 's%.*d[0-9]*p%%' \
|
||
-e 's%.*/fd[0-9]*$%%' \
|
||
-e 's%.*/floppy/[0-9]*$%%' \
|
||
-e 's%.*/\(disc\|part\([0-9]*\)\)$%\2%' \
|
||
- -e 's%.*c[0-7]d[0-9]*p%%'`
|
||
+ -e 's%.*c[0-7]d[0-9]*p*%%' \
|
||
+ -e 's%.*e[0-9]\.[0-9]*p%%' \
|
||
+ -e 's%.*e[0-9]\.[0-9]*\$%%'`
|
||
;;
|
||
gnu*)
|
||
tmp_disk=`echo "$1" | sed 's%\([sh]d[0-9]*\).*%\1%'`
|
||
tmp_part=`echo "$1" | sed "s%$tmp_disk%%"` ;;
|
||
freebsd* | kfreebsd*-gnu)
|
||
- tmp_disk=`echo "$1" | sed 's%r\{0,1\}\([saw]d[0-9]*\).*$%r\1%' \
|
||
- | sed 's%r\{0,1\}\(da[0-9]*\).*$%r\1%'`
|
||
+ tmp_disk=`echo "$1" | sed 's%r\{0,1\}\([saw]d[0-9]*\).*$%\1%' \
|
||
+ | sed 's%r\{0,1\}\(da[0-9]*\).*$%\1%'`
|
||
tmp_part=`echo "$1" \
|
||
| sed "s%.*/r\{0,1\}[saw]d[0-9]\(s[0-9]*[a-h]\)%\1%" \
|
||
| sed "s%.*/r\{0,1\}da[0-9]\(s[0-9]*[a-h]\)%\1%"`
|
||
@@ -131,7 +134,7 @@
|
||
|
||
# Get the drive name.
|
||
tmp_drive=`grep -v '^#' $device_map | grep "$tmp_disk *$" \
|
||
- | sed 's%.*\(([hf]d[0-9][a-g0-9,]*)\).*%\1%'`
|
||
+ | sed 's%.*\(([hf]d[0-9][a-z0-9,]*)\).*%\1%'`
|
||
|
||
# If not found, print an error message and exit.
|
||
if test "x$tmp_drive" = x; then
|
||
@@ -148,13 +151,13 @@
|
||
gnu*)
|
||
if echo $tmp_part | grep "^s" >/dev/null; then
|
||
tmp_pc_slice=`echo $tmp_part \
|
||
- | sed "s%s\([0-9]*\)[a-g]*$%\1%"`
|
||
+ | sed "s%s\([0-9]*\)[a-z]*$%\1%"`
|
||
tmp_drive=`echo "$tmp_drive" \
|
||
| sed "s%)%,\`expr "$tmp_pc_slice" - 1\`)%"`
|
||
fi
|
||
- if echo $tmp_part | grep "[a-g]$" >/dev/null; then
|
||
+ if echo $tmp_part | grep "[a-z]$" >/dev/null; then
|
||
tmp_bsd_partition=`echo "$tmp_part" \
|
||
- | sed "s%[^a-g]*\([a-g]\)$%\1%"`
|
||
+ | sed "s%[^a-z]*\([a-z]\)$%\1%"`
|
||
tmp_drive=`echo "$tmp_drive" \
|
||
| sed "s%)%,$tmp_bsd_partition)%"`
|
||
fi
|
||
@@ -336,6 +339,10 @@
|
||
# Create a safe temporary file.
|
||
test -n "$mklog" && log_file=`$mklog`
|
||
|
||
+ # Before all invocations of the grub shell, call sync to make sure
|
||
+ # the raw device is in sync with any bufferring in filesystems.
|
||
+ sync
|
||
+
|
||
$grub_shell --batch $no_floppy --device-map=$device_map <<EOF >$log_file
|
||
quit
|
||
EOF
|
||
@@ -450,6 +457,10 @@
|
||
# Create a safe temporary file.
|
||
test -n "$mklog" && log_file=`$mklog`
|
||
|
||
+# Before all invocations of the grub shell, call sync to make sure
|
||
+# the raw device is in sync with any bufferring in filesystems.
|
||
+sync
|
||
+
|
||
# Now perform the installation.
|
||
$grub_shell --batch $no_floppy --device-map=$device_map <<EOF >$log_file
|
||
root $root_drive
|
||
diff -Nur grub-0.97/util/grub-install.in.orig grub-0.97-patched/util/grub-install.in.orig
|
||
--- grub-0.97/util/grub-install.in.orig 1970-01-01 01:00:00.000000000 +0100
|
||
+++ grub-0.97-patched/util/grub-install.in.orig 2004-07-24 20:57:31.000000000 +0200
|
||
@@ -0,0 +1,477 @@
|
||
+#! /bin/sh
|
||
+
|
||
+# Install GRUB on your drive.
|
||
+# Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
|
||
+#
|
||
+# This file is free software; you can redistribute it and/or modify it
|
||
+# under the terms of the GNU General Public License as published by
|
||
+# the Free Software Foundation; either version 2 of the License, or
|
||
+# (at your option) any later version.
|
||
+#
|
||
+# This program is distributed in the hope that it will be useful, but
|
||
+# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+# General Public License for more details.
|
||
+#
|
||
+# You should have received a copy of the GNU General Public License
|
||
+# along with this program; if not, write to the Free Software
|
||
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
+
|
||
+# Initialize some variables.
|
||
+prefix=@prefix@
|
||
+exec_prefix=@exec_prefix@
|
||
+sbindir=@sbindir@
|
||
+libdir=@libdir@
|
||
+PACKAGE=@PACKAGE@
|
||
+VERSION=@VERSION@
|
||
+host_cpu=@host_cpu@
|
||
+host_os=@host_os@
|
||
+host_vendor=@host_vendor@
|
||
+pkglibdir=${libdir}/${PACKAGE}/${host_cpu}-${host_vendor}
|
||
+
|
||
+grub_shell=${sbindir}/grub
|
||
+grub_set_default=${sbindir}/grub-set-default
|
||
+log_file=/tmp/grub-install.log.$$
|
||
+img_file=/tmp/grub-install.img.$$
|
||
+rootdir=
|
||
+grub_prefix=/boot/grub
|
||
+
|
||
+install_device=
|
||
+no_floppy=
|
||
+force_lba=
|
||
+recheck=no
|
||
+debug=no
|
||
+
|
||
+# look for secure tempfile creation wrappers on this platform
|
||
+if test -x /bin/tempfile; then
|
||
+ mklog="/bin/tempfile --prefix=grub"
|
||
+ mkimg="/bin/tempfile --prefix=grub"
|
||
+elif test -x /bin/mktemp; then
|
||
+ mklog="/bin/mktemp /tmp/grub-install.log.XXXXXX"
|
||
+ mkimg="/bin/mktemp /tmp/grub-install.img.XXXXXX"
|
||
+else
|
||
+ mklog=""
|
||
+ mkimg=""
|
||
+fi
|
||
+
|
||
+# Usage: usage
|
||
+# Print the usage.
|
||
+usage () {
|
||
+ cat <<EOF
|
||
+Usage: grub-install [OPTION] install_device
|
||
+Install GRUB on your drive.
|
||
+
|
||
+ -h, --help print this message and exit
|
||
+ -v, --version print the version information and exit
|
||
+ --root-directory=DIR install GRUB images under the directory DIR
|
||
+ instead of the root directory
|
||
+ --grub-shell=FILE use FILE as the grub shell
|
||
+ --no-floppy do not probe any floppy drive
|
||
+ --force-lba force GRUB to use LBA mode even for a buggy
|
||
+ BIOS
|
||
+ --recheck probe a device map even if it already exists
|
||
+
|
||
+INSTALL_DEVICE can be a GRUB device name or a system device filename.
|
||
+
|
||
+grub-install copies GRUB images into the DIR/boot directory specfied by
|
||
+--root-directory, and uses the grub shell to install grub into the boot
|
||
+sector.
|
||
+
|
||
+Report bugs to <bug-grub@gnu.org>.
|
||
+EOF
|
||
+}
|
||
+
|
||
+# Usage: convert os_device
|
||
+# Convert an OS device to the corresponding GRUB drive.
|
||
+# This part is OS-specific.
|
||
+convert () {
|
||
+ # First, check if the device file exists.
|
||
+ if test -e "$1"; then
|
||
+ :
|
||
+ else
|
||
+ echo "$1: Not found or not a block device." 1>&2
|
||
+ exit 1
|
||
+ fi
|
||
+
|
||
+ # Break the device name into the disk part and the partition part.
|
||
+ case "$host_os" in
|
||
+ linux*)
|
||
+ tmp_disk=`echo "$1" | sed -e 's%\([sh]d[a-z]\)[0-9]*$%\1%' \
|
||
+ -e 's%\(d[0-9]*\)p[0-9]*$%\1%' \
|
||
+ -e 's%\(fd[0-9]*\)$%\1%' \
|
||
+ -e 's%/part[0-9]*$%/disc%' \
|
||
+ -e 's%\(c[0-7]d[0-9]*\).*$%\1%'`
|
||
+ tmp_part=`echo "$1" | sed -e 's%.*/[sh]d[a-z]\([0-9]*\)$%\1%' \
|
||
+ -e 's%.*d[0-9]*p%%' \
|
||
+ -e 's%.*/fd[0-9]*$%%' \
|
||
+ -e 's%.*/floppy/[0-9]*$%%' \
|
||
+ -e 's%.*/\(disc\|part\([0-9]*\)\)$%\2%' \
|
||
+ -e 's%.*c[0-7]d[0-9]*p%%'`
|
||
+ ;;
|
||
+ gnu*)
|
||
+ tmp_disk=`echo "$1" | sed 's%\([sh]d[0-9]*\).*%\1%'`
|
||
+ tmp_part=`echo "$1" | sed "s%$tmp_disk%%"` ;;
|
||
+ freebsd* | kfreebsd*-gnu)
|
||
+ tmp_disk=`echo "$1" | sed 's%r\{0,1\}\([saw]d[0-9]*\).*$%r\1%' \
|
||
+ | sed 's%r\{0,1\}\(da[0-9]*\).*$%r\1%'`
|
||
+ tmp_part=`echo "$1" \
|
||
+ | sed "s%.*/r\{0,1\}[saw]d[0-9]\(s[0-9]*[a-h]\)%\1%" \
|
||
+ | sed "s%.*/r\{0,1\}da[0-9]\(s[0-9]*[a-h]\)%\1%"`
|
||
+ ;;
|
||
+ netbsd* | knetbsd*-gnu)
|
||
+ tmp_disk=`echo "$1" | sed 's%r\{0,1\}\([sw]d[0-9]*\).*$%r\1d%' \
|
||
+ | sed 's%r\{0,1\}\(fd[0-9]*\).*$%r\1a%'`
|
||
+ tmp_part=`echo "$1" \
|
||
+ | sed "s%.*/r\{0,1\}[sw]d[0-9]\([abe-p]\)%\1%"`
|
||
+ ;;
|
||
+ *)
|
||
+ echo "grub-install does not support your OS yet." 1>&2
|
||
+ exit 1 ;;
|
||
+ esac
|
||
+
|
||
+ # Get the drive name.
|
||
+ tmp_drive=`grep -v '^#' $device_map | grep "$tmp_disk *$" \
|
||
+ | sed 's%.*\(([hf]d[0-9][a-g0-9,]*)\).*%\1%'`
|
||
+
|
||
+ # If not found, print an error message and exit.
|
||
+ if test "x$tmp_drive" = x; then
|
||
+ echo "$1 does not have any corresponding BIOS drive." 1>&2
|
||
+ exit 1
|
||
+ fi
|
||
+
|
||
+ if test "x$tmp_part" != x; then
|
||
+ # If a partition is specified, we need to translate it into the
|
||
+ # GRUB's syntax.
|
||
+ case "$host_os" in
|
||
+ linux*)
|
||
+ echo "$tmp_drive" | sed "s%)$%,`expr $tmp_part - 1`)%" ;;
|
||
+ gnu*)
|
||
+ if echo $tmp_part | grep "^s" >/dev/null; then
|
||
+ tmp_pc_slice=`echo $tmp_part \
|
||
+ | sed "s%s\([0-9]*\)[a-g]*$%\1%"`
|
||
+ tmp_drive=`echo "$tmp_drive" \
|
||
+ | sed "s%)%,\`expr "$tmp_pc_slice" - 1\`)%"`
|
||
+ fi
|
||
+ if echo $tmp_part | grep "[a-g]$" >/dev/null; then
|
||
+ tmp_bsd_partition=`echo "$tmp_part" \
|
||
+ | sed "s%[^a-g]*\([a-g]\)$%\1%"`
|
||
+ tmp_drive=`echo "$tmp_drive" \
|
||
+ | sed "s%)%,$tmp_bsd_partition)%"`
|
||
+ fi
|
||
+ echo "$tmp_drive" ;;
|
||
+ freebsd* | kfreebsd*-gnu)
|
||
+ if echo $tmp_part | grep "^s" >/dev/null; then
|
||
+ tmp_pc_slice=`echo $tmp_part \
|
||
+ | sed "s%s\([0-9]*\)[a-h]*$%\1%"`
|
||
+ tmp_drive=`echo "$tmp_drive" \
|
||
+ | sed "s%)%,\`expr "$tmp_pc_slice" - 1\`)%"`
|
||
+ fi
|
||
+ if echo $tmp_part | grep "[a-h]$" >/dev/null; then
|
||
+ tmp_bsd_partition=`echo "$tmp_part" \
|
||
+ | sed "s%s\{0,1\}[0-9]*\([a-h]\)$%\1%"`
|
||
+ tmp_drive=`echo "$tmp_drive" \
|
||
+ | sed "s%)%,$tmp_bsd_partition)%"`
|
||
+ fi
|
||
+ echo "$tmp_drive" ;;
|
||
+ netbsd* | knetbsd*-gnu)
|
||
+ if echo $tmp_part | grep "^[abe-p]$" >/dev/null; then
|
||
+ tmp_bsd_partition=`echo "$tmp_part" \
|
||
+ | sed "s%\([a-p]\)$%\1%"`
|
||
+ tmp_drive=`echo "$tmp_drive" \
|
||
+ | sed "s%)%,$tmp_bsd_partition)%"`
|
||
+ fi
|
||
+ echo "$tmp_drive" ;;
|
||
+ esac
|
||
+ else
|
||
+ # If no partition is specified, just print the drive name.
|
||
+ echo "$tmp_drive"
|
||
+ fi
|
||
+}
|
||
+
|
||
+# Usage: resolve_symlink file
|
||
+# Find the real file/device that file points at
|
||
+resolve_symlink () {
|
||
+ tmp_fname=$1
|
||
+ # Resolve symlinks
|
||
+ while test -L $tmp_fname; do
|
||
+ tmp_new_fname=`ls -al $tmp_fname | sed -n 's%.*-> \(.*\)%\1%p'`
|
||
+ if test -z "$tmp_new_fname"; then
|
||
+ echo "Unrecognized ls output" 2>&1
|
||
+ exit 1
|
||
+ fi
|
||
+
|
||
+ # Convert relative symlinks
|
||
+ case $tmp_new_fname in
|
||
+ /*) tmp_fname="$tmp_new_fname"
|
||
+ ;;
|
||
+ *) tmp_fname="`echo $tmp_fname | sed 's%/[^/]*$%%'`/$tmp_new_fname"
|
||
+ ;;
|
||
+ esac
|
||
+ done
|
||
+ echo "$tmp_fname"
|
||
+}
|
||
+
|
||
+# Usage: find_device file
|
||
+# Find block device on which the file resides.
|
||
+find_device () {
|
||
+ # For now, this uses the program `df' to get the device name, but is
|
||
+ # this really portable?
|
||
+ tmp_fname=`df $1/ | sed -n 's%.*\(/dev/[^ ]*\).*%\1%p'`
|
||
+
|
||
+ if test -z "$tmp_fname"; then
|
||
+ echo "Could not find device for $1" 2>&1
|
||
+ exit 1
|
||
+ fi
|
||
+
|
||
+ tmp_fname=`resolve_symlink $tmp_fname`
|
||
+
|
||
+ echo "$tmp_fname"
|
||
+}
|
||
+
|
||
+# Check the arguments.
|
||
+for option in "$@"; do
|
||
+ case "$option" in
|
||
+ -h | --help)
|
||
+ usage
|
||
+ exit 0 ;;
|
||
+ -v | --version)
|
||
+ echo "grub-install (GNU GRUB ${VERSION})"
|
||
+ exit 0 ;;
|
||
+ --root-directory=*)
|
||
+ rootdir=`echo "$option" | sed 's/--root-directory=//'` ;;
|
||
+ --grub-shell=*)
|
||
+ grub_shell=`echo "$option" | sed 's/--grub-shell=//'` ;;
|
||
+ --no-floppy)
|
||
+ no_floppy="--no-floppy" ;;
|
||
+ --force-lba)
|
||
+ force_lba="--force-lba" ;;
|
||
+ --recheck)
|
||
+ recheck=yes ;;
|
||
+ # This is an undocumented feature...
|
||
+ --debug)
|
||
+ debug=yes ;;
|
||
+ -*)
|
||
+ echo "Unrecognized option \`$option'" 1>&2
|
||
+ usage
|
||
+ exit 1
|
||
+ ;;
|
||
+ *)
|
||
+ if test "x$install_device" != x; then
|
||
+ echo "More than one install_devices?" 1>&2
|
||
+ usage
|
||
+ exit 1
|
||
+ fi
|
||
+ install_device="${option}" ;;
|
||
+ esac
|
||
+done
|
||
+
|
||
+if test "x$install_device" = x; then
|
||
+ echo "install_device not specified." 1>&2
|
||
+ usage
|
||
+ exit 1
|
||
+fi
|
||
+
|
||
+# If the debugging feature is enabled, print commands.
|
||
+if test $debug = yes; then
|
||
+ set -x
|
||
+fi
|
||
+
|
||
+# Initialize these directories here, since ROOTDIR was initialized.
|
||
+case "$host_os" in
|
||
+netbsd* | openbsd*)
|
||
+ # Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub
|
||
+ # instead of /boot/grub.
|
||
+ grub_prefix=/grub
|
||
+ bootdir=${rootdir}
|
||
+ ;;
|
||
+*)
|
||
+ # Use /boot/grub by default.
|
||
+ bootdir=${rootdir}/boot
|
||
+ ;;
|
||
+esac
|
||
+
|
||
+grubdir=${bootdir}/grub
|
||
+device_map=${grubdir}/device.map
|
||
+
|
||
+# Check if GRUB is installed.
|
||
+# This is necessary, because the user can specify "grub --read-only".
|
||
+set $grub_shell dummy
|
||
+if test -f "$1"; then
|
||
+ :
|
||
+else
|
||
+ echo "$1: Not found." 1>&2
|
||
+ exit 1
|
||
+fi
|
||
+
|
||
+if test -f "$pkglibdir/stage1"; then
|
||
+ :
|
||
+else
|
||
+ echo "${pkglibdir}/stage1: Not found." 1>&2
|
||
+ exit 1
|
||
+fi
|
||
+
|
||
+if test -f "$pkglibdir/stage2"; then
|
||
+ :
|
||
+else
|
||
+ echo "${pkglibdir}/stage2: Not found." 1>&2
|
||
+ exit 1
|
||
+fi
|
||
+
|
||
+# Don't check for *stage1_5, because it is not fatal even if any
|
||
+# Stage 1.5 does not exist.
|
||
+
|
||
+# Create the GRUB directory if it is not present.
|
||
+test -d "$bootdir" || mkdir "$bootdir" || exit 1
|
||
+test -d "$grubdir" || mkdir "$grubdir" || exit 1
|
||
+
|
||
+# If --recheck is specified, remove the device map, if present.
|
||
+if test $recheck = yes; then
|
||
+ rm -f $device_map
|
||
+fi
|
||
+
|
||
+# Create the device map file if it is not present.
|
||
+if test -f "$device_map"; then
|
||
+ :
|
||
+else
|
||
+ # Create a safe temporary file.
|
||
+ test -n "$mklog" && log_file=`$mklog`
|
||
+
|
||
+ $grub_shell --batch $no_floppy --device-map=$device_map <<EOF >$log_file
|
||
+quit
|
||
+EOF
|
||
+ if grep "Error [0-9]*: " $log_file >/dev/null; then
|
||
+ cat $log_file 1>&2
|
||
+ exit 1
|
||
+ fi
|
||
+
|
||
+ rm -f $log_file
|
||
+fi
|
||
+
|
||
+# Make sure that there is no duplicated entry.
|
||
+tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' $device_map \
|
||
+ | sort | uniq -d | sed -n 1p`
|
||
+if test -n "$tmp"; then
|
||
+ echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2
|
||
+ exit 1
|
||
+fi
|
||
+
|
||
+# Check for INSTALL_DEVICE.
|
||
+case "$install_device" in
|
||
+/dev/*)
|
||
+ install_device=`resolve_symlink "$install_device"`
|
||
+ install_drive=`convert "$install_device"`
|
||
+ # I don't know why, but some shells wouldn't die if exit is
|
||
+ # called in a function.
|
||
+ if test "x$install_drive" = x; then
|
||
+ exit 1
|
||
+ fi ;;
|
||
+\([hf]d[0-9]*\))
|
||
+ install_drive="$install_device" ;;
|
||
+[hf]d[0-9]*)
|
||
+ # The GRUB format with no parenthesis.
|
||
+ install_drive="($install_device)" ;;
|
||
+*)
|
||
+ echo "Format of install_device not recognized." 1>&2
|
||
+ usage
|
||
+ exit 1 ;;
|
||
+esac
|
||
+
|
||
+# Get the root drive.
|
||
+root_device=`find_device ${rootdir}`
|
||
+bootdir_device=`find_device ${bootdir}`
|
||
+
|
||
+# Check if the boot directory is in the same device as the root directory.
|
||
+if test "x$root_device" != "x$bootdir_device"; then
|
||
+ # Perhaps the user has a separate boot partition.
|
||
+ root_device=$bootdir_device
|
||
+ grub_prefix="/grub"
|
||
+fi
|
||
+
|
||
+# Convert the root device to a GRUB drive.
|
||
+root_drive=`convert "$root_device"`
|
||
+if test "x$root_drive" = x; then
|
||
+ exit 1
|
||
+fi
|
||
+
|
||
+# Check if the root directory exists in the same device as the grub
|
||
+# directory.
|
||
+grubdir_device=`find_device ${grubdir}`
|
||
+
|
||
+if test "x$grubdir_device" != "x$root_device"; then
|
||
+ # For now, cannot deal with this situation.
|
||
+ cat <<EOF 1>&2
|
||
+You must set the root directory by the option --root-directory, because
|
||
+$grubdir does not exist in the root device $root_device.
|
||
+EOF
|
||
+ exit 1
|
||
+fi
|
||
+
|
||
+# Copy the GRUB images to the GRUB directory.
|
||
+for file in ${grubdir}/stage1 ${grubdir}/stage2 ${grubdir}/*stage1_5; do
|
||
+ rm -f $file || exit 1
|
||
+done
|
||
+for file in \
|
||
+ ${pkglibdir}/stage1 ${pkglibdir}/stage2 ${pkglibdir}/*stage1_5; do
|
||
+ cp -f $file ${grubdir} || exit 1
|
||
+done
|
||
+
|
||
+# Make a default file.
|
||
+${grub_set_default} --root-directory=${rootdir} default
|
||
+
|
||
+# Make sure that GRUB reads the same images as the host OS.
|
||
+test -n "$mkimg" && img_file=`$mkimg`
|
||
+test -n "$mklog" && log_file=`$mklog`
|
||
+
|
||
+for file in ${grubdir}/stage1 ${grubdir}/stage2 ${grubdir}/*stage1_5; do
|
||
+ count=5
|
||
+ tmp=`echo $file | sed "s|^${grubdir}|${grub_prefix}|"`
|
||
+ while test $count -gt 0; do
|
||
+ $grub_shell --batch $no_floppy --device-map=$device_map <<EOF >$log_file
|
||
+dump ${root_drive}${tmp} ${img_file}
|
||
+quit
|
||
+EOF
|
||
+ if grep "Error [0-9]*: " $log_file >/dev/null; then
|
||
+ :
|
||
+ elif cmp $file $img_file >/dev/null; then
|
||
+ break
|
||
+ fi
|
||
+ sleep 1
|
||
+ count=`expr $count - 1`
|
||
+ done
|
||
+ if test $count -eq 0; then
|
||
+ echo "The file $file not read correctly." 1>&2
|
||
+ exit 1
|
||
+ fi
|
||
+done
|
||
+
|
||
+rm -f $img_file
|
||
+rm -f $log_file
|
||
+
|
||
+# Create a safe temporary file.
|
||
+test -n "$mklog" && log_file=`$mklog`
|
||
+
|
||
+# Now perform the installation.
|
||
+$grub_shell --batch $no_floppy --device-map=$device_map <<EOF >$log_file
|
||
+root $root_drive
|
||
+setup $force_lba --stage2=$grubdir/stage2 --prefix=$grub_prefix $install_drive
|
||
+quit
|
||
+EOF
|
||
+
|
||
+if grep "Error [0-9]*: " $log_file >/dev/null || test $debug = yes; then
|
||
+ cat $log_file 1>&2
|
||
+ exit 1
|
||
+fi
|
||
+
|
||
+rm -f $log_file
|
||
+
|
||
+# Prompt the user to check if the device map is correct.
|
||
+echo "Installation finished. No error reported."
|
||
+echo "This is the contents of the device map $device_map."
|
||
+echo "Check if this is correct or not. If any of the lines is incorrect,"
|
||
+echo "fix it and re-run the script \`grub-install'."
|
||
+echo
|
||
+
|
||
+cat $device_map
|
||
+
|
||
+# Bye.
|
||
+exit 0
|
||
diff -Nur grub-0.97/util/mkbimage grub-0.97-patched/util/mkbimage
|
||
--- grub-0.97/util/mkbimage 2004-07-24 20:57:31.000000000 +0200
|
||
+++ grub-0.97-patched/util/mkbimage 2012-11-11 17:07:12.744730138 +0100
|
||
@@ -1,7 +1,7 @@
|
||
#!/bin/sh
|
||
# MaKe a Bootable IMAGE --- 1.44, 2.88 and El Torito no-emulation mode
|
||
# C) 2001,2002,2003 Thierry Laronde <tlaronde@polynum.org>
|
||
-# C) 2001,2002,2003 Robert Millan <robertmh@gnu.org>
|
||
+# C) 2001,2002,2003 Robert Millan <rmh@aybabtu.com>
|
||
|
||
|
||
# This program is free software; you can redistribute it and/or modify
|
||
@@ -94,15 +94,13 @@
|
||
display Version information and exit
|
||
|
||
Copyright (c) 2001,2002,2003 Thierry Laronde <tlaronde@polynum.org>.
|
||
-Copyright (c) 2001,2002 Robert Millan <zeratul2@wanadoo.es>.
|
||
GPLed."
|
||
|
||
version="mkbimage $version_number
|
||
|
||
-Written by Thierry Laronde and Robert Millan.
|
||
+Written by Thierry Laronde.
|
||
|
||
Copyright (c) 2001,2002,2003 Thierry Laronde <tlaronde@polynum.org>.
|
||
-Copyright (c) 2001,2002,2003 Robert Millan <zeratul2@wanadoo.es>.
|
||
|
||
This is free software under the GPL version 2 or later; see the source for
|
||
copying conditions. There is NO warranty, not even for MERCHANTABILITY or
|