merge mainline into gingold2

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-09-11 18:03:47 +02:00
commit 4ce9a74332
162 changed files with 8986 additions and 1304 deletions

View file

@ -18,7 +18,6 @@ config.log
config.status
config.sub
configure
conf/*.mk
*.d
DISTLIST
docs/*.info
@ -69,6 +68,7 @@ Makefile
mod-*.c
missing
*.pf2
*.pp
po/*.mo
po/grub.pot
stamp-h
@ -91,7 +91,10 @@ texinfo.tex
grub-core/lib/libgcrypt-grub
**/.deps-util
**/.deps-core
**/.dirstamp
Makefile.util.am
grub-core/Makefile.core.am
grub-core/Makefile.gcry.am
grub-core/Makefile.gcry.def
grub-core/*.module
grub-core/*.pp

662
ChangeLog
View file

@ -1,3 +1,665 @@
2010-09-11 Vladimir Serbinenko <phcoder@gmail.com>
Shutdown using ACPI.
* grub-core/Makefile.core.def (halt): Add commands/acpihalt.c on i386-pc.
* grub-core/commands/acpihalt.c: New file.
* grub-core/commands/i386/pc/halt.c (grub_cmd_halt): Call grub_acpi_halt.
* include/grub/acpi.h (grub_acpi_fadt): New member pm1a.
(grub_acpi_halt): New proto.
(GRUB_ACPI_SLP_EN): New const.
(GRUB_ACPI_SLP_TYP_OFFSET): Likewise.
(GRUB_ACPI_OPCODE_*): New enum.
(GRUB_ACPI_EXTOPCODE_*): Likewise.
2010-09-11 Tristan Gingold <gingold@free.fr>
2010-09-11 Robert Millan <rmh.grub@aybabtu.com>
2010-09-11 Vladimir Serbinenko <phcoder@gmail.com>
* commands/lsacpi.c: New file.
* grub-core/Makefile.core.def (lsacpi): New module.
* include/grub/acpi.h (GRUB_ACPI_FADT_SIGNATURE): New definition.
(GRUB_ACPI_MADT_SIGNATURE): Likewise.
(grub_acpi_madt_entry_header): New struct.
(grub_acpi_madt): Likewise.
(grub_acpi_madt_entry_interrupt_override): Likewise.
(grub_acpi_madt_entry_sapic): Likewise.
(grub_acpi_madt_entry_lsapic): Likewise.
(grub_acpi_madt_entry_platform_int_source): Likewise.
* include/grub/types.h (PRIxGRUB_UINT32_T): New definition.
(PRIuGRUB_UINT32_T): Likewise.
(PRIxGRUB_UINT64_T): Likewise.
2010-09-11 Vladimir Serbinenko <phcoder@gmail.com>
Implement loading palette on ieee1275_fb.
* grub-core/video/ieee1275.c (stdout_ihandle): New variable.
(have_setcolors): Likewise.
(grub_video_ieee1275_init): Fill stdout_ihandle and have_setcolors.
(grub_video_ieee1275_setup): Use grub_video_ieee1275_set_palette.
(grub_video_ieee1275_set_palette): Implement.
2010-09-11 Vladimir Serbinenko <phcoder@gmail.com>
2010-09-11 Colin Watson <cjwatson@ubuntu.com>
* util/grub-install.in (grub_partition): New variable.
Set prefix_drive on EFI and PC to (,$grub_partition) as last resort.
* util/i386/pc/grub-setup.c (setup): Don't touch prefix.
Fixes a bug reported by Yves Blusseau.
2010-09-11 Vladimir Serbinenko <phcoder@gmail.com>
Fix emu on mipsel.
* conf/Makefile.common (CFLAGS_PLATFORM): Add -mflush-func
=grub_cpu_flush_cache on all mips and not only yeeloong.
* configure.ac (COND_mips): New conditional.
* grub-core/Makefile.am (KERNEL_HEADER_FILES): Add libgcc on all
platforms.
* grub-core/kern/emu/cache.S (__mips__): Use _flush_cache.
* grub-core/kern/emu/full.c (grub_arch_dl_init_linker)
[GRUB_LINKER_HAVE_INIT]: New function.
(grub_emu_post_init): Likewise.
* grub-core/kern/emu/lite.c (grub_emu_post_init): Likewise.
* grub-core/kern/emu/main.c: Use grub_emu_post_init.
* include/grub/cache.h (_mips): Include mips/cache.h.
* include/grub/disk.h [GRUB_UTIL || GRUB_MACHINE_EMU]: Add missing
LVM and RAID prototypes.
* include/grub/emu/misc.h (grub_emu_post_init): New proto.
* include/grub/mips/time.h (grub_cpu_idle) [GRUB_MACHINE_EMU]: New
function.
2010-09-10 Colin Watson <cjwatson@ubuntu.com>
* util/grub-install.in: Don't try to verify core.img until after
running grub-mkimage to create it.
2010-09-10 Robert Millan <rmh@gnu.org>
* util/grub.d/10_hurd.in: Add misc readability checks.
* util/grub.d/10_kfreebsd.in: Likewise.
* util/grub.d/10_linux.in: Likewise.
2010-09-10 Colin Watson <cjwatson@ubuntu.com>
* util/grub-install.in: ${imgext} won't be defined here until the
install branch is merged. For the meantime, only verify core.img on
i386-pc and sparc64-ieee1275 platforms.
2010-09-10 Robert Millan <rmh@gnu.org>
Solaris support in grub_find_zpool_from_dir(). Thanks
Seth Goldberg for referring to getextmntent() facility.
* configure.ac: Check for getextmntent(), `sys/mnttab.h' and
`sys/mkdev.h'.
* grub-core/kern/emu/misc.c [HAVE_SYS_MNTTAB_H]: Include
`<sys/mnttab.h>'.
[HAVE_SYS_MKDEV_H]: Include `<sys/mkdev.h>'.
[HAVE_GETEXTMNTENT] (grub_find_zpool_from_dir): Add getextmntent()
method for finding zpool name.
2010-09-10 Colin Watson <cjwatson@ubuntu.com>
grub-fstest needs the host and hostfs modules while other utilities
actively require those modules to be absent, so grub-fstest needs
its own initialisation and finalisation code.
* Makefile.am (grub_fstest.pp): New target.
(grub_fstest_init.lst): Likewise.
(grub_fstest_init.c): Likewise.
* Makefile.util.def (grub-fstest): Add grub_fstest_init.c.
2010-09-10 Robert Millan <rmh@gnu.org>
* configure.ac: Check for `struct statfs.f_fstypename' and
`struct statfs.f_mntfromname'.
* grub-core/kern/emu/misc.c (grub_find_zpool_from_dir): Conditionalize
kFreeBSD-specific code.
2010-09-10 Robert Millan <rmh@gnu.org>
* util/grub.d/10_kfreebsd.in: Fix ${kfreebsd_device} initialization
on ZFS. Now non-main filesystems are supported as / too.
2010-09-09 Colin Watson <cjwatson@ubuntu.com>
* Makefile.util.def (libgrub.a): Move grub-core/kern/emu/hostfs.c
and grub-core/disk/host.c to ...
(grub-fstest): ... here. Having the host disk implementation
present confuses grub-probe and other utility programs.
* util/grub-mkconfig.in: Only verify readability of grub.cfg.new
when writing to a file, not when writing to stdout.
2010-09-09 BVK Chaitanya <bvk.groups@gmail.com>
* tests/partmap_test.in: New test for partitions.
* Makefile.util.def: Rules for new test.
2010-09-09 Robert Millan <rmh@gnu.org>
* util/grub-probe.c (probe): Fix a pair of unhandled error
conditions.
2010-09-09 Robert Millan <rmh@gnu.org>
Basic Btrfs support (detection and UUID).
* grub-core/fs/btrfs.c: New file.
* Makefile.util.def (library): Register btrfs.c.
* grub-core/Makefile.core.def: Likewise.
2010-09-08 Robert Millan <rmh@gnu.org>
* util/grub-mkconfig_lib.in (is_path_readable_by_grub): Improve
with (optional) parameters to specify device and relative path.
* util/grub-install.in: Use is_path_readable_by_grub() to
verify readability of a few critical files.
* util/grub-mkconfig.in: Use is_path_readable_by_grub() to
verify readability of grub.cfg.new.
2010-09-08 Vladimir Serbinenko <phcoder@gmail.com>
Split minix.mod into minix.mod and minix2.mod.
* Makefile.util.def (libgrub.a): Add grub-core/fs/minix2.c.
* grub-core/Makefile.core.def (minix2): New module.
* grub-core/fs/minix.c: Use definitions instead of runtime version
checking.
* grub-core/fs/minix2.c: New file.
2010-09-08 Yves Blusseau <blusseau@zetam.org>
Add new --boot-directory option to replace --root-directory
* util/grub-install.in: Add new --boot-directory option
* util/grub-reboot.in: Likewise.
* util/grub-set-default.in: Likewise.
2010-09-08 Yves Blusseau <blusseau@zetam.org>
* util/grub-mkconfig.in: Use new variable.
2010-09-08 Yves Blusseau <blusseau@zetam.org>
* configure.ac: Define some useful variables.
2010-09-08 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/kern/ieee1275/cmain.c (grub_ieee1275_find_options): Set
GRUB_IEEE1275_FLAG_HAS_CURSORONOFF when appropriate.
* grub-core/term/ieee1275/ofconsole.c (grub_ofconsole_setcursor):
Use terminfo and don't use cursor-on/cursor-off unless it's known
to work.
* include/grub/ieee1275/ieee1275.h (grub_ieee1275_flag): New element
GRUB_IEEE1275_FLAG_HAS_CURSORONOFF.
2010-09-08 Colin Watson <cjwatson@ubuntu.com>
* grub-core/kern/efi/init.c (grub_efi_set_prefix): If the prefix
starts with "(,", fill the drive containing the loaded image in
between those two characters, but expect that a full partition
specification including partition map names will follow.
2010-09-08 Robert Millan <rmh@gnu.org>
* configure.ac: Remove `--enable-grub-fstest' option.
* Makefile.util.def (grub-fstest): Remove COND_GRUB_FSTEST condition.
* util/grub-mkconfig_lib.in (is_path_readable_by_grub): Use
`grub-fstest' instead of `grub-probe' for readability verification.
* util/grub-probe.c (probe): Remove readability verification kludge.
2010-09-08 Robert Millan <rmh@gnu.org>
* util/grub-mkconfig.in: Pass `--device ${GRUB_DEVICE}' when
initializing `GRUB_FS'.
2010-09-08 BVK Chaitanya <bvk.groups@gmail.com>
Not command (!) support to GRUB script.
* tests/grub_script_not.in: New test.
* Makefile.util.def: Rules for new test.
* grub-core/script/execute.c (grub_script_execute_cmdline): Handle
! command as a special case.
* grub-core/script/yylex.l (GRUB_PARSER_TOKEN_NOT): Removed.
2010-09-07 BVK Chaitanya <bvk.groups@gmail.com>
* grub-core/commands/wildcard.c (wildcard_expand): Fix wrong
grub_free.
2010-09-07 BVK Chaitanya <bvk.groups@gmail.com>
* docs/grub.texi (Shell-like scripting): Fix @dots to @dots{}.
2010-09-07 BVK Chaitanya <bvk.groups@gmail.com>
* docs/grub.texi (Shell-like scripting): Documentation for break,
continue, shift and return commands.
2010-09-06 Vladimir Serbinenko <phcoder@gmail.com>
Rename CD-ROM to cd on BIOS.
* grub-core/disk/i386/pc/biosdisk.c (grub_biosdisk_get_drive): Recognise
"cd".
(grub_biosdisk_call_hook): Call with "cd" instead of arbitrary hdX.
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/kern/emu/main.c (main): Reinit LVM and RAID.
* util/grub-probe.c (main): Likewise.
* util/i386/pc/grub-setup.c (main): Likewise.
* util/sparc64/ieee1275/grub-setup.c (main): Likewise.
Reported and debugged by: alexxy
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/disk/lvm.c (grub_lvm_scan_device) [GRUB_UTIL]: Output more
diagnostic info.
2010-09-05 Jo Shields <directhex@apebox.org>
* util/grub.d/30_os-prober.in: Add missing classes.
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
* docs/grub.texi (Theme file format): Document new position format.
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
* docs/grub.texi (Theme file format): Replace Box_slice_names.png with
a table. Use @code instead of @verbatim.
2010-09-05 Colin D Bennett <colin@gibibit.com>
Gfxmenu documentation.
* docs/grub.texi (Theme file format): New chapter.
2010-09-05 Szymon Janc <szymon@janc.net.pl>
* grub-core/Makefile.core.def (xzio): New module.
* grub-core/io/xzio.c: New file.
* grub-core/lib/xzembed/xz.h: New file (from xembed).
* grub-core/lib/xzembed/xz_config.h: Likewise.
* grub-core/lib/xzembed/xz_dec_bcj.c: Likewise.
* grub-core/lib/xzembed/xz_dec_lzma2.c: Likewise.
* grub-core/lib/xzembed/xz_dec_stream.c: Likewise.
* grub-core/lib/xzembed/xz_lzma2.h: Likewise.
* grub-core/lib/xzembed/xz_private.h: Likewise.
* grub-core/lib/xzembed/xz_stream.h: Likewise.
* include/grub/file.h (grub_file_filter_id): New compression filter
GRUB_FILE_FILTER_XZIO.
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
* include/grub/file.h (GRUB_FILE_SIZE_UNKNOWN): New definition.
* grub-core/disk/loopback.c (grub_loopback_open): Handle unknown file
size.
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
* include/grub/err.h (grub_err_t): Replace GRUB_ERR_BAD_GZIP_DATA with
GRUB_ERR_BAD_COMPRESSED_DATA. All users updated.
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
Uncompressed checksum support.
* grub-core/commands/hashsum.c (options): Add option --uncompress.
(check_list): New parameter uncompress.
(grub_cmd_hashsum): Handle --uncompress.
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
Reintroduce testload.
* grub-core/commands/minicmd.c (grub_rescue_cmd_testload) [0]: Moved
from here ...
* grub-core/commands/testload.c (grub_cmd_testload): ... here.
(GRUB_MOD_INIT): New function.
(GRUB_MOD_FINI): Likewise.
* grub-core/Makefile.core.def (testload): New module.
2010-09-05 Szymon Janc <szymon@janc.net.pl>
* grub-core/lib/posix_wrap/sys/types.h (bool): Transform into an enum.
(uint8_t): New type.
(uint16_t): Likewise.
(uint32_t): Likewise.
(uint64_t): Likewise.
2010-09-05 Szymon Janc <szymon@janc.net.pl>
* include/grub/crypto.h (GRUB_MD_CRC32): New definition.
2010-09-05 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/io/gzio.c (grub_gzio_open): Removed "transparent" parameter.
Made static.
(grub_gzfile_open): Removed. All users updated.
(GRUB_MOD_INIT): New function.
(GRUB_MOD_FINI): Likewise.
* grub-core/kern/file.c (grub_file_filters_all): New variable.
(grub_file_filters_enabled): Likewise.
(grub_file_open): Handle filters.
* grub-core/loader/i386/bsd.c (GRUB_MOD_INIT): Load gzio.
* grub-core/normal/main.c (GRUB_MOD_INIT): Likewise.
* include/grub/file.h (grub_file_filter_id_t): New type.
(grub_file_filter_t): Likewise.
(grub_file_filters_all): New extern variable.
(grub_file_filters_enabled): Likewise.
(grub_file_filter_register): New inline function.
(grub_file_filter_unregister): Likewise.
(grub_file_filter_disable): Likewise.
(grub_file_filter_disable_compression): Likewise.
* include/grub/gzio.h: Removed.
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
Filename expansion support for wildcards in GRUB script.
* tests/grub_script_expansion.in: New test.
* Makefile.util.def: Rule for new test.
* grub-core/commands/wildcard.c: New file, implements filename
expansion support for GRUB script.
* grub-core/Makefile.core.def: Rule update for regexp.mod.
* grub-core/script/argv.c: Cosmetic changes.
* grub-core/script/execute.c (grub_script_arglist_to_argv):
Refactored to perform wildcard expansion on arguments.
* include/grub/script_sh.h (grub_script_wildcard_translator): New
struct.
* tests/util/grub-shell.in: Fix quoting for read input.
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
Support for updating environment variables with matched substrings
of regexp.
* tests/grub_cmd_regexp.in: New test.
* Makefile.util.def: Rule for new test.
* grub-core/commands/regexp.c: New option -s to update environment
variables with regexp matches.
2010-09-04 Szymon Janc <szymon@janc.net.pl>
* include/grub/file.h (grub_file): New member not_easly_seekable.
(grub_file_seekable): New inline function.
* grub-core/io/gzio.c (test_header): Don't test end magic if file isn't
easily seekable.
(grub_gzio_open): Set not_easly_seekable.
* grub-core/fs/i386/pc/pxe.c (grub_pxefs_open): Set not_easily_seekable.
* grub-core/io/bufio.c (grub_bufio_open): Propagate not_easily_seekable.
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
Support for options to appear multiple times on cmdline.
* include/grub/lib/arg.h (grub_arg_list_alloc): New prototype.
* grub-core/commands/extcmd.c: Support for repeatable option.
* grub-core/lib/arg.c (grub_arg_list_alloc): New function for
repeatable option support.
Refactor menuentry into a regular command.
* grub-core/commands/menuentry.c: New file, menuentry command
implementation.
* grub-core/Makefile.core.def: Rule update for normal.mod.
* grub-core/normal/main.c: Moved menuentry creation to
grub-core/commands/menuentry.c.
* grub-core/normal/menu.c (grub_menu_execute_entry): Removed.
(grub_menu_execute_entry_real): Removed.
* grub-core/script/execute.c (grub_script_execute_sourcecode): New
function.
(grub_script_execute_menuentry): Removed.
* grub-core/script/parser.y (menuentry): Removed.
* grub-core/script/script.c (grub_script_create_cmdmenu): Removed.
* grub-core/script/yylex.l (menuentry): Removed.
* include/grub/menu.h (grub_menu_init): New prototype.
(grub_menu_fini): New prototype.
* include/grub/normal.h (grub_normal_add_menu_entry): Removed.
* include/grub/script_sh.h (grub_script_cmd_menuentry): Removed.
(grub_script_execute_sourcecode): New prototype.
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
"return" command for GRUB script functions.
* tests/grub_script_return.in: New test.
* Makefile.util.def: Rules for new test.
* grub-core/script/execute.c (grub_script_return): New function.
* grub-core/script/main.c: Register/unregister return commaond.
* include/grub/script_sh.h (grub_script_return): New prototype.
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
"setparams" command to update positional parameters.
* tests/grub_script_setparams.in: New test.
* Makefile.util.def: Rules for new test.
* grub-core/script/argv.c (grub_script_argv_make): New function.
* grub-core/script/execute.c (replace_scope): New function.
(grub_script_setparams): New function.
* grub-core/script/lexer.c: Remove unused variables.
* grub-core/script/main.c: Register/unregister setparams command.
* include/grub/script_sh.h (grub_script_argv_make): New prototype.
(grub_script_setparams): New prototype.
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
* grub-core/normal/completion.c (grub_normal_do_completion): Fix
grub_free order.
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
Support for passing block of commands as an argument to extcmds.
* Makefile.util.def: Rules for new test.
* tests/grub_script_blockarg.in: New test.
* grub-core/tests/test_blockarg.c: New file, block argument
command used in the test.
* include/grub/extcmd.h (grub_extcmd_context): New struct.
(grub_register_extcmd_prio): New function prototype.
(grub_extcmd_dispatcher): New function prototype.
* include/grub/command.h (GRUB_COMMAND_FLAG_BLOCKS): New command
type.
* include/grub/script_sh.h (struct grub_script): New members
`children', `next_siblings' and `refcnt' for block arguments and
reference counting.
(GRUB_SCRIPT_ARG_TYPE_BLOCK): New argument type.
(grub_script_arg): New member `script' for block argument.
(grub_script_argv): New member `script' for block argument.
(grub_parser_param): New member `scripts' for block argument.
(grub_script_mem_free): New extern function prototype.
(grub_script_ref): New function prototype.
(grub_script_unref): New function prototype.
* grub-core/normal/dyncmd.c (grub_dyncmd_dispatcher): Moved to
extcmd form to support block arguments.
* grub-core/script/argv.c: Block arguments support.
* grub-core/script/execute.c: Likewise.
* grub-core/script/lexer.c: Likewise.
* grub-core/script/main.c: Likewise.
* grub-core/script/script.c: Likewise.
* grub-core/script/parser.y: Likewise. New `block' and `block0'
non-terminals.
* grub-core/commands/acpi.c: Update extcmd implementations with
grub_extcmd_context_t.
* grub-core/commands/cat.c: Likewise.
* grub-core/commands/echo.c: Likewise.
* grub-core/commands/extcmd.c: Likewise.
* grub-core/commands/hashsum.c: Likewise.
* grub-core/commands/hdparm.c: Likewise.
* grub-core/commands/help.c: Likewise.
* grub-core/commands/hexdump.c: Likewise.
* grub-core/commands/i386/cpuid.c: Likewise.
* grub-core/commands/i386/pc/drivemap.c: Likewise.
* grub-core/commands/i386/pc/halt.c: Likewise.
* grub-core/commands/i386/pc/sendkey.c: Likewise.
* grub-core/commands/iorw.c: Likewise.
* grub-core/commands/keystatus.c: Likewise.
* grub-core/commands/loadenv.c: Likewise.
* grub-core/commands/ls.c: Likewise.
* grub-core/commands/lspci.c: Likewise.
* grub-core/commands/memrw.c: Likewise.
* grub-core/commands/probe.c: Likewise.
* grub-core/commands/search_wrap.c: Likewise.
* grub-core/commands/setpci.c: Likewise.
* grub-core/commands/sleep.c: Likewise.
* grub-core/disk/loopback.c: Likewise.
* grub-core/hello/hello.c: Likewise.
* grub-core/loader/i386/bsd.c: Likewise.
* grub-core/loader/xnu.c: Likewise.
* grub-core/term/gfxterm.c: Likewise.
* grub-core/term/serial.c: Likewise.
* grub-core/tests/lib/functional_test.c: Likewise.
2010-09-04 BVK Chaitanya <bvk.groups@gmail.com>
Multi-line quoted strings support.
* grub-core/script/lexer.c (append_newline): Removed.
(grub_script_lexer_yywrap): Refactored.
(grub_script_lexer_init): Refactored.
* grub-core/script/yylex.l (yywrap): New function.
(grub_lexer_resplit): New function.
(grub_lexer_unput): New function.
* include/grub/script_sh.h (grub_lexer_param): New members, unput
and resplit.
* tests/grub_script_echo1.in: Added few more testcases.
2010-09-04 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/kern/misc.c: Don't add abort alias in utils.
Reported by: echoline.
2010-09-03 BVK Chaitanya <bvk.groups@gmail.com>
Add missing files into "make dist" tarball for other platforms.
* gentpl.py (script): Use dist_noinst_DATA instead of EXTRA_DIST.
* conf/Makefile.common (dist_noinst_DATA): New variable.
* conf/Makefile.extra-dist: Added missing make dist files.
* grub-core/Makefile.core.def: Likewise.
2010-09-03 Vladimir Serbinenko <phcoder@gmail.com>
Compress grub_prefix.
* grub-core/boot/i386/pc/lnxboot.S: Use
GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE.
* grub-core/kern/i386/pc/startup.S: Move grub_prefix to compressed part.
* include/grub/offsets.h: Rename GRUB_MACHINE_DATA_END to
GRUB_MACHINE_PREFIX_END. All users updated.
(GRUB_KERNEL_I386_PC_PREFIX): Set to GRUB_KERNEL_I386_PC_RAW_SIZE.
(GRUB_KERNEL_I386_PC_PREFIX_END): Set to GRUB_KERNEL_I386_PC_PREFIX
+ 0x40.
(GRUB_KERNEL_I386_PC_RAW_SIZE): Decrease.
* util/grub-mkimage.c (image_target_desc): Change data_end to
prefix_end. All users updated.
2010-09-03 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/loader/i386/bsd.c (grub_freebsd_boot): Set %ebp to sane
value.
(grub_openbsd_boot): Likewise.
(grub_netbsd_boot): Likewise.
* grub-core/loader/i386/xnu.c (grub_xnu_boot_resume): Likewise.
(grub_xnu_boot): Likewise.
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
* configure.ac: Clean LIBS variable after tests.
2010-09-02 Colin Watson <cjwatson@ubuntu.com>
* INSTALL: Document that libdevmapper needs to be 1.02.34 or later.
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
* configure.ac: Check for dm_log_with_errno_init in libdevmapper and
echo if libdevmapper will be used.
2010-09-02 Ian Turner <Ian.Turner@deshaw.com>
* grub-core/fs/i386/pc/pxe.c (grub_pxefs_read): Keep the blocksize
constant for the same file.
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/kern/i386/multiboot_mmap.c: Remove leftover include.
2010-09-02 Colin Watson <cjwatson@ubuntu.com>
* .bzrignore: Add *.pp, **/.dirstamp, grub-core/*.module, and
grub-core/*.pp.
2010-09-02 Colin Watson <cjwatson@ubuntu.com>
Zero %ebp and %edi when entering Linux's 32-bit entry point, as
required by the boot protocol.
* include/grub/i386/relocator.h (struct grub_relocator32_state): Add
ebp and edi members.
* grub-core/lib/i386/relocator.c (grub_relocator_boot): Handle
state.ebp and state.edi.
* grub-core/lib/i386/relocator32.S (grub_relocator32_start): Set
%ebp and %edi according to grub_relocator32_ebp and
grub_relocator32_edi respectively.
* grub-core/loader/i386/linux.c (grub_linux_boot): Zero state.ebp
and state.edi.
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
Add i386-pc-pxe image target.
* util/grub-mkimage.c (image_target_desc): New enum value
IMAGE_I386_PC_PXE.
(image_targets): New target i386-pc-pxe.
(generate_image): Handle i386-pc-pxe image.
2010-09-02 Vladimir Serbinenko <phcoder@gmail.com>
Fix grub_pxe_scan.
* grub-core/fs/i386/pc/pxe.c (grub_pxe_pxenv): Put correct type bangpxe.
(grub_pxe_scan): Fix types and pxe_rm_entry computation.
All users updated.
* include/grub/i386/pc/pxe.h (grub_pxe_bangpxe): New struct.
(grub_pxe_pxenv): Correct type.
2010-09-01 Colin Watson <cjwatson@ubuntu.com>
* NEWS: Document most of the important changes since 1.98.
2010-09-01 Colin Watson <cjwatson@ubuntu.com>
* util/grub-mkrescue.in (usage): Tidy up usage output (and hence
generated manual page) a little.
2010-09-01 Colin Watson <cjwatson@ubuntu.com>
* docs/grub.texi: Add myself as an author.
2010-09-01 Vladimir Serbinenko <phcoder@gmail.com>
* Makefile.util.def (libgrub.a): Add missing sunpc.
Reported by: Seth Goldberg.
2010-08-30 Vladimir Serbinenko <phcoder@gmail.com>
Interrupt wrapping and code simplifications.

View file

@ -1,17 +0,0 @@
2008-01-28 Tristan Gingold <gingold@free.fr>
2010-01-18 Robert Millan <rmh.grub@aybabtu.com>
2010-08-31 Vladimir Serbinenko <phcoder@gmail.com>
* commands/lsacpi.c: New file.
* grub-core/Makefile.core.def (lsacpi): New module.
* include/grub/acpi.h (GRUB_ACPI_FADT_SIGNATURE): New definition.
(GRUB_ACPI_MADT_SIGNATURE): Likewise.
(grub_acpi_madt_entry_header): New struct.
(grub_acpi_madt): Likewise.
(grub_acpi_madt_entry_interrupt_override): Likewise.
(grub_acpi_madt_entry_sapic): Likewise.
(grub_acpi_madt_entry_lsapic): Likewise.
(grub_acpi_madt_entry_platform_int_source): Likewise.
* include/grub/types.h (PRIxGRUB_UINT32_T): New definition.
(PRIuGRUB_UINT32_T): Likewise.
(PRIxGRUB_UINT64_T): Likewise.

View file

@ -21,7 +21,7 @@ configuring the GRUB.
On GNU/Linux, you also need:
* libdevmapper (recommended)
* libdevmapper 1.02.34 or later (recommended)
To build grub-emu, you need:

View file

@ -44,6 +44,20 @@ libgrub_a_init.c: libgrub_a_init.lst $(top_srcdir)/geninit.sh
sh $(top_srcdir)/geninit.sh `cat $<` > $@ || (rm -f $@; exit 1)
CLEANFILES += libgrub_a_init.c
# For grub-fstest
grub_fstest.pp: $(grub_fstest_SOURCES)
$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(grub_fstest_CPPFLAGS) $(CPPFLAGS) \
-D'GRUB_MOD_INIT(x)=@MARKER@x@' $^ > $@ || (rm -f $@; exit 1)
CLEANFILES += grub_fstest.pp
grub_fstest_init.lst: libgrub.pp grub_fstest.pp
cat $^ | grep '@MARKER@' | sed 's/@MARKER@\(.*\)@/\1/g' | sort -u > $@ || (rm -f $@; exit 1)
CLEANFILES += grub_fstest_init.lst
grub_fstest_init.c: grub_fstest_init.lst $(top_srcdir)/geninit.sh
sh $(top_srcdir)/geninit.sh `cat $<` > $@ || (rm -f $@; exit 1)
CLEANFILES += grub_fstest_init.c
if COND_GRUB_MKFONT
if COND_HAVE_FONT_SOURCE
grubdata_DATA = unicode.pf2 ascii.pf2 ascii.h widthspec.h

View file

@ -23,7 +23,6 @@ library = {
common = grub-core/kern/misc.c;
common = grub-core/kern/emu/mm.c;
common = grub-core/kern/emu/misc.c;
common = grub-core/kern/emu/hostfs.c;
common = grub-core/kern/emu/getroot.c;
common = grub-core/kern/emu/hostdisk.c;
@ -31,7 +30,6 @@ library = {
common = grub-core/commands/extcmd.c;
common = grub-core/commands/ls.c;
common = grub-core/disk/dmraid_nvidia.c;
common = grub-core/disk/host.c;
common = grub-core/disk/loopback.c;
common = grub-core/disk/lvm.c;
common = grub-core/disk/mdraid_linux.c;
@ -43,6 +41,7 @@ library = {
common = grub-core/fs/afs.c;
common = grub-core/fs/befs_be.c;
common = grub-core/fs/befs.c;
common = grub-core/fs/btrfs.c;
common = grub-core/fs/cpio.c;
common = grub-core/fs/ext2.c;
common = grub-core/fs/fat.c;
@ -52,6 +51,7 @@ library = {
common = grub-core/fs/iso9660.c;
common = grub-core/fs/jfs.c;
common = grub-core/fs/minix.c;
common = grub-core/fs/minix2.c;
common = grub-core/fs/nilfs2.c;
common = grub-core/fs/ntfs.c;
common = grub-core/fs/ntfscomp.c;
@ -88,6 +88,7 @@ library = {
common = grub-core/partmap/gpt.c;
common = grub-core/partmap/msdos.c;
common = grub-core/partmap/sun.c;
common = grub-core/partmap/sunpc.c;
common = grub-core/script/function.c;
common = grub-core/script/lexer.c;
common = grub-core/script/main.c;
@ -178,11 +179,13 @@ program = {
program = {
name = grub-fstest;
mansection = 1;
common_nodist = grub_fstest_init.c;
common = util/grub-fstest.c;
common = grub-core/kern/emu/hostfs.c;
common = grub-core/disk/host.c;
ldadd = libgrub.a;
ldadd = '$(LIBINTL) $(LIBDEVMAPPER)';
condition = COND_GRUB_FSTEST;
};
program = {
@ -500,6 +503,48 @@ script = {
common = tests/grub_script_shift.in;
};
script = {
testcase;
name = grub_script_blockarg;
common = tests/grub_script_blockarg.in;
};
script = {
testcase;
name = grub_script_setparams;
common = tests/grub_script_setparams.in;
};
script = {
testcase;
name = grub_script_return;
common = tests/grub_script_return.in;
};
script = {
testcase;
name = grub_cmd_regexp;
common = tests/grub_cmd_regexp.in;
};
script = {
testcase;
name = grub_script_expansion;
common = tests/grub_script_expansion.in;
};
script = {
testcase;
name = grub_script_not;
common = tests/grub_script_not.in;
};
script = {
testcase;
name = partmap_test;
common = tests/partmap_test.in;
};
program = {
testcase;
name = example_unit_test;

89
NEWS
View file

@ -1,9 +1,98 @@
New in 1.99:
* New relocator. Allows for more kernel support and more
straightforward loader writing.
* Handle USB pendrives exposed as floppies.
* New Automake-based build system.
* Add `sendkey' command (i386-pc only).
* ZFS support in `grub-install' and `grub-mkconfig'. Note: complete
functionality requires external ZFS implementation (available from
grub-extras).
* Support 1.x versions of mdadm metadata.
* Fix corruption when reading Reiserfs directory entries.
* Bidirectional text and diacritics support.
* Skip LVM snapshots.
* MIPS Yeeloong firmware port.
* Change grub-mkdevicemap to emit /dev/disk/by-id/ names where possible
on GNU/Linux.
* Add `grub-mkconfig' support for Xen with Linux.
* Add `grub-mkconfig' support for initrd images on Fedora 13.
* Support >3GiB and <16MiB RAM in i386-qemu.
* Add support for Cirrus 5446 and Bochs video cards.
* Load more appropriate video drivers automatically in `grub-mkconfig'.
* USB improvements, including hotplugging/hotunplugging, hub support,
and USB serial support.
* AMD Geode CS5536 support.
* Extensive updates to the Texinfo documentation.
* Add `grub-probe' support for the btrfs filesystem, permitting / to
reside on btrfs as long as /boot is on a filesystem natively supported
by GRUB.
* Handle symbolic links under /dev/mapper on GNU/Linux.
* Handle installation across multiple partition table types.
* Add `cmostest' command (i386/x86_64 only).
* Add support for DM-RAID disk devices on GNU/Linux.
* Remove `grub-mkisofs'. `grub-mkrescue' now uses GNU xorriso to build
CD images.
* `grub-mkrescue' support for EFI, coreboot, and QEMU platforms.
* Unify `grub-mkimage' source code across platforms.
* Fix VGA (as opposed to VBE) video driver, formerly a terminal driver.
* Add menu hotkey support.
* Add support for the nilfs2 filesystem.
* `grub-probe' and `grub-mkconfig' support for NetBSD.
* Support setting a background image in `grub-mkconfig'.
* Support multiple terminals in `grub-mkconfig'.
* Regexp support.
* MIPS multiboot2 support.
* Multiboot2 tag support.
* sunpc partition table support.
* Add a number of new language features to GRUB script: `for', `while',
`until', `elif', function parameters, `break', `continue', and
`shift'.
* Support nested partition tables. GRUB now prefers to name partitions
in the form `(hd0,msdos1,bsd1)' rather than `(hd0,1,a)'.
* Speed up consecutive hostdisk operations on the same device.
* Compile parts of `grub-emu' as modules.
New in 1.98 - 2010-03-06:
* Multiboot on EFI support.

View file

@ -1,8 +1,10 @@
# -*- makefile -*-
CFLAGS_PLATFORM=
# Platform specific options
if COND_i386_pc
CFLAGS_PLATFORM = -mrtd -mregparm=3
CFLAGS_PLATFORM += -mrtd -mregparm=3
endif
if COND_i386_efi
LDFLAGS_PLATFORM = -melf_i386
@ -11,21 +13,24 @@ if COND_x86_64_efi
LDFLAGS_PLATFORM = -melf_x86_64
endif
if COND_i386_qemu
CFLAGS_PLATFORM = -mrtd -mregparm=3
CFLAGS_PLATFORM += -mrtd -mregparm=3
endif
if COND_i386_coreboot
CFLAGS_PLATFORM = -mrtd -mregparm=3
CFLAGS_PLATFORM += -mrtd -mregparm=3
endif
if COND_i386_ieee1275
CFLAGS_PLATFORM = -mrtd -mregparm=3
CFLAGS_PLATFORM += -mrtd -mregparm=3
endif
if COND_mips_yeeloong
CFLAGS_PLATFORM = -march=mips3 -mexplicit-relocs -mflush-func=grub_cpu_flush_cache
CFLAGS_PLATFORM += -march=mips3 -mexplicit-relocs
CPPFLAGS_PLATFORM = -DUSE_ASCII_FAILBACK
CCASFLAGS_PLATFORM = -march=mips3
endif
if COND_mips
CFLAGS_PLATFORM += -mflush-func=grub_cpu_flush_cache
endif
if COND_sparc64_ieee1275
CFLAGS_PLATFORM = -mno-app-regs
CFLAGS_PLATFORM += -mno-app-regs
LDFLAGS_PLATFORM = -melf64_sparc -mno-relax
endif
@ -115,6 +120,7 @@ pkglib_SCRIPTS =
noinst_PROGRAMS =
grubconf_SCRIPTS =
noinst_LIBRARIES =
dist_noinst_DATA =
TESTS =
EXTRA_DIST =

View file

@ -5,6 +5,11 @@ EXTRA_DIST += gentpl.py
EXTRA_DIST += Makefile.tpl
EXTRA_DIST += Makefile.util.def
EXTRA_DIST += unicode
EXTRA_DIST += util/import_gcry.py
EXTRA_DIST += util/import_unicode.py
EXTRA_DIST += docs/man
EXTRA_DIST += docs/grub.cfg
@ -26,8 +31,8 @@ EXTRA_DIST += grub-core/genterminallist.sh
EXTRA_DIST += grub-core/genparttoollist.sh
EXTRA_DIST += grub-core/genemuinitheader.sh
EXTRA_DIST += grub-core/lib/libgcrypt/cipher
EXTRA_DIST += $(shell find $(top_srcdir)/include -name '*.h')
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/gnulib -name '*.h')
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/efiemu -name '*.h')
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib/posix_wrap -name '*.h')
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib/libgcrypt_wrap -name '*.h')
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib -name '*.h')

View file

@ -176,6 +176,19 @@ AC_SUBST(host_kernel)
AC_SUBST(target_cpu)
AC_SUBST(platform)
# Define default variables
case "$host_os" in
netbsd* | openbsd*)
# Because /boot is used for the boot block in NetBSD and OpenBSD,
bootdirname='' ;;
*) bootdirname='boot' ;;
esac
bootdirname=`echo "$bootdirname" | sed "$program_transform_name"`
AC_SUBST(bootdirname)
grubdirname=`echo "$PACKAGE" | sed "$program_transform_name"`
AC_SUBST(grubdirname)
#
# Checks for build programs.
#
@ -264,8 +277,16 @@ else
fi
# Check for functions and headers.
AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf)
AC_CHECK_HEADERS(libzfs.h libnvpair.h sys/param.h sys/mount.h)
AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf getextmntent)
AC_CHECK_HEADERS(libzfs.h libnvpair.h sys/param.h sys/mount.h sys/mnttab.h sys/mkdev.h)
AC_CHECK_MEMBERS([struct statfs.f_fstypename],,,[$ac_includes_default
#include <sys/param.h>
#include <sys/mount.h>])
AC_CHECK_MEMBERS([struct statfs.f_mntfromname],,,[$ac_includes_default
#include <sys/param.h>
#include <sys/mount.h>])
# For opendisk() and getrawpartition() on NetBSD.
# Used in util/deviceiter.c and in util/hostdisk.c.
@ -762,19 +783,6 @@ AC_SUBST([enable_grub_emu_usb])
AC_SUBST([enable_grub_emu_pci])
fi
AC_ARG_ENABLE([grub-fstest],
[AS_HELP_STRING([--enable-grub-fstest],
[build and install the `grub-fstest' debugging utility (default=guessed)])])
if test x"$enable_grub_fstest" = xno ; then
grub_fstest_excuse="explicitly disabled"
fi
if test x"$grub_fstest_excuse" = x ; then
enable_grub_fstest=yes
else
enable_grub_fstest=no
fi
AC_SUBST([enable_grub_fstest])
AC_ARG_ENABLE([grub-mkfont],
[AS_HELP_STRING([--enable-grub-mkfont],
[build and install the `grub-mkfont' utility (default=guessed)])])
@ -822,12 +830,23 @@ fi
if test x"$device_mapper_excuse" = x ; then
# Check for device-mapper library.
AC_CHECK_LIB([devmapper], [dm_task_create],
[LIBDEVMAPPER="-ldevmapper"
AC_DEFINE([HAVE_DEVICE_MAPPER], [1],
[Define to 1 if you have the devmapper library.])],
AC_CHECK_LIB([devmapper], [dm_task_create], [],
[device_mapper_excuse="need devmapper library"])
fi
if test x"$device_mapper_excuse" = x ; then
# Check for device-mapper library.
AC_CHECK_LIB([devmapper], [dm_log_with_errno_init],
[],
[device_mapper_excuse="need devmapper library"])
fi
if test x"$device_mapper_excuse" = x ; then
LIBDEVMAPPER="-ldevmapper";
AC_DEFINE([HAVE_DEVICE_MAPPER], [1],
[Define to 1 if you have the devmapper library.])
fi
AC_SUBST([LIBDEVMAPPER])
AC_CHECK_LIB([zfs], [libzfs_init],
@ -842,6 +861,8 @@ AC_CHECK_LIB([nvpair], [nvlist_print],
[Define to 1 if you have the NVPAIR library.])],)
AC_SUBST([LIBNVPAIR])
LIBS=""
pkglibrootdir='$(libdir)'/`echo $PACKAGE | sed "$program_transform_name"`
AC_SUBST(pkglibrootdir)
@ -879,6 +900,7 @@ AM_CONDITIONAL([COND_mips_yeeloong], [test x$target_cpu = xmips -a x$platform =
AM_CONDITIONAL([COND_mips_qemu_mips], [test x$target_cpu = xmips -a x$platform = xqemu_mips])
AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platform = xieee1275])
AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platform = xieee1275])
AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips])
AM_CONDITIONAL([COND_HOST_HURD], [test x$host_kernel = xhurd])
AM_CONDITIONAL([COND_HOST_LINUX], [test x$host_kernel = xlinux])
@ -892,7 +914,6 @@ AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test x$enable_grub_emu_sdl = xyes])
AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes])
AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes])
AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x])
AM_CONDITIONAL([COND_GRUB_FSTEST], [test x$enable_grub_fstest = xyes])
AM_CONDITIONAL([COND_GRUB_PE2ELF], [test x$TARGET_OBJ2ELF != x])
AM_CONDITIONAL([COND_APPLE_CC], [test x$TARGET_APPLE_CC = x1])
AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes])
@ -942,6 +963,11 @@ else
echo PCI support for grub-emu: No "($grub_emu_pci_excuse)"
fi
fi
if test x"$device_mapper_excuse" = x ; then
echo With devmapper support: Yes
else
echo With devmapper support: No "($device_mapper_excuse)"
fi
if [ x"$enable_mm_debug" = xyes ]; then
echo With memory debugging: Yes
else
@ -952,11 +978,6 @@ echo efiemu runtime: Yes
else
echo efiemu runtime: No "($efiemu_excuse)"
fi
if [ x"$grub_fstest_excuse" = x ]; then
echo grub-fstest: Yes
else
echo grub-fstest: No "($grub_fstest_excuse)"
fi
if [ x"$grub_mkfont_excuse" = x ]; then
echo grub-mkfont: Yes
else

View file

@ -46,6 +46,8 @@ Invariant Sections.
@subtitle The GRand Unified Bootloader, version @value{VERSION}, @value{UPDATED}.
@author Gordon Matzigkeit
@author Yoshinori K. Okuji
@author Colin Watson
@author Colin D. Bennett
@c The following two commands start the copyright page.
@page
@vskip 0pt plus 1filll
@ -77,6 +79,7 @@ This edition documents version @value{VERSION}.
* Installation:: Installing GRUB on your drive
* Booting:: How to boot different operating systems
* Configuration:: Writing your own configuration file
* Theme file format:: Format of GRUB theme files
* Network:: Downloading OS images from a network
* Serial terminal:: Using GRUB via a serial line
* Vendor power-on keys:: Changing GRUB behaviour on vendor power-on keys
@ -964,7 +967,6 @@ need to write the whole thing by hand.
* Simple configuration:: Recommended for most users
* Shell-like scripting:: For power users and developers
* Embedded configuration:: Embedding a configuration file into GRUB
* Themes:: Graphical menu themes
@end menu
@ -1126,7 +1128,6 @@ The image will be scaled if necessary to fit the screen.
@item GRUB_THEME
Set a theme for use with the @samp{gfxterm} graphical terminal.
@xref{Themes}.
@item GRUB_GFXPAYLOAD_LINUX
Set to @samp{text} to force the Linux kernel to boot in normal text mode,
@ -1226,8 +1227,10 @@ The @samp{$} character retains its special meaning within double quotes.
The backslash retains its special meaning only when followed by one of the
following characters: @samp{$}, @samp{"}, @samp{\}, or newline. A
backslash-newline pair is treated as a line continuation (that is, it is
removed from the input stream and effectively ignored). A double quote may
be quoted within double quotes by preceding it with a backslash.
removed from the input stream and effectively ignored@footnote{Currently a
backslash-newline pair within a variable name is not handled properly, so
use this feature with some care.}). A double quote may be quoted within
double quotes by preceding it with a backslash.
@heading Variable expansion
@ -1239,11 +1242,15 @@ which could be interpreted as part of the name.
Normal variable names begin with an alphabetic character, followed by zero
or more alphanumeric characters.
Positional variable names consist of one or more digits. These are reserved
for future expansion.
Positional variable names consist of one or more digits. They represent
parameters passed to function calls, with @samp{$1} representing the first
parameter, and so on.
The special variable name @samp{?} expands to the exit status of the most
recently executed command.
recently executed command. When positional variable names are active, other
special variable names @samp{@@}, @samp{*} and @samp{#} are defined and they
expand to all positional parameters with necessary quoting, positional
parameters without any quoting, and positional parameter count respectively.
@heading Comments
@ -1304,6 +1311,45 @@ the body.
@xref{menuentry}.
@end table
@heading Built-in Commands
Some built-in commands are also provided by GRUB script to help script
writers perform actions that are otherwise not possible. For example, these
include commands to jump out of a loop without fully completing it, etc.
@table @asis
@item break [@code{n}]
Exit from within a @code{for}, @code{while}, or @code{until} loop. If
@code{n} is specified, break @code{n} levels. @code{n} must be greater than
or equal to 1. If @code{n} is greater than the number of enclosing loops,
all enclosing loops are exited. The return value is 0 unless @code{n} is
not greater than or equal to 1.
@item continue [@code{n}]
Resume the next iteration of the enclosing @code{for}, @code{while} or
@code{until} loop. If @code{n} is specified, resume at the @code{n}th
enclosing loop. @code{n} must be greater than or equal to 1. If @code{n}
is greater than the number of enclosing loops, the last enclosing loop (the
@dfn{top-level} loop) is resumed. The return value is 0 unless @code{n} is
not greater than or equal to 1.
@item return [@code{n}]
Causes a function to exit with the return value specified by @code{n}. If
@code{n} is omitted, the return status is that of the last command executed
in the function body. If used outside a function the return status is
false.
@item shift [@code{n}]
The positional parameters from @code{n}+1 @dots{} are renamed to
@code{$1}@dots{}. Parameters represented by the numbers @code{$#} down to
@code{$#}-@code{n}+1 are unset. @code{n} must be a non-negative number less
than or equal to @code{$#}. If @code{n} is 0, no parameters are changed.
If @code{n} is not given, it is assumed to be 1. If @code{n} is greater
than @code{$#}, the positional parameters are not changed. The return
status is greater than zero if @code{n} is greater than @code{$#} or less
than zero; otherwise 0.
@end table
@node Embedded configuration
@section Embedding a configuration file into GRUB
@ -1372,9 +1418,372 @@ fi
The embedded configuration file may not contain menu entries directly, but
may only read them from elsewhere using @command{configfile}.
@node Theme file format
@chapter Theme file format
@section Introduction
The GRUB graphical menu supports themes that can customize the layout and
appearance of the GRUB boot menu. The theme is configured through a plain
text file that specifies the layout of the various GUI components (including
the boot menu, timeout progress bar, and text messages) as well as the
appearance using colors, fonts, and images. Example is available in docs/example_theme.txt
@section Theme Elements
@subsection Colors
Colors can be specified in several ways:
@itemize
@item HTML-style ``#RRGGBB'' or ``#RGB'' format, where *R*, *G*, and *B* are hexadecimal digits (e.g., ``#8899FF'')
@item as comma-separated decimal RGB values (e.g., ``128, 128, 255'')
@item with ``SVG 1.0 color names'' (e.g., ``cornflowerblue'') which must be specified in lowercase.
@end itemize
@subsection Fonts
The fonts GRUB uses ``PFF2 font format'' bitmap fonts. Fonts are specified
with full font names. Currently there is no
provision for a preference list of fonts, or deriving one font from another.
Fonts are loaded with the ``loadfont'' command in GRUB. To see the list of
loaded fonts, execute the ``lsfonts'' command. If there are too many fonts to
fit on screen, do ``set pager=1'' before executing ``lsfonts''.
@subsection Progress Bar
@float Figure, Pixmap-styled progress bar
@c @image{Theme_progress_bar,,,,.png}
@end float
@float Figure, Plain progress bar, drawn with solid color.
@c @image{Theme_progress_bar_filled,,,,.png}
@end float
Progress bars are used to display the remaining time before GRUB boots the
default menu entry. To create a progress bar that will display the remaining
time before automatic boot, simply create a ``progress_bar'' component with
the id ``__timeout__''. This indicates to GRUB that the progress bar should
be updated as time passes, and it should be made invisible if the countdown to
automatic boot is interrupted by the user.
Progress bars may optionally have text displayed on them. This is controlled
through the ``show_text'' property, which can be set to either ``true'' or
``false'' to control whether text is displayed. When GRUB is counting down to
automatic boot, the text informs the user of the number of seconds remaining.
@subsection Circular Progress Indicator
@c @image{Theme_circular_progress,,,,.png}
The circular progress indicator functions similarly to the progress bar. When
given an id of ``__timeout__'', GRUB updates the circular progress indicator's
value to indicate the time remaining. For the circular progress indicator,
there are two images used to render it: the *center* image, and the *tick*
image. The center image is rendered in the center of the component, while the
tick image is used to render each mark along the circumference of the
indicator.
@subsection Labels
Text labels can be placed on the boot screen. The font, color, and horizontal
alignment can be specified for labels. If a label is given the id
``__timeout__'', then the ``text'' property for that label is also updated
with a message informing the user of the number of seconds remaining until
automatic boot. This is useful in case you want the text displayed somewhere
else instead of directly on the progress bar.
@subsection Boot Menu
@c @image{Theme_boot_menu,,,,.png}
The boot menu where GRUB displays the menu entries from the ``grub.cfg'' file.
It is a list of items, where each item has a title and an optional icon. The
icon is selected based on the *classes* specified for the menu entry. If
there is a PNG file named ``myclass.png'' in the ``grub/themes/icons''
directory, it will be displayed for items which have the class *myclass*. The
boot menu can be customized in several ways, such as the font and color used
for the menu entry title, and by specifying styled boxes for the menu itself
and for the selected item highlight.
@subsection Styled Boxes
One of the most important features for customizing the layout is the use of
*styled boxes*. A styled box is composed of 9 rectangular (and potentially
empty) regions, which are used to seamlessly draw the styled box on screen:
@multitable @columnfractions 0.3 0.3 0.3
@item Northwest (nw) @tab North (n) @tab Northeast (ne)
@item West (w) @tab Center (c) @tab East (e)
@item Southwest (sw) @tab South (s) @tab Southeast (se)
@end multitable
To support any size of box on screen, the center slice and the slices for the
top, bottom, and sides are all scaled to the correct size for the component on
screen, using the following rules:
@enumerate
@item The edge slices (north, south, east, and west) are scaled in the direction of the edge they are adjacent to. For instance, the west slice is scaled vertically.
@item The corner slices (northwest, northeast, southeast, and southwest) are not scaled.
@item The center slice is scaled to fill the remaining space in the middle.
@end enumerate
As an example of how an image might be sliced up, consider the styled box
used for a terminal view.
@float Figure, An example of the slices (in red) used for a terminal window. This drawing was created and sliced in Inkscape_, as the next section explains.
@c @image{Box_slice_example_terminal,,,,.png}
@end float
@subsection Creating Styled Box Images
The Inkscape_ scalable vector graphics editor is a very useful tool for
creating styled box images. One process that works well for slicing a drawing
into the necessary image slices is:
@enumerate
@item Create or open the drawing you'd like use.
@item Create a new layer on the top of the layer stack. Make it visible. Select this layer as the current layer.
@item Draw 9 rectangles on your drawing where you'd like the slices to be. Clear the fill option, and set the stroke to 1 pixel wide solid stroke. The corners of the slices must meet precisely; if it is off by a single pixel, it will probably be evident when the styled box is rendered in the GRUB menu. You should probably go to File | Document Properties | Grids and enable a grid or create a guide (click on one of the rulers next to the drawing and drag over the drawing; release the mouse button to place the guide) to help place the rectangles precisely.
@item Right click on the center slice rectangle and choose Object Properties. Change the "Id" to ``slice_c`` and click Set. Repeat this for the remaining 8 rectangles, giving them Id values of ``slice_n``, ``slice_ne``, ``slice_e``, and so on according to the location.
@item Save the drawing.
@item Select all the slice rectangles. With the slice layer selected, you can simply press Ctrl+A to select all rectangles. The status bar should indicate that 9 rectangles are selected.
@item Click the layer hide icon for the slice layer in the layer palette. The rectangles will remain selected, even though they are hidden.
@item Choose File | Export Bitmap and check the *Batch export 9 selected objects* box. Make sure that *Hide all except selected* is unchecked. click *Export*. This will create PNG files in the same directory as the drawing, named after the slices. These can now be used for a styled box in a GRUB theme.
@end enumerate
@section Theme File Manual
The theme file is a plain text file. Lines that begin with ``#`` are ignored
and considered comments. (Note: This may not be the case if the previous line
ended where a value was expected.)
The theme file contains two types of statements:
@enumerate
@item Global properties.
@item Component construction.
@end enumerate
@subsection Global Properties
@subsection Format
Global properties are specified with the simple format:
@itemize
@item name1: value1
@item name2: "value which may contain spaces"
@item name3: #88F
@end itemize
In this example, name3 is assigned a color value.
@subsection Global Property List
@multitable @columnfractions 0.3 0.6
@item title-text @tab Specifies the text to display at the top center of the screen as a title.
@item title-font @tab Defines the font used for the title message at the top of the screen.
@item title-color @tab Defines the color of the title message.
@item message-font @tab Defines the font used for messages, such as when GRUB is unable to automatically boot an entry.
@item message-color @tab Defines the color of the message text.
@item message-bg-color @tab Defines the background color of the message text area.
@item desktop-image @tab Specifies the image to use as the background. It will be scaled to fit the screen size.
@item desktop-color @tab Specifies the color for the background if *desktop-image* is not specified.
@item terminal-box @tab Specifies the file name pattern for the styled box slices used for the command line terminal window. For example, ``terminal-box: terminal_*.png'' will use the images ``terminal_c.png`` as the center area, ``terminal_n.png`` as the north (top) edge, ``terminal_nw.png`` as the northwest (upper left) corner, and so on. If the image for any slice is not found, it will simply be left empty.
@end multitable
@subsection Component Construction
Greater customizability comes is provided by components. A tree of components
forms the user interface. *Containers* are components that can contain other
components, and there is always a single root component which is an instance
of a *canvas* container.
Components are created in the theme file by prefixing the type of component
with a '+' sign:
@code{ + label @{ text="GRUB" font="aqui 11" color="#8FF" @} }
properties of a component are specified as "name = value" (whitespace
surrounding tokens is optional and is ignored) where *value* may be:
@itemize
@item a single word (e.g., ``align = center``, ``color = #FF8080``),
@item a quoted string (e.g., ``text = "Hello, World!"``), or
@item a tuple (e.g., ``preferred_size = (120, 80)``).
@end itemize
@subsection Component List
The following is a list of the components and the properties they support.
@itemize
@item label
A label displays a line of text.
Properties:
@multitable @columnfractions 0.2 0.7
@item text @tab The text to display.
@item font @tab The font to use for text display.
@item color @tab The color of the text.
@item align @tab The horizontal alignment of the text within the component. Options are ``left``, ``center``, and ``right``.
@end multitable
@item image
A component that displays an image. The image is scaled to fit the
component, although the preferred size defaults to the image's original
size unless the ``preferred_size`` property is explicitly set.
Properties:
@multitable @columnfractions 0.2 0.7
@item file @tab The full path to the image file to load.
@end multitable
@item progress_bar
Displays a horizontally oriented progress bar. It can be rendered using
simple solid filled rectangles, or using a pair of pixmap styled boxes.
Properties:
@multitable @columnfractions 0.2 0.7
@item fg_color @tab The foreground color for plain solid color rendering.
@item bg_color @tab The background color for plain solid color rendering.
@item border_color @tab The border color for plain solid color rendering.
@item text_color @tab The text color.
@item show_text @tab Boolean value indicating whether or not text should be displayed on the progress bar. If set to *false*, then no text will be displayed on the bar. If set to any other value, text will be displayed on the bar.
@item bar_style @tab The styled box specification for the frame of the progress bar. Example: ``progress_frame_*.png``
@item highlight_style @tab The styled box specification for the highlighted region of the progress bar. This box will be used to paint just the highlighted region of the bar, and will be increased in size as the bar nears completion. Example: ``progress_hl_*.png``.
@item text @tab The text to display on the progress bar. If the progress bar's ID is set to ``__timeout__``, then GRUB will updated this property with an informative message as the timeout approaches.
@item value @tab The progress bar current value. Normally not set manually.
@item start @tab The progress bar start value. Normally not set manually.
@item end @tab The progress bar end value. Normally not set manually.
@end multitable
@item circular_progress
Displays a circular progress indicator. The appearance of this component
is determined by two images: the *center* image and the *tick* image. The
center image is generally larger and will be drawn in the center of the
component. Around the circumference of a circle within the component, the
tick image will be drawn a certain number of times, depending on the
properties of the component.
Properties:
@multitable @columnfractions 0.3 0.6
@item center_bitmap
@tab The file name of the image to draw in the center of the component.
@item tick_bitmap
@tab The file name of the image to draw for the tick marks.
@item num_ticks
@tab The number of ticks that make up a full circle.
@item ticks_disappear
@tab Boolean value indicating whether tick marks should progressively appear,
or progressively disappear as *value* approaches *end*. Specify
``true`` or ``false``.
@item value
@tab The progress indicator current value. Normally not set manually.
@item start
@tab The progress indicator start value. Normally not set manually.
@item end
@tab The progress indicator end value. Normally not set manually.
@end multitable
@item boot_menu
Displays the GRUB boot menu. It allows selecting items and executing them.
Properties:
@multitable @columnfractions 0.4 0.5
@item item_font
@tab The font to use for the menu item titles.
@item selected_item_font
@tab The font to use for the selected menu item, or ``inherit`` (the default)
to use ``item_font`` for the selected menu item as well.
@item item_color
@tab The color to use for the menu item titles.
@item selected_item_color
@tab The color to use for the selected menu item, or ``inherit`` (the default)
to use ``item_color`` for the selected menu item as well.
@item icon_width
@tab The width of menu item icons. Icons are scaled to the specified size.
@item icon_height
@tab The height of menu item icons.
@item item_height
@tab The height of each menu item in pixels.
@item item_padding
@tab The amount of space in pixels to leave on each side of the menu item
contents.
@item item_icon_space
@tab The space between an item's icon and the title text, in pixels.
@item item_spacing
@tab The amount of space to leave between menu items, in pixels.
@item menu_pixmap_style
@tab The image file pattern for the menu frame styled box.
Example: ``menu_*.png`` (this will use images such as ``menu_c.png``,
``menu_w.png``, `menu_nw.png``, etc.)
@item selected_item_pixmap_style
@tab The image file pattern for the selected item highlight styled box.
@item scrollbar
@tab Boolean value indicating whether the scroll bar should be drawn if the
frame and thumb styled boxes are configured.
@item scrollbar_frame
@tab The image file pattern for the entire scroll bar.
Example: ``scrollbar_*.png``
@item scrollbar_thumb
@tab The image file pattern for the scroll bar thumb (the part of the scroll
bar that moves as scrolling occurs).
Example: ``scrollbar_thumb_*.png``
@item max_items_shown
@tab The maximum number of items to show on the menu. If there are more than
*max_items_shown* items in the menu, the list will scroll to make all
items accessible.
@end multitable
@item canvas
Canvas is a container that allows manual placement of components within it.
It does not alter the positions of its child components. It assigns all
child components their preferred sizes.
@item hbox
The *hbox* container lays out its children from left to right, giving each
one its preferred width. The height of each child is set to the maximum of
the preferred heights of all children.
@item vbox
The *vbox* container lays out its children from top to bottom, giving each
one its preferred height. The width of each child is set to the maximum of
the preferred widths of all children.
@end itemize
@subsection Common properties
The following properties are supported by all components:
@table @samp
@item left
The distance from the left border of container to left border of the object in either of three formats:
@multitable @columnfractions 0.2 0.7
@item x @tab Value in pixels
@item p% @tab Percentage
@item p%+x @tab mixture of both
@end multitable
@item top
The distance from the left border of container to left border of the object in same format.
@item width
The width of object in same format.
@item height
The height of object in same format.
@item id
The identifier for the component. This can be any arbitrary string.
The ID can be used by scripts to refer to various components in the GUI
component tree. Currently, there is one special ID value that GRUB
recognizes:
@multitable @columnfractions 0.2 0.7
@item ``__timeout__`` @tab Any component with this ID will have its *text*, *start*, *end*, *value*, and *visible* properties set by GRUB when it is counting down to an automatic boot of the default menu entry.
@end multitable
@end table
@node Themes
@section Graphical menu themes
@node Network

View file

@ -478,7 +478,7 @@ chmod a+x [+ name +]
""")
r += gvar_add("CLEANFILES", "[+ name +]")
r += gvar_add("EXTRA_DIST", platform_sources(platform))
r += gvar_add("dist_noinst_DATA", platform_sources(platform))
return r
def module_rules():

View file

@ -74,6 +74,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h
if COND_i386_pc
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h
@ -132,7 +133,6 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/font.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bitmap_scale.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bufio.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cs5536.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pci.h
KERNEL_HEADER_FILES += $(top_builddir)/include/grub/serial.h
@ -140,11 +140,9 @@ endif
if COND_powerpc_ieee1275
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h
endif
if COND_sparc64_ieee1275
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sparc64/ieee1275/ieee1275.h
endif

View file

@ -137,6 +137,7 @@ kernel = {
mips_yeeloong = term/at_keyboard.c;
mips_yeeloong = term/serial.c;
mips_yeeloong = video/sm712.c;
extra_dist = video/sm712_init.c;
powerpc_ieee1275 = kern/ieee1275/init.c;
powerpc_ieee1275 = kern/powerpc/cache.S;
@ -394,6 +395,7 @@ module = {
module = {
name = regexp;
common = commands/regexp.c;
common = commands/wildcard.c;
ldadd = libgnulib.a;
cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
@ -518,6 +520,7 @@ module = {
name = halt;
nopc = commands/halt.c;
i386_pc = commands/i386/pc/halt.c;
i386_pc = commands/acpihalt.c;
i386_multiboot = lib/i386/halt.c;
i386_coreboot = lib/i386/halt.c;
i386_qemu = lib/i386/halt.c;
@ -860,6 +863,11 @@ module = {
common = fs/befs_be.c;
};
module = {
name = btrfs;
common = fs/btrfs.c;
};
module = {
name = cpio;
common = fs/cpio.c;
@ -905,6 +913,11 @@ module = {
common = fs/minix.c;
};
module = {
name = minix2;
common = fs/minix2.c;
};
module = {
name = nilfs2;
common = fs/nilfs2.c;
@ -1036,6 +1049,9 @@ module = {
powerpc = lib/powerpc/relocator_asm.S;
powerpc = lib/powerpc/relocator.c;
extra_dist = lib/i386/relocator_common.S;
extra_dist = kern/powerpc/cache_flush.S;
enable = mips;
enable = powerpc;
enable = x86;
@ -1187,6 +1203,8 @@ module = {
common = script/lexer.c;
common = script/argv.c;
common = commands/menuentry.c;
common = unidata.c;
common_nodist = grub_script.tab.c;
common_nodist = grub_script.yy.c;
@ -1403,3 +1421,22 @@ module = {
name = datehook;
common = hook/datehook.c;
};
module = {
name = test_blockarg;
common = tests/test_blockarg.c;
};
module = {
name = xzio;
common = io/xzio.c;
common = lib/xzembed/xz_dec_bcj.c;
common = lib/xzembed/xz_dec_lzma2.c;
common = lib/xzembed/xz_dec_stream.c;
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed';
};
module = {
name = testload;
common = commands/testload.c;
};

View file

@ -185,7 +185,7 @@ real_code_2:
call LOCAL(move_memory)
/* Check for multiboot signature. */
cmpl $MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_DATA_END)
cmpl $MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE)
jz 1f
movl (ramdisk_image - start), %esi

View file

@ -23,7 +23,6 @@
#include <grub/disk.h>
#include <grub/term.h>
#include <grub/misc.h>
#include <grub/gzio.h>
#include <grub/acpi.h>
#include <grub/mm.h>
#include <grub/machine/memory.h>
@ -458,10 +457,9 @@ free_tables (void)
}
static grub_err_t
grub_cmd_acpi (struct grub_extcmd *cmd,
int argc, char **args)
grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
struct grub_acpi_rsdp_v10 *rsdp;
struct efiemu_acpi_table *cur, *t;
grub_err_t err;
@ -629,7 +627,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd,
grub_size_t size;
char *buf;
file = grub_gzfile_open (args[i], 1);
file = grub_file_open (args[i]);
if (! file)
{
free_tables ();

View file

@ -0,0 +1,266 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/acpi.h>
#include <grub/misc.h>
#include <grub/cpu/io.h>
static inline grub_uint32_t
decode_length (const grub_uint8_t *ptr, int *numlen)
{
int num_bytes, i;
grub_uint32_t ret;
if (*ptr < 64)
{
if (numlen)
*numlen = 1;
return *ptr;
}
num_bytes = *ptr >> 6;
if (numlen)
*numlen = num_bytes + 1;
ret = *ptr & 0xf;
ptr++;
for (i = 0; i < num_bytes; i++)
{
ret |= *ptr << (8 * i + 4);
ptr++;
}
return ret;
}
static inline grub_uint32_t
skip_name_string (const grub_uint8_t *ptr, const grub_uint8_t *end)
{
const grub_uint8_t *ptr0 = ptr;
while (ptr < end && (*ptr == '^' || *ptr == '\\'))
ptr++;
switch (*ptr)
{
case '.':
ptr++;
ptr += 8;
break;
case '/':
ptr++;
ptr += 1 + (*ptr) * 4;
break;
case 0:
ptr++;
break;
default:
ptr += 4;
break;
}
return ptr - ptr0;
}
static inline grub_uint32_t
skip_data_ref_object (const grub_uint8_t *ptr, const grub_uint8_t *end)
{
grub_dprintf ("acpi", "data type = 0x%x\n", *ptr);
switch (*ptr)
{
case GRUB_ACPI_OPCODE_PACKAGE:
return 1 + decode_length (ptr + 1, 0);
case GRUB_ACPI_OPCODE_ZERO:
case GRUB_ACPI_OPCODE_ONES:
case GRUB_ACPI_OPCODE_ONE:
return 1;
case GRUB_ACPI_OPCODE_BYTE_CONST:
return 2;
case GRUB_ACPI_OPCODE_WORD_CONST:
return 3;
case GRUB_ACPI_OPCODE_DWORD_CONST:
return 5;
default:
if (*ptr == '^' || *ptr == '\\' || *ptr == '_'
|| (*ptr >= 'A' && *ptr <= 'Z'))
return skip_name_string (ptr, end);
grub_printf ("Unknown opcode 0x%x\n", *ptr);
return 0;
}
}
static inline grub_uint32_t
skip_ext_op (const grub_uint8_t *ptr, const grub_uint8_t *end)
{
const grub_uint8_t *ptr0 = ptr;
int add;
grub_dprintf ("acpi", "Extended opcode: 0x%x\n", *ptr);
switch (*ptr)
{
case GRUB_ACPI_EXTOPCODE_MUTEX:
ptr++;
ptr += skip_name_string (ptr, end);
ptr++;
break;
case GRUB_ACPI_EXTOPCODE_OPERATION_REGION:
ptr++;
ptr += skip_name_string (ptr, end);
ptr++;
ptr += add = skip_data_ref_object (ptr, end);
if (!add)
return 0;
ptr += add = skip_data_ref_object (ptr, end);
if (!add)
return 0;
break;
case GRUB_ACPI_EXTOPCODE_FIELD_OP:
ptr++;
ptr += decode_length (ptr, 0);
break;
default:
grub_printf ("Unexpected extended opcode: 0x%x\n", *ptr);
return 0;
}
return ptr - ptr0;
}
static int
get_sleep_type (grub_uint8_t *table, grub_uint8_t *end)
{
grub_uint8_t *ptr, *prev;
int sleep_type = -1;
ptr = table + sizeof (struct grub_acpi_table_header);
while (ptr < end && prev < ptr)
{
int add;
prev = ptr;
grub_dprintf ("acpi", "Opcode %x\n", *ptr);
grub_dprintf ("acpi", "Tell %x\n", ptr - table);
switch (*ptr)
{
case GRUB_ACPI_OPCODE_EXTOP:
ptr++;
ptr += add = skip_ext_op (ptr, end);
if (!add)
return -1;
break;
case GRUB_ACPI_OPCODE_NAME:
ptr++;
if (memcmp (ptr, "_S5_", 4) == 0)
{
int ll;
grub_uint8_t *ptr2 = ptr;
ptr2 += 4;
if (*ptr2 != 0x12)
{
grub_printf ("Unknown opcode in _S5: 0x%x\n", *ptr2);
return -1;
}
ptr2++;
decode_length (ptr2, &ll);
ptr2 += ll;
ptr2++;
switch (*ptr2)
{
case GRUB_ACPI_OPCODE_ZERO:
sleep_type = 0;
break;
case GRUB_ACPI_OPCODE_ONE:
sleep_type = 1;
break;
case GRUB_ACPI_OPCODE_BYTE_CONST:
sleep_type = ptr2[1];
break;
default:
grub_printf ("Unknown data type in _S5: 0x%x\n", *ptr2);
return -1;
}
}
ptr += add = skip_name_string (ptr, end);
if (!add)
return -1;
ptr += add = skip_data_ref_object (ptr, end);
if (!add)
return -1;
break;
case GRUB_ACPI_OPCODE_SCOPE:
case GRUB_ACPI_OPCODE_IF:
case GRUB_ACPI_OPCODE_METHOD:
{
ptr++;
ptr += decode_length (ptr, 0);
break;
}
}
}
grub_dprintf ("acpi", "TYP = %d\n", sleep_type);
return sleep_type;
}
void
grub_acpi_halt (void)
{
struct grub_acpi_rsdp_v20 *rsdp2;
struct grub_acpi_rsdp_v10 *rsdp1;
struct grub_acpi_table_header *rsdt;
grub_uint32_t *entry_ptr;
rsdp2 = grub_acpi_get_rsdpv2 ();
if (rsdp2)
rsdp1 = &(rsdp2->rsdpv1);
else
rsdp1 = grub_acpi_get_rsdpv1 ();
grub_dprintf ("acpi", "rsdp1=%p\n", rsdp1);
if (!rsdp1)
return;
rsdt = (struct grub_acpi_table_header *) rsdp1->rsdt_addr;
for (entry_ptr = (grub_uint32_t *) (rsdt + 1);
entry_ptr < (grub_uint32_t *) (((grub_uint8_t *) rsdt)
+ rsdt->length);
entry_ptr++)
{
if (grub_memcmp ((void *)*entry_ptr, "FACP", 4) == 0)
{
grub_uint32_t port;
struct grub_acpi_fadt *fadt
= ((struct grub_acpi_fadt *) *entry_ptr);
struct grub_acpi_table_header *dsdt
= (struct grub_acpi_table_header *) fadt->dsdt_addr;
int sleep_type = -1;
port = fadt->pm1a;
grub_dprintf ("acpi", "PM1a port=%x\n", port);
if (grub_memcmp (dsdt->signature, "DSDT",
sizeof (dsdt->signature)) != 0)
break;
sleep_type = get_sleep_type ((grub_uint8_t *) dsdt,
(grub_uint8_t *) dsdt + dsdt->length);
if (sleep_type < 0 || sleep_type >= 8)
break;
grub_dprintf ("acpi", "SLP_TYP = %d, port = 0x%x\n",
sleep_type, port);
grub_outw (GRUB_ACPI_SLP_EN
| (sleep_type << GRUB_ACPI_SLP_TYP_OFFSET), port & 0xffff);
}
}
grub_printf ("ACPI shutdown failed\n");
}

View file

@ -82,6 +82,7 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)),
if (argc < 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
grub_file_filter_disable_compression ();
file = grub_file_open (args[0]);
if (! file)
return grub_errno;

View file

@ -22,7 +22,6 @@
#include <grub/disk.h>
#include <grub/term.h>
#include <grub/misc.h>
#include <grub/gzio.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
@ -33,9 +32,9 @@ static const struct grub_arg_option options[] =
};
static grub_err_t
grub_cmd_cat (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
int dos = 0;
grub_file_t file;
char buf[GRUB_DISK_SECTOR_SIZE];
@ -48,7 +47,7 @@ grub_cmd_cat (grub_extcmd_t cmd, int argc, char **args)
if (argc != 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
file = grub_gzfile_open (args[0], 1);
file = grub_file_open (args[0]);
if (! file)
return grub_errno;

View file

@ -21,7 +21,6 @@
#include <grub/misc.h>
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/gzio.h>
#include <grub/command.h>
#include <grub/i18n.h>
@ -44,8 +43,8 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)),
grub_printf ("Compare file `%s' with `%s':\n", args[0],
args[1]);
file1 = grub_gzfile_open (args[0], 1);
file2 = grub_gzfile_open (args[1], 1);
file1 = grub_file_open (args[0]);
file2 = grub_file_open (args[1]);
if (! file1 || ! file2)
goto cleanup;

View file

@ -38,6 +38,7 @@ grub_cmd_crc (grub_command_t cmd __attribute__ ((unused)),
if (argc != 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
grub_file_filter_disable_compression ();
file = grub_file_open (args[0]);
if (! file)
return 0;

View file

@ -30,9 +30,9 @@ static const struct grub_arg_option options[] =
};
static grub_err_t
grub_cmd_echo (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
int newline = 1;
int i;

View file

@ -21,46 +21,55 @@
#include <grub/list.h>
#include <grub/misc.h>
#include <grub/extcmd.h>
#include <grub/script_sh.h>
static grub_err_t
grub_extcmd_dispatcher (struct grub_command *cmd,
int argc, char **args)
grub_err_t
grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args,
struct grub_script *script)
{
int new_argc;
char **new_args;
struct grub_arg_option *parser;
struct grub_arg_list *state;
int maxargs = 0;
struct grub_extcmd_context context;
grub_err_t ret;
grub_extcmd_t ext;
grub_extcmd_t ext = cmd->data;
ext = cmd->data;
parser = (struct grub_arg_option *) ext->options;
while (parser && (parser++)->doc)
maxargs++;
context.state = 0;
context.extcmd = ext;
context.script = script;
/* Set up the option state. */
state = grub_zalloc (sizeof (struct grub_arg_list) * maxargs);
if (! ext->options)
{
ret = (ext->func) (&context, argc, args);
return ret;
}
state = grub_arg_list_alloc (ext, argc, args);
if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc))
{
ext->state = state;
ret = (ext->func) (ext, new_argc, new_args);
context.state = state;
ret = (ext->func) (&context, new_argc, new_args);
grub_free (new_args);
grub_free (state);
return ret;
}
else
ret = grub_errno;
grub_free (state);
return grub_errno;
}
return ret;
static grub_err_t
grub_extcmd_dispatch (struct grub_command *cmd, int argc, char **args)
{
return grub_extcmd_dispatcher (cmd, argc, args, 0);
}
grub_extcmd_t
grub_register_extcmd (const char *name, grub_extcmd_func_t func,
unsigned flags, const char *summary,
const char *description,
const struct grub_arg_option *parser)
grub_register_extcmd_prio (const char *name, grub_extcmd_func_t func,
unsigned flags, const char *summary,
const char *description,
const struct grub_arg_option *parser,
int prio)
{
grub_extcmd_t ext;
grub_command_t cmd;
@ -69,8 +78,8 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func,
if (! ext)
return 0;
cmd = grub_register_command_prio (name, grub_extcmd_dispatcher,
summary, description, 1);
cmd = grub_register_command_prio (name, grub_extcmd_dispatch,
summary, description, prio);
if (! cmd)
{
grub_free (ext);
@ -88,6 +97,16 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func,
return ext;
}
grub_extcmd_t
grub_register_extcmd (const char *name, grub_extcmd_func_t func,
unsigned flags, const char *summary,
const char *description,
const struct grub_arg_option *parser)
{
return grub_register_extcmd_prio (name, func, flags,
summary, description, parser, 1);
}
void
grub_unregister_extcmd (grub_extcmd_t ext)
{

View file

@ -32,6 +32,7 @@ static const struct grub_arg_option options[] = {
{"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIRECTORY"),
ARG_TYPE_STRING},
{"keep-going", 'k', 0, N_("Don't stop after first error."), 0, 0},
{"uncompress", 'u', 0, N_("Uncompress file before checksumming."), 0, 0},
{0, 0, 0, 0, 0, 0}
};
@ -80,7 +81,7 @@ hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result)
static grub_err_t
check_list (const gcry_md_spec_t *hash, const char *hashfilename,
const char *prefix, int keep)
const char *prefix, int keep, int uncompress)
{
grub_file_t hashlist, file;
char *buf = NULL;
@ -115,11 +116,17 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
filename = grub_xasprintf ("%s/%s", prefix, p);
if (!filename)
return grub_errno;
if (!uncompress)
grub_file_filter_disable_compression ();
file = grub_file_open (filename);
grub_free (filename);
}
else
file = grub_file_open (p);
{
if (!uncompress)
grub_file_filter_disable_compression ();
file = grub_file_open (p);
}
if (!file)
{
grub_file_close (hashlist);
@ -165,19 +172,20 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename,
}
static grub_err_t
grub_cmd_hashsum (struct grub_extcmd *cmd,
grub_cmd_hashsum (struct grub_extcmd_context *ctxt,
int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
const char *hashname = NULL;
const char *prefix = NULL;
const gcry_md_spec_t *hash;
unsigned i;
int keep = state[3].set;
int uncompress = state[4].set;
unsigned unread = 0;
for (i = 0; i < ARRAY_SIZE (aliases); i++)
if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0)
if (grub_strcmp (ctxt->extcmd->cmd->name, aliases[i].name) == 0)
hashname = aliases[i].hashname;
if (state[0].set)
hashname = state[0].arg;
@ -197,7 +205,7 @@ grub_cmd_hashsum (struct grub_extcmd *cmd,
if (argc != 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"--check is incompatible with file list");
return check_list (hash, state[1].arg, prefix, keep);
return check_list (hash, state[1].arg, prefix, keep, uncompress);
}
for (i = 0; i < (unsigned) argc; i++)
@ -206,6 +214,8 @@ grub_cmd_hashsum (struct grub_extcmd *cmd,
grub_file_t file;
grub_err_t err;
unsigned j;
if (!uncompress)
grub_file_filter_disable_compression ();
file = grub_file_open (args[i]);
if (!file)
{

View file

@ -270,9 +270,9 @@ static int get_int_arg (const struct grub_arg_list *state)
}
static grub_err_t
grub_cmd_hdparm (grub_extcmd_t cmd, int argc, char **args) // state????
grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state????
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
/* Check command line. */
if (argc != 1)

View file

@ -27,7 +27,7 @@
#include <grub/charset.h>
static grub_err_t
grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc,
grub_cmd_help (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc,
char **args)
{
int cnt = 0;
@ -112,7 +112,8 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc,
if (cnt++ > 0)
grub_printf ("\n\n");
if (cmd->flags & GRUB_COMMAND_FLAG_EXTCMD)
if ((cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) &&
! (cmd->flags & GRUB_COMMAND_FLAG_DYNCMD))
grub_arg_show_help ((grub_extcmd_t) cmd->data);
else
grub_printf ("%s %s %s\n%s\n", _("Usage:"), cmd->name, _(cmd->summary),

View file

@ -21,7 +21,6 @@
#include <grub/file.h>
#include <grub/disk.h>
#include <grub/misc.h>
#include <grub/gzio.h>
#include <grub/lib/hexdump.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
@ -34,9 +33,9 @@ static const struct grub_arg_option options[] = {
};
static grub_err_t
grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
char buf[GRUB_DISK_SECTOR_SIZE * 4];
grub_ssize_t size, length;
grub_disk_addr_t skip;
@ -89,7 +88,7 @@ grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args)
{
grub_file_t file;
file = grub_gzfile_open (args[0], 1);
file = grub_file_open (args[0]);
if (! file)
return 0;

View file

@ -43,7 +43,7 @@ static const struct grub_arg_option options[] =
unsigned char grub_cpuid_has_longmode = 0;
static grub_err_t
grub_cmd_cpuid (grub_extcmd_t cmd __attribute__ ((unused)),
grub_cmd_cpuid (grub_extcmd_context_t ctxt __attribute__ ((unused)),
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{

View file

@ -196,13 +196,13 @@ list_mappings (void)
}
static grub_err_t
grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args)
grub_cmd_drivemap (struct grub_extcmd_context *ctxt, int argc, char **args)
{
if (cmd->state[OPTIDX_LIST].set)
if (ctxt->state[OPTIDX_LIST].set)
{
return list_mappings ();
}
else if (cmd->state[OPTIDX_RESET].set)
else if (ctxt->state[OPTIDX_RESET].set)
{
/* Reset: just delete all mappings, freeing their memory. */
drivemap_node_t *curnode = map_head;
@ -216,7 +216,7 @@ grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args)
map_head = 0;
return GRUB_ERR_NONE;
}
else if (!cmd->state[OPTIDX_SWAP].set && argc == 0)
else if (!ctxt->state[OPTIDX_SWAP].set && argc == 0)
{
/* No arguments */
return list_mappings ();
@ -248,11 +248,11 @@ grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args)
}
/* Set the mapping for the disk (overwrites any existing mapping). */
grub_dprintf ("drivemap", "%s %s (%02x) = %s (%02x)\n",
cmd->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping",
ctxt->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping",
args[1], mapto, args[0], mapfrom);
err = drivemap_set (mapto, mapfrom);
/* If -s, perform the reverse mapping too (only if the first was OK). */
if (cmd->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE)
if (ctxt->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE)
err = drivemap_set (mapfrom, mapto);
return err;
}

View file

@ -22,6 +22,7 @@
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/machine/int.h>
#include <grub/acpi.h>
static const struct grub_arg_option options[] =
{
@ -93,13 +94,16 @@ grub_halt (int no_apm)
}
static grub_err_t
grub_cmd_halt (grub_extcmd_t cmd,
grub_cmd_halt (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
int no_apm = 0;
grub_acpi_halt ();
if (state[0].set)
no_apm = 1;
grub_halt (no_apm);

View file

@ -284,9 +284,9 @@ grub_sendkey_preboot (int noret __attribute__ ((unused)))
}
static grub_err_t
grub_cmd_sendkey (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_sendkey (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
auto int find_key_code (char *key);
auto int find_ascii_code (char *key);

View file

@ -36,7 +36,7 @@ static const struct grub_arg_option options[] =
static grub_err_t
grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **argv)
{
grub_target_addr_t addr;
grub_uint32_t value = 0;
@ -46,7 +46,7 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments");
addr = grub_strtoul (argv[0], 0, 0);
switch (cmd->cmd->name[sizeof ("in") - 1])
switch (ctxt->extcmd->cmd->name[sizeof ("in") - 1])
{
case 'l':
value = grub_inl (addr);
@ -61,10 +61,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
break;
}
if (cmd->state[0].set)
if (ctxt->state[0].set)
{
grub_snprintf (buf, sizeof (buf), "%x", value);
grub_env_set (cmd->state[0].arg, buf);
grub_env_set (ctxt->state[0].arg, buf);
}
else
grub_printf ("0x%x\n", value);

View file

@ -34,11 +34,11 @@ static const struct grub_arg_option options[] =
#define grub_cur_term_input grub_term_get_current_input ()
static grub_err_t
grub_cmd_keystatus (grub_extcmd_t cmd,
grub_cmd_keystatus (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
int expect_mods = 0;
int mods;

View file

@ -56,6 +56,7 @@ open_envblk_file (char *filename)
grub_strcpy (filename, prefix);
filename[len] = '/';
grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG);
grub_file_filter_disable_compression ();
file = grub_file_open (filename);
grub_free (filename);
return file;
@ -67,6 +68,7 @@ open_envblk_file (char *filename)
}
}
grub_file_filter_disable_compression ();
return grub_file_open (filename);
}
@ -111,11 +113,11 @@ read_envblk_file (grub_file_t file)
}
static grub_err_t
grub_cmd_load_env (grub_extcmd_t cmd,
grub_cmd_load_env (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
grub_file_t file;
grub_envblk_t envblk;
@ -143,11 +145,11 @@ grub_cmd_load_env (grub_extcmd_t cmd,
}
static grub_err_t
grub_cmd_list_env (grub_extcmd_t cmd,
grub_cmd_list_env (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
grub_file_t file;
grub_envblk_t envblk;
@ -280,9 +282,9 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
}
static grub_err_t
grub_cmd_save_env (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
grub_file_t file;
grub_envblk_t envblk;
struct blocklist *head = 0;

View file

@ -105,6 +105,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
/* XXX: For ext2fs symlinks are detected as files while they
should be reported as directories. */
grub_file_filter_disable_compression ();
file = grub_file_open (pathname);
if (! file)
{
@ -211,6 +212,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
struct grub_dirhook_info info;
grub_errno = 0;
grub_file_filter_disable_compression ();
file = grub_file_open (dirname);
if (! file)
goto fail;
@ -248,9 +250,9 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
}
static grub_err_t
grub_cmd_ls (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_ls (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
if (argc == 0)
grub_ls_list_devices (state[0].set);

View file

@ -211,11 +211,11 @@ grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid)
}
static grub_err_t
grub_cmd_lspci (grub_extcmd_t cmd,
grub_cmd_lspci (grub_extcmd_context_t ctxt,
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{
iospace = cmd->state[0].set;
iospace = ctxt->state[0].set;
grub_pci_iterate (grub_lspci_iter);
return GRUB_ERR_NONE;
}

View file

@ -35,7 +35,7 @@ static const struct grub_arg_option options[] =
static grub_err_t
grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **argv)
{
grub_target_addr_t addr;
grub_uint32_t value = 0;
@ -45,7 +45,7 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments");
addr = grub_strtoul (argv[0], 0, 0);
switch (cmd->cmd->name[sizeof ("read_") - 1])
switch (ctxt->extcmd->cmd->name[sizeof ("read_") - 1])
{
case 'd':
value = *((volatile grub_uint32_t *) addr);
@ -60,10 +60,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv)
break;
}
if (cmd->state[0].set)
if (ctxt->state[0].set)
{
grub_snprintf (buf, sizeof (buf), "%x", value);
grub_env_set (cmd->state[0].arg, buf);
grub_env_set (ctxt->state[0].arg, buf);
}
else
grub_printf ("0x%x\n", value);

View file

@ -0,0 +1,285 @@
/* menuentry.c - menuentry command */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/normal.h>
static const struct grub_arg_option options[] =
{
{"class", 1, GRUB_ARG_OPTION_REPEATABLE,
N_("Menu entry type."), "STRING", ARG_TYPE_STRING},
{"users", 2, 0,
N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING},
{"hotkey", 3, 0,
N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING},
{"source", 4, 0,
N_("Menu entry definition as a string."), "STRING", ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
static struct
{
char *name;
int key;
} hotkey_aliases[] =
{
{"backspace", '\b'},
{"tab", '\t'},
{"delete", GRUB_TERM_DC}
};
/* Add a menu entry to the current menu context (as given by the environment
variable data slot `menu'). As the configuration file is read, the script
parser calls this when a menu entry is to be created. */
static grub_err_t
append_menu_entry (int argc, const char **args, char **classes,
const char *users, const char *hotkey,
const char *prefix, const char *sourcecode)
{
unsigned i;
int menu_hotkey = 0;
char **menu_args = NULL;
char *menu_users = NULL;
char *menu_title = NULL;
char *menu_sourcecode = NULL;
struct grub_menu_entry_class *menu_classes = NULL;
grub_menu_t menu;
grub_menu_entry_t *last;
menu = grub_env_get_menu ();
if (! menu)
return grub_error (GRUB_ERR_MENU, "no menu context");
last = &menu->entry_list;
menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode);
if (! menu_sourcecode)
return grub_errno;
if (classes)
{
for (i = 0; classes[i]; i++); /* count # of menuentry classes */
menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class) * i);
if (! menu_classes)
goto fail;
for (i = 0; classes[i]; i++)
{
menu_classes[i].name = grub_strdup (classes[i]);
if (! menu_classes[i].name)
goto fail;
menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
}
}
if (users)
{
menu_users = grub_strdup (users);
if (! menu_users)
goto fail;
}
if (hotkey)
{
for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
{
menu_hotkey = hotkey_aliases[i].key;
break;
}
if (i == ARRAY_SIZE (hotkey_aliases))
menu_hotkey = hotkey[0];
}
if (! argc)
{
grub_error (GRUB_ERR_MENU, "menuentry is missing title");
goto fail;
}
menu_title = grub_strdup (args[0]);
if (! menu_title)
goto fail;
/* Save argc, args to pass as parameters to block arg later. */
menu_args = grub_malloc (sizeof (char*) * (argc + 1));
if (! menu_args)
goto fail;
for (i = 0; args[i]; i++)
{
menu_args[i] = grub_strdup (args[i]);
if (! menu_args[i])
goto fail;
}
menu_args[argc] = NULL;
/* Add the menu entry at the end of the list. */
while (*last)
last = &(*last)->next;
*last = grub_zalloc (sizeof (**last));
if (! *last)
goto fail;
(*last)->title = menu_title;
(*last)->hotkey = menu_hotkey;
(*last)->classes = menu_classes;
if (menu_users)
(*last)->restricted = 1;
(*last)->users = menu_users;
(*last)->argc = argc;
(*last)->args = menu_args;
(*last)->sourcecode = menu_sourcecode;
menu->size++;
return GRUB_ERR_NONE;
fail:
grub_free (menu_sourcecode);
for (i = 0; menu_classes && menu_classes[i].name; i++)
grub_free (menu_classes[i].name);
grub_free (menu_classes);
for (i = 0; menu_args && menu_args[i]; i++)
grub_free (menu_args[i]);
grub_free (menu_args);
grub_free (menu_users);
grub_free (menu_title);
return grub_errno;
}
static char *
setparams_prefix (int argc, char **args)
{
int i;
int j;
char *p;
char *result;
grub_size_t len = 10;
static const char *escape_characters = "\"\\";
auto char *strescpy (char *, const char *, const char *);
char * strescpy (char *d, const char *s, const char *escapes)
{
while (*s)
{
if (grub_strchr (escapes, *s))
*d++ = '\\';
*d++ = *s++;
}
*d = '\0';
return d;
}
/* Count resulting string length */
for (i = 0; i < argc; i++)
{
len += 3; /* 3 = 1 space + 2 quotes */
p = args[i];
while (*p)
len += grub_strchr (escape_characters, *p++) ? 2 : 1;
}
result = grub_malloc (len + 2);
if (! result)
return 0;
grub_strcpy (result, "setparams");
i = 9;
for (j = 0; j < argc; j++)
{
result[i++] = ' ';
result[i++] = '"';
i = strescpy (result + i, args[j], escape_characters) - result;
result[i++] = '"';
}
result[i++] = '\n';
result[i] = '\0';
return result;
}
static grub_err_t
grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
{
char ch;
char *src;
char *prefix;
unsigned len;
grub_err_t r;
if (! argc)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
if (ctxt->state[3].set && ctxt->script)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
if (! ctxt->state[3].set && ! ctxt->script)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
if (! ctxt->script)
return append_menu_entry (argc, (const char **) args,
ctxt->state[0].args, ctxt->state[1].arg,
ctxt->state[2].arg, 0, ctxt->state[3].arg);
src = args[argc - 1];
args[argc - 1] = NULL;
len = grub_strlen(src);
ch = src[len - 1];
src[len - 1] = '\0';
prefix = setparams_prefix (argc - 1, args);
if (! prefix)
return grub_errno;
r = append_menu_entry (argc - 1, (const char **) args,
ctxt->state[0].args, ctxt->state[1].arg,
ctxt->state[2].arg, prefix, src + 1);
src[len - 1] = ch;
args[argc - 1] = src;
grub_free (prefix);
return r;
}
static grub_extcmd_t cmd;
void
grub_menu_init (void)
{
cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS,
N_("BLOCK"), N_("Define a menuentry."), options);
}
void
grub_menu_fini (void)
{
grub_unregister_extcmd (cmd);
}

View file

@ -142,112 +142,6 @@ grub_mini_cmd_root (struct grub_command *cmd __attribute__ ((unused)),
return 0;
}
#if 0
static void
grub_rescue_cmd_testload (int argc, char *argv[])
{
grub_file_t file;
char *buf;
grub_ssize_t size;
grub_ssize_t pos;
auto void read_func (unsigned long sector, unsigned offset, unsigned len);
void read_func (unsigned long sector __attribute__ ((unused)),
unsigned offset __attribute__ ((unused)),
unsigned len __attribute__ ((unused)))
{
grub_putchar ('.');
grub_refresh ();
}
if (argc < 1)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
return;
}
file = grub_file_open (argv[0]);
if (! file)
return;
size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1);
if (size == 0)
{
grub_file_close (file);
return;
}
buf = grub_malloc (size);
if (! buf)
goto fail;
grub_printf ("Reading %s sequentially", argv[0]);
file->read_hook = read_func;
if (grub_file_read (file, buf, size) != size)
goto fail;
grub_printf (" Done.\n");
/* Read sequentially again. */
grub_printf ("Reading %s sequentially again", argv[0]);
if (grub_file_seek (file, 0) < 0)
goto fail;
for (pos = 0; pos < size; pos += GRUB_DISK_SECTOR_SIZE)
{
char sector[GRUB_DISK_SECTOR_SIZE];
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
!= GRUB_DISK_SECTOR_SIZE)
goto fail;
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
{
grub_printf ("\nDiffers in %d\n", pos);
goto fail;
}
}
grub_printf (" Done.\n");
/* Read backwards and compare. */
grub_printf ("Reading %s backwards", argv[0]);
pos = size;
while (pos > 0)
{
char sector[GRUB_DISK_SECTOR_SIZE];
pos -= GRUB_DISK_SECTOR_SIZE;
if (grub_file_seek (file, pos) < 0)
goto fail;
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
!= GRUB_DISK_SECTOR_SIZE)
goto fail;
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
{
int i;
grub_printf ("\nDiffers in %d\n", pos);
for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++)
grub_putchar (buf[pos + i]);
if (i)
grub_refresh ();
goto fail;
}
}
grub_printf (" Done.\n");
fail:
grub_file_close (file);
grub_free (buf);
}
#endif
/* dump ADDRESS [SIZE] */
static grub_err_t
grub_mini_cmd_dump (struct grub_command *cmd __attribute__ ((unused)),

View file

@ -45,9 +45,9 @@ static const struct grub_arg_option options[] =
};
static grub_err_t
grub_cmd_probe (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
grub_device_t dev;
grub_fs_t fs;
char *ptr;

View file

@ -20,37 +20,104 @@
#include <grub/dl.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/command.h>
#include <grub/err.h>
#include <grub/env.h>
#include <grub/extcmd.h>
#include <grub/i18n.h>
#include <grub/script_sh.h>
#include <regex.h>
static const struct grub_arg_option options[] =
{
{ "set", 's', GRUB_ARG_OPTION_REPEATABLE,
N_("Variable names to update with matches."),
N_("[NUMBER:]VARNAME"), ARG_TYPE_STRING },
{ 0, 0, 0, 0, 0, 0 }
};
static grub_err_t
grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)),
int argc, char **args)
set_matches (char **varnames, char *str, grub_size_t nmatches,
regmatch_t *matches)
{
int i;
char ch;
char *p;
char *q;
grub_err_t err;
unsigned long j;
auto void setvar (char *v, regmatch_t *m);
void setvar (char *v, regmatch_t *m)
{
ch = str[m->rm_eo];
str[m->rm_eo] = '\0';
err = grub_env_set (v, str + m->rm_so);
str[m->rm_eo] = ch;
}
for (i = 0; varnames && varnames[i]; i++)
{
if (! (p = grub_strchr (varnames[i], ':')))
{
/* varname w/o index defaults to 1 */
if (nmatches < 2 || matches[1].rm_so == -1)
grub_env_unset (varnames[i]);
else
setvar (varnames[i], &matches[1]);
}
else
{
j = grub_strtoul (varnames[i], &q, 10);
if (q != p)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"invalid variable name format %s", varnames[i]);
if (nmatches <= j || matches[j].rm_so == -1)
grub_env_unset (p + 1);
else
setvar (p + 1, &matches[j]);
}
if (err != GRUB_ERR_NONE)
return err;
}
return GRUB_ERR_NONE;
}
static grub_err_t
grub_cmd_regexp (grub_extcmd_context_t ctxt, int argc, char **args)
{
int argn = 0;
int matches = 0;
regex_t regex;
int ret;
grub_size_t s;
char *comperr;
grub_err_t err;
regmatch_t *matches = 0;
if (argc != 2)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected");
ret = regcomp (&regex, args[0], RE_SYNTAX_GNU_AWK);
ret = regcomp (&regex, args[0], REG_EXTENDED);
if (ret)
goto fail;
ret = regexec (&regex, args[1], 0, 0, 0);
matches = grub_zalloc (sizeof (*matches) * (regex.re_nsub + 1));
if (! matches)
goto fail;
ret = regexec (&regex, args[1], regex.re_nsub + 1, matches, 0);
if (!ret)
{
err = set_matches (ctxt->state[0].args, args[1],
regex.re_nsub + 1, matches);
regfree (&regex);
return GRUB_ERR_NONE;
grub_free (matches);
return err;
}
fail:
grub_free (matches);
s = regerror (ret, &regex, 0, 0);
comperr = grub_malloc (s);
if (!comperr)
@ -65,16 +132,20 @@ grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)),
return err;
}
static grub_command_t cmd;
static grub_extcmd_t cmd;
GRUB_MOD_INIT(regexp)
{
cmd = grub_register_command ("regexp", grub_cmd_regexp,
N_("REGEXP STRING"),
N_("Test if REGEXP matches STRING."));
cmd = grub_register_extcmd ("regexp", grub_cmd_regexp,
GRUB_COMMAND_FLAG_BOTH, N_("REGEXP STRING"),
N_("Test if REGEXP matches STRING."), options);
/* Setup GRUB script wildcard translator. */
grub_wildcard_translator = &grub_filename_translator;
}
GRUB_MOD_FINI(regexp)
{
grub_unregister_command (cmd);
grub_unregister_extcmd (cmd);
grub_wildcard_translator = 0;
}

View file

@ -54,6 +54,7 @@ FUNC_NAME (const char *key, const char *var, int no_floppy)
if (! buf)
return 1;
grub_file_filter_disable_compression ();
file = grub_file_open (buf);
if (file)
{

View file

@ -50,9 +50,9 @@ enum options
};
static grub_err_t
grub_cmd_search (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
const char *var = 0;
if (argc == 0)

View file

@ -155,7 +155,7 @@ grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid)
}
static grub_err_t
grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
grub_cmd_setpci (grub_extcmd_context_t ctxt, int argc, char **argv)
{
const char *ptr;
unsigned i;
@ -163,14 +163,14 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
pciid_check_value = 0;
pciid_check_mask = 0;
if (cmd->state[0].set)
if (ctxt->state[0].set)
{
ptr = cmd->state[0].arg;
ptr = ctxt->state[0].arg;
pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff);
if (grub_errno == GRUB_ERR_BAD_NUMBER)
{
grub_errno = GRUB_ERR_NONE;
ptr = cmd->state[0].arg;
ptr = ctxt->state[0].arg;
}
else
pciid_check_mask |= 0xffff;
@ -191,11 +191,11 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
check_bus = check_device = check_function = 0;
if (cmd->state[1].set)
if (ctxt->state[1].set)
{
const char *optr;
ptr = cmd->state[1].arg;
ptr = ctxt->state[1].arg;
optr = ptr;
bus = grub_strtoul (ptr, (char **) &ptr, 16);
if (grub_errno == GRUB_ERR_BAD_NUMBER)
@ -229,8 +229,8 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv)
}
}
if (cmd->state[2].set)
varname = cmd->state[2].arg;
if (ctxt->state[2].set)
varname = ctxt->state[2].arg;
else
varname = NULL;

View file

@ -60,9 +60,9 @@ grub_interruptible_millisleep (grub_uint32_t ms)
}
static grub_err_t
grub_cmd_sleep (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_sleep (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = cmd->state;
struct grub_arg_list *state = ctxt->state;
int n;
if (argc != 1)

View file

@ -334,6 +334,7 @@ test_parse (char **args, int *argn, int argc)
if (grub_strcmp (args[*argn], "-s") == 0)
{
grub_file_t file;
grub_file_filter_disable_compression ();
file = grub_file_open (args[*argn + 1]);
update_val (file && (grub_file_size (file) != 0));
if (file)

View file

@ -0,0 +1,155 @@
/* minicmd.c - commands for the rescue mode */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2003,2005,2006,2007,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/env.h>
#include <grub/misc.h>
#include <grub/file.h>
#include <grub/disk.h>
#include <grub/term.h>
#include <grub/loader.h>
#include <grub/command.h>
#include <grub/i18n.h>
static grub_err_t
grub_cmd_testload (struct grub_command *cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file;
char *buf;
grub_size_t size;
grub_off_t pos;
auto void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector, unsigned offset, unsigned len);
void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector __attribute__ ((unused)),
unsigned offset __attribute__ ((unused)),
unsigned len __attribute__ ((unused)))
{
grub_xputs (".");
grub_refresh ();
}
if (argc < 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
file = grub_file_open (argv[0]);
if (! file)
return grub_errno;
size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1);
if (size == 0)
{
grub_file_close (file);
return GRUB_ERR_NONE;
}
buf = grub_malloc (size);
if (! buf)
goto fail;
grub_printf ("Reading %s sequentially", argv[0]);
file->read_hook = read_func;
if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
goto fail;
grub_printf (" Done.\n");
/* Read sequentially again. */
grub_printf ("Reading %s sequentially again", argv[0]);
grub_file_seek (file, 0);
for (pos = 0; pos < size; pos += GRUB_DISK_SECTOR_SIZE)
{
char sector[GRUB_DISK_SECTOR_SIZE];
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
!= GRUB_DISK_SECTOR_SIZE)
goto fail;
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
{
grub_printf ("\nDiffers in %lld\n", (unsigned long long) pos);
goto fail;
}
}
grub_printf (" Done.\n");
/* Read backwards and compare. */
grub_printf ("Reading %s backwards", argv[0]);
pos = size;
while (pos > 0)
{
char sector[GRUB_DISK_SECTOR_SIZE];
pos -= GRUB_DISK_SECTOR_SIZE;
grub_file_seek (file, pos);
if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE)
!= GRUB_DISK_SECTOR_SIZE)
goto fail;
if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0)
{
int i;
grub_printf ("\nDiffers in %lld\n", (unsigned long long) pos);
for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++)
{
grub_printf ("%02x ", buf[pos + i]);
if ((i & 15) == 15)
grub_printf ("\n");
}
if (i)
grub_refresh ();
goto fail;
}
}
grub_printf (" Done.\n");
return GRUB_ERR_NONE;
fail:
grub_file_close (file);
grub_free (buf);
if (!grub_errno)
grub_error (GRUB_ERR_IO, "bad read");
return grub_errno;
}
static grub_command_t cmd;
GRUB_MOD_INIT(testload)
{
cmd =
grub_register_command ("testload", grub_cmd_testload,
N_("FILE"),
N_("Load the same file in multiple ways."));
}
GRUB_MOD_FINI(testload)
{
grub_unregister_command (cmd);
}

View file

@ -0,0 +1,494 @@
/* wildcard.c - Wildcard character expansion for GRUB script. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/mm.h>
#include <grub/fs.h>
#include <grub/env.h>
#include <grub/file.h>
#include <grub/device.h>
#include <grub/script_sh.h>
#include <regex.h>
static inline int isregexop (char ch);
static char ** merge (char **lhs, char **rhs);
static char *make_dir (const char *prefix, const char *start, const char *end);
static int make_regex (const char *regex_start, const char *regex_end,
regex_t *regexp);
static void split_path (const char *path, const char **suffix_end, const char **regex_end);
static char ** match_devices (const regex_t *regexp, int noparts);
static char ** match_files (const char *prefix, const char *suffix_start,
const char *suffix_end, const regex_t *regexp);
static char* wildcard_escape (const char *s);
static char* wildcard_unescape (const char *s);
static grub_err_t wildcard_expand (const char *s, char ***strs);
struct grub_script_wildcard_translator grub_filename_translator = {
.expand = wildcard_expand,
.escape = wildcard_escape,
.unescape = wildcard_unescape
};
static char **
merge (char **dest, char **ps)
{
int i;
int j;
char **p;
if (! dest)
return ps;
if (! ps)
return dest;
for (i = 0; dest[i]; i++)
;
for (j = 0; ps[j]; j++)
;
p = grub_realloc (dest, sizeof (char*) * (i + j + 1));
if (! p)
{
grub_free (dest);
grub_free (ps);
return 0;
}
dest = p;
for (j = 0; ps[j]; j++)
dest[i++] = ps[j];
dest[i] = 0;
grub_free (ps);
return dest;
}
static inline int
isregexop (char ch)
{
return grub_strchr ("*.\\", ch) ? 1 : 0;
}
static char *
make_dir (const char *prefix, const char *start, const char *end)
{
char ch;
unsigned i;
unsigned n;
char *result;
i = grub_strlen (prefix);
n = i + end - start;
result = grub_malloc (n + 1);
if (! result)
return 0;
grub_strcpy (result, prefix);
while (start < end && (ch = *start++))
if (ch == '\\' && isregexop (*start))
result[i++] = *start++;
else
result[i++] = ch;
result[i] = '\0';
return result;
}
static int
make_regex (const char *start, const char *end, regex_t *regexp)
{
char ch;
int i = 0;
unsigned len = end - start;
char *buffer = grub_malloc (len * 2 + 2 + 1); /* worst case size. */
if (! buffer)
return 1;
buffer[i++] = '^';
while (start < end)
{
/* XXX Only * expansion for now. */
switch ((ch = *start++))
{
case '\\':
buffer[i++] = ch;
if (*start != '\0')
buffer[i++] = *start++;
break;
case '.':
buffer[i++] = '\\';
buffer[i++] = '.';
break;
case '*':
buffer[i++] = '.';
buffer[i++] = '*';
break;
default:
buffer[i++] = ch;
}
}
buffer[i++] = '$';
buffer[i] = '\0';
if (regcomp (regexp, buffer, RE_SYNTAX_GNU_AWK))
{
grub_free (buffer);
return 1;
}
grub_free (buffer);
return 0;
}
/* Split `str' into two parts: (1) dirname that is regexop free (2)
dirname that has a regexop. */
static void
split_path (const char *str, const char **noregexop, const char **regexop)
{
char ch = 0;
int regex = 0;
const char *end;
const char *split; /* points till the end of dirnaname that doesn't
need expansion. */
split = end = str;
while ((ch = *end))
{
if (ch == '\\' && end[1])
end++;
else if (isregexop (ch))
regex = 1;
else if (ch == '/' && ! regex)
split = end + 1; /* forward to next regexop-free dirname */
else if (ch == '/' && regex)
break; /* stop at the first dirname with a regexop */
end++;
}
*regexop = end;
if (! regex)
*noregexop = end;
else
*noregexop = split;
}
static char **
match_devices (const regex_t *regexp, int noparts)
{
int i;
int ndev;
char **devs;
auto int match (const char *name);
int match (const char *name)
{
char **t;
char *buffer;
/* skip partitions if asked to. */
if (noparts && grub_strchr(name, ','))
return 0;
buffer = grub_xasprintf ("(%s)", name);
if (! buffer)
return 1;
grub_dprintf ("expand", "matching: %s\n", buffer);
if (regexec (regexp, buffer, 0, 0, 0))
{
grub_free (buffer);
return 0;
}
t = grub_realloc (devs, sizeof (char*) * (ndev + 2));
if (! t)
return 1;
devs = t;
devs[ndev++] = buffer;
devs[ndev] = 0;
return 0;
}
ndev = 0;
devs = 0;
if (grub_device_iterate (match))
goto fail;
return devs;
fail:
for (i = 0; devs && devs[i]; i++)
grub_free (devs[i]);
if (devs)
grub_free (devs);
return 0;
}
static char **
match_files (const char *prefix, const char *suffix, const char *end,
const regex_t *regexp)
{
int i;
int error;
char **files;
unsigned nfile;
char *dir;
const char *path;
char *device_name;
grub_fs_t fs;
grub_device_t dev;
auto int match (const char *name, const struct grub_dirhook_info *info);
int match (const char *name, const struct grub_dirhook_info *info)
{
char **t;
char *buffer;
/* skip . and .. names */
if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0)
return 0;
grub_dprintf ("expand", "matching: %s in %s\n", name, dir);
if (regexec (regexp, name, 0, 0, 0))
return 0;
buffer = grub_xasprintf ("%s%s", dir, name);
if (! buffer)
return 1;
t = grub_realloc (files, sizeof (char*) * (nfile + 2));
if (! t)
{
grub_free (buffer);
return 1;
}
files = t;
files[nfile++] = buffer;
files[nfile] = 0;
return 0;
}
nfile = 0;
files = 0;
dev = 0;
device_name = 0;
grub_error_push ();
dir = make_dir (prefix, suffix, end);
if (! dir)
goto fail;
device_name = grub_file_get_device_name (dir);
dev = grub_device_open (device_name);
if (! dev)
goto fail;
fs = grub_fs_probe (dev);
if (! fs)
goto fail;
path = grub_strchr (dir, ')');
if (! path)
goto fail;
path++;
if (fs->dir (dev, path, match))
goto fail;
grub_free (dir);
grub_device_close (dev);
grub_free (device_name);
grub_error_pop ();
return files;
fail:
if (dir)
grub_free (dir);
for (i = 0; files && files[i]; i++)
grub_free (files[i]);
if (files)
grub_free (files);
if (dev)
grub_device_close (dev);
if (device_name)
grub_free (device_name);
grub_error_pop ();
return 0;
}
static char*
wildcard_escape (const char *s)
{
int i;
int len;
char ch;
char *p;
len = grub_strlen (s);
p = grub_malloc (len * 2 + 1);
if (! p)
return NULL;
i = 0;
while ((ch = *s++))
{
if (isregexop (ch))
p[i++] = '\\';
p[i++] = ch;
}
p[i] = '\0';
return p;
}
static char*
wildcard_unescape (const char *s)
{
int i;
int len;
char ch;
char *p;
len = grub_strlen (s);
p = grub_malloc (len + 1);
if (! p)
return NULL;
i = 0;
while ((ch = *s++))
{
if (ch == '\\' && isregexop (*s))
p[i++] = *s++;
else
p[i++] = ch;
}
p[i] = '\0';
return p;
}
static grub_err_t
wildcard_expand (const char *s, char ***strs)
{
const char *start;
const char *regexop;
const char *noregexop;
char **paths = 0;
unsigned i;
regex_t regexp;
start = s;
while (*start)
{
split_path (start, &noregexop, &regexop);
if (noregexop >= regexop) /* no more wildcards */
break;
if (make_regex (noregexop, regexop, &regexp))
goto fail;
if (paths == 0)
{
if (start == noregexop) /* device part has regexop */
paths = match_devices (&regexp, *start != '(');
else if (*start == '(') /* device part explicit wo regexop */
paths = match_files ("", start, noregexop, &regexp);
else if (*start == '/') /* no device part */
{
char **r;
unsigned n;
char *root;
char *prefix;
root = grub_env_get ("root");
if (! root)
goto fail;
prefix = grub_xasprintf ("(%s)", root);
if (! prefix)
goto fail;
paths = match_files (prefix, start, noregexop, &regexp);
grub_free (prefix);
}
}
else
{
char **r = 0;
for (i = 0; paths[i]; i++)
{
char **p;
p = match_files (paths[i], start, noregexop, &regexp);
if (! p)
continue;
r = merge (r, p);
if (! r)
goto fail;
}
paths = r;
}
regfree (&regexp);
if (! paths)
goto done;
start = regexop;
}
done:
*strs = paths;
return 0;
fail:
for (i = 0; paths && paths[i]; i++)
grub_free (paths[i]);
grub_free (paths);
regfree (&regexp);
return grub_errno;
}

View file

@ -248,6 +248,9 @@ grub_biosdisk_get_drive (const char *name)
{
unsigned long drive;
if (name[0] == 'c' && name[1] == 'd' && name[2] == 0 && cd_drive)
return cd_drive;
if ((name[0] != 'f' && name[0] != 'h') || name[1] != 'd')
goto fail;
@ -270,6 +273,9 @@ grub_biosdisk_call_hook (int (*hook) (const char *name), int drive)
{
char name[10];
if (cd_drive && drive == cd_drive)
return hook ("cd");
grub_snprintf (name, sizeof (name),
(drive & 0x80) ? "hd%d" : "fd%d", drive & (~0x80));
return hook (name);

View file

@ -71,9 +71,9 @@ delete_loopback (const char *name)
/* The command to add and remove loopback devices. */
static grub_err_t
grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args)
grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args)
{
struct grub_arg_list *state = state = cmd->state;
struct grub_arg_list *state = ctxt->state;
grub_file_t file;
struct grub_loopback *newdev;
grub_err_t ret;
@ -167,8 +167,11 @@ grub_loopback_open (const char *name, grub_disk_t disk)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device");
/* Use the filesize for the disk size, round up to a complete sector. */
disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1)
/ GRUB_DISK_SECTOR_SIZE);
if (dev->file->size != GRUB_FILE_SIZE_UNKNOWN)
disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1)
/ GRUB_DISK_SECTOR_SIZE);
else
disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
disk->id = (unsigned long) dev;
disk->has_partitions = dev->has_partitions;

View file

@ -274,6 +274,10 @@ grub_lvm_scan_device (const char *name)
struct grub_lvm_vg *vg;
struct grub_lvm_pv *pv;
#ifdef GRUB_UTIL
grub_util_info ("scanning %s for LVM", name);
#endif
disk = grub_disk_open (name);
if (!disk)
return 0;
@ -294,7 +298,12 @@ grub_lvm_scan_device (const char *name)
/* Return if we didn't find a label. */
if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
goto fail;
{
#ifdef GRUB_UTIL
grub_util_info ("no LVM signature found\n");
#endif
goto fail;
}
pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
@ -318,6 +327,9 @@ grub_lvm_scan_device (const char *name)
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"we don't support multiple LVM data areas");
#ifdef GRUB_UTIL
grub_util_info ("we don't support multiple LVM data areas\n");
#endif
goto fail;
}
@ -344,6 +356,9 @@ grub_lvm_scan_device (const char *name)
{
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unknown LVM metadata header");
#ifdef GRUB_UTIL
grub_util_info ("unknown LVM metadata header\n");
#endif
goto fail2;
}
@ -364,7 +379,12 @@ grub_lvm_scan_device (const char *name)
q++;
if (q == metadatabuf + mda_size)
goto fail2;
{
#ifdef GRUB_UTIL
grub_util_info ("error parsing metadata\n");
#endif
goto fail2;
}
vgname_len = q - p;
vgname = grub_malloc (vgname_len + 1);
@ -376,7 +396,12 @@ grub_lvm_scan_device (const char *name)
p = grub_strstr (q, "id = \"");
if (p == NULL)
goto fail3;
{
#ifdef GRUB_UTIL
grub_util_info ("couldn't find ID\n");
#endif
goto fail3;
}
p += sizeof ("id = \"") - 1;
grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
vg_id[GRUB_LVM_ID_STRLEN] = '\0';
@ -399,7 +424,12 @@ grub_lvm_scan_device (const char *name)
vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
if (p == NULL)
goto fail4;
{
#ifdef GRUB_UTIL
grub_util_info ("unknown extent size\n");
#endif
goto fail4;
}
vg->lvs = NULL;
vg->pvs = NULL;
@ -439,11 +469,21 @@ grub_lvm_scan_device (const char *name)
pv->start = grub_lvm_getvalue (&p, "pe_start = ");
if (p == NULL)
goto pvs_fail;
{
#ifdef GRUB_UTIL
grub_util_info ("unknown pe_start\n");
#endif
goto pvs_fail;
}
p = grub_strchr (p, '}');
if (p == NULL)
goto pvs_fail;
{
#ifdef GRUB_UTIL
grub_util_info ("error parsing pe_start\n");
#endif
goto pvs_fail;
}
p++;
pv->disk = NULL;
@ -500,7 +540,12 @@ grub_lvm_scan_device (const char *name)
lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
if (p == NULL)
goto lvs_fail;
{
#ifdef GRUB_UTIL
grub_util_info ("unknown segment_count\n");
#endif
goto lvs_fail;
}
lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
seg = lv->segments;
@ -510,14 +555,29 @@ grub_lvm_scan_device (const char *name)
p = grub_strstr (p, "segment");
if (p == NULL)
goto lvs_segment_fail;
{
#ifdef GRUB_UTIL
grub_util_info ("unknown segment\n");
#endif
goto lvs_segment_fail;
}
seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
if (p == NULL)
goto lvs_segment_fail;
{
#ifdef GRUB_UTIL
grub_util_info ("unknown start_extent\n");
#endif
goto lvs_segment_fail;
}
seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
if (p == NULL)
goto lvs_segment_fail;
{
#ifdef GRUB_UTIL
grub_util_info ("unknown extent_count\n");
#endif
goto lvs_segment_fail;
}
if (grub_lvm_checkvalue (&p, "type = ", "snapshot"))
{
@ -528,7 +588,12 @@ grub_lvm_scan_device (const char *name)
seg->stripe_count = grub_lvm_getvalue (&p, "stripe_count = ");
if (p == NULL)
goto lvs_segment_fail;
{
#ifdef GRUB_UTIL
grub_util_info ("unknown stripe_count\n");
#endif
goto lvs_segment_fail;
}
lv->size += seg->extent_count * vg->extent_size;
@ -541,7 +606,12 @@ grub_lvm_scan_device (const char *name)
p = grub_strstr (p, "stripes = [");
if (p == NULL)
goto lvs_segment_fail2;
{
#ifdef GRUB_UTIL
grub_util_info ("unknown stripes\n");
#endif
goto lvs_segment_fail2;
}
p += sizeof("stripes = [") - 1;
for (j = 0; j < seg->stripe_count; j++)

132
grub-core/fs/btrfs.c Normal file
View file

@ -0,0 +1,132 @@
/* btrfs.c - B-tree file system. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/err.h>
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/disk.h>
#include <grub/dl.h>
#include <grub/types.h>
#define BTRFS_SIGNATURE "_BHRfS_M"
struct btrfs_superblock
{
grub_uint8_t dummy1[32];
grub_uint16_t uuid[8];
grub_uint8_t dummy2[16];
grub_uint8_t signature[sizeof (BTRFS_SIGNATURE) - 1];
} __attribute__ ((packed));
struct grub_btrfs_data
{
struct btrfs_superblock sblock;
};
static struct grub_btrfs_data *
grub_btrfs_mount (grub_disk_t disk)
{
struct grub_btrfs_data *data = grub_malloc (sizeof (*data));
if (! data)
return NULL;
if (grub_disk_read (disk, 128, 0, sizeof (data->sblock),
&data->sblock) != GRUB_ERR_NONE)
goto fail;
if (grub_strncmp ((char *) data->sblock.signature, BTRFS_SIGNATURE, sizeof (BTRFS_SIGNATURE) - 1))
{
grub_error (GRUB_ERR_BAD_FS, "not a Btrfs filesystem");
goto fail;
}
return data;
fail:
grub_free (data);
return NULL;
}
static grub_err_t
grub_btrfs_open (struct grub_file *file __attribute__ ((unused)),
const char *name __attribute__ ((unused)))
{
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "only detection is supported for Btrfs");
}
static grub_err_t
grub_btrfs_dir (grub_device_t device,
const char *path __attribute__ ((unused)),
int (*hook) (const char *filename,
const struct grub_dirhook_info *info)
__attribute__ ((unused)))
{
struct grub_btrfs_data *data = grub_btrfs_mount (device->disk);
if (grub_errno)
return grub_errno;
grub_free (data);
return GRUB_ERR_NONE;
}
static grub_err_t
grub_btrfs_uuid (grub_device_t device, char **uuid)
{
struct grub_btrfs_data *data;
*uuid = NULL;
data = grub_btrfs_mount (device->disk);
if (! data)
return grub_errno;
*uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
grub_be_to_cpu16 (data->sblock.uuid[0]),
grub_be_to_cpu16 (data->sblock.uuid[1]),
grub_be_to_cpu16 (data->sblock.uuid[2]),
grub_be_to_cpu16 (data->sblock.uuid[3]),
grub_be_to_cpu16 (data->sblock.uuid[4]),
grub_be_to_cpu16 (data->sblock.uuid[5]),
grub_be_to_cpu16 (data->sblock.uuid[6]),
grub_be_to_cpu16 (data->sblock.uuid[7]));
grub_free (data);
return grub_errno;
}
static struct grub_fs grub_btrfs_fs =
{
.name = "btrfs",
.dir = grub_btrfs_dir,
.open = grub_btrfs_open,
.uuid = grub_btrfs_uuid,
};
GRUB_MOD_INIT(btrfs)
{
grub_fs_register (&grub_btrfs_fs);
}
GRUB_MOD_FINI(btrfs)
{
grub_fs_unregister (&grub_btrfs_fs);
}

View file

@ -41,7 +41,7 @@ struct grub_pxe_disk_data
grub_uint32_t gateway_ip;
};
struct grub_pxenv *grub_pxe_pxenv;
struct grub_pxe_bangpxe *grub_pxe_pxenv;
static grub_uint32_t grub_pxe_your_ip;
static grub_uint32_t grub_pxe_default_server_ip;
static grub_uint32_t grub_pxe_default_gateway_ip;
@ -58,41 +58,47 @@ struct grub_pxe_data
static grub_uint32_t pxe_rm_entry = 0;
static struct grub_pxenv *
static struct grub_pxe_bangpxe *
grub_pxe_scan (void)
{
struct grub_bios_int_registers regs;
struct grub_pxenv *ret;
void *pxe;
struct grub_pxenv *pxenv;
struct grub_pxe_bangpxe *bangpxe;
regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
regs.ebx = 0;
regs.ecx = 0;
regs.eax = 0x5650;
regs.es = 0;
grub_bios_interrupt (0x1a, &regs);
if ((regs.eax & 0xffff) != 0x564e)
return NULL;
ret = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff));
if (grub_memcmp (ret->signature, GRUB_PXE_SIGNATURE, sizeof (ret->signature))
pxenv = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff));
if (grub_memcmp (pxenv->signature, GRUB_PXE_SIGNATURE,
sizeof (pxenv->signature))
!= 0)
return NULL;
if (ret->version < 0x201)
if (pxenv->version < 0x201)
return NULL;
pxe = (void *) ((((ret->pxe_ptr & 0xffff0000) >> 16) << 4)
+ (ret->pxe_ptr & 0xffff));
if (!pxe)
bangpxe = (void *) ((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4)
+ (pxenv->pxe_ptr & 0xffff));
if (!bangpxe)
return NULL;
/* !PXE */
if (*(grub_uint32_t *) pxe != 0x45585021)
if (grub_memcmp (bangpxe->signature, GRUB_PXE_BANGPXE_SIGNATURE,
sizeof (bangpxe->signature)) != 0)
return NULL;
pxe_rm_entry = ret->rm_entry;
return ret;
pxe_rm_entry = bangpxe->rm_entry;
return bangpxe;
}
static int
@ -276,6 +282,7 @@ grub_pxefs_open (struct grub_file *file, const char *name)
}
file->data = data;
file->not_easly_seekable = 1;
grub_memcpy (file_int, file, sizeof (struct grub_file));
curr_file = file_int;
@ -321,7 +328,7 @@ grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len)
o.gateway_ip = disk_data->gateway_ip;
grub_strcpy ((char *)&o.filename[0], data->filename);
o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT);
o.packet_size = grub_pxe_blksize;
o.packet_size = data->block_size;
grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &o, pxe_rm_entry);
if (o.status)
{
@ -483,7 +490,7 @@ parse_dhcp_vendor (void *vend, int limit)
static void
grub_pxe_detect (void)
{
struct grub_pxenv *pxenv;
struct grub_pxe_bangpxe *pxenv;
struct grub_pxenv_get_cached_info ci;
struct grub_pxenv_boot_player *bp;

View file

@ -25,10 +25,13 @@
#include <grub/dl.h>
#include <grub/types.h>
#ifdef MODE_MINIX2
#define GRUB_MINIX_MAGIC 0x2468
#define GRUB_MINIX_MAGIC_30 0x2478
#else
#define GRUB_MINIX_MAGIC 0x137F
#define GRUB_MINIX2_MAGIC 0x2468
#define GRUB_MINIX_MAGIC_30 0x138F
#define GRUB_MINIX2_MAGIC_30 0x2478
#endif
#define GRUB_MINIX_BSIZE 1024U
#define GRUB_MINIX_LOG2_BSIZE 1
#define GRUB_MINIX_ROOT_INODE 1
@ -38,20 +41,25 @@
#define GRUB_MINIX_IFDIR 0040000U
#define GRUB_MINIX_IFLNK 0120000U
#define GRUB_MINIX_INODE(data,field) (data->version == 1 ? \
data->inode. field : data->inode2. field)
#define GRUB_MINIX_INODE_ENDIAN(data,field,bits1,bits2) (data->version == 1 ? \
grub_le_to_cpu##bits1 (data->inode.field) : \
grub_le_to_cpu##bits2 (data->inode2.field))
#define GRUB_MINIX_INODE_SIZE(data) GRUB_MINIX_INODE_ENDIAN (data,size,16,32)
#define GRUB_MINIX_INODE_MODE(data) GRUB_MINIX_INODE_ENDIAN (data,mode,16,16)
#define GRUB_MINIX_INODE_DIR_ZONES(data,blk) GRUB_MINIX_INODE_ENDIAN \
(data,dir_zones[blk],16,32)
#define GRUB_MINIX_INODE_INDIR_ZONE(data) \
GRUB_MINIX_INODE_ENDIAN (data,indir_zone,16,32)
#define GRUB_MINIX_INODE_DINDIR_ZONE(data) \
GRUB_MINIX_INODE_ENDIAN (data,double_indir_zone,16,32)
#define GRUB_MINIX_INODE_BLKSZ(data) (data->version == 1 ? 2 : 4)
#ifdef MODE_MINIX2
typedef grub_uint32_t grub_minix_uintn_t;
#define grub_minix_le_to_cpu_n grub_le_to_cpu32
#else
typedef grub_uint16_t grub_minix_uintn_t;
#define grub_minix_le_to_cpu_n grub_le_to_cpu16
#endif
#define GRUB_MINIX_INODE_BLKSZ(data) sizeof (grub_minix_uintn_t)
#define GRUB_MINIX_INODE_SIZE(data) (grub_minix_le_to_cpu_n (data->inode.size))
#define GRUB_MINIX_INODE_MODE(data) (grub_le_to_cpu16 (data->inode.mode))
#define GRUB_MINIX_INODE_DIR_ZONES(data,blk) (grub_minix_le_to_cpu_n \
(data->inode.dir_zones[blk]))
#define GRUB_MINIX_INODE_INDIR_ZONE(data) (grub_minix_le_to_cpu_n \
(data->inode.indir_zone))
#define GRUB_MINIX_INODE_DINDIR_ZONE(data) (grub_minix_le_to_cpu_n \
(data->inode.double_indir_zone))
#define GRUB_MINIX_LOG2_ZONESZ (GRUB_MINIX_LOG2_BSIZE \
+ grub_le_to_cpu16 (sblock->log2_zone_size))
#define GRUB_MINIX_ZONESZ (GRUB_MINIX_BSIZE \
@ -69,6 +77,7 @@ struct grub_minix_sblock
grub_uint16_t magic;
};
#ifndef MODE_MINIX2
struct grub_minix_inode
{
grub_uint16_t mode;
@ -82,7 +91,9 @@ struct grub_minix_inode
grub_uint16_t double_indir_zone;
};
struct grub_minix2_inode
#else
struct grub_minix_inode
{
grub_uint16_t mode;
grub_uint16_t nlinks;
@ -99,16 +110,16 @@ struct grub_minix2_inode
};
#endif
/* Information about a "mounted" minix filesystem. */
struct grub_minix_data
{
struct grub_minix_sblock sblock;
struct grub_minix_inode inode;
struct grub_minix2_inode inode2;
int ino;
int linknest;
grub_disk_t disk;
int version;
int filename_size;
};
@ -128,24 +139,12 @@ grub_minix_get_file_block (struct grub_minix_data *data, unsigned int blk)
/* Read the block pointer in ZONE, on the offset NUM. */
int grub_get_indir (int zone, int num)
{
if (data->version == 1)
{
grub_uint16_t indir16;
grub_disk_read (data->disk,
zone << GRUB_MINIX_LOG2_ZONESZ,
sizeof (grub_uint16_t) * num,
sizeof (grub_uint16_t), (char *) &indir16);
return grub_le_to_cpu16 (indir16);
}
else
{
grub_uint32_t indir32;
grub_disk_read (data->disk,
zone << GRUB_MINIX_LOG2_ZONESZ,
sizeof (grub_uint32_t) * num,
sizeof (grub_uint32_t), (char *) &indir32);
return grub_le_to_cpu32 (indir32);
}
grub_minix_uintn_t indirn;
grub_disk_read (data->disk,
zone << GRUB_MINIX_LOG2_ZONESZ,
sizeof (grub_minix_uintn_t) * num,
sizeof (grub_minix_uintn_t), (char *) &indirn);
return grub_minix_le_to_cpu_n (indirn);
}
/* Direct block. */
@ -259,27 +258,13 @@ grub_minix_read_inode (struct grub_minix_data *data, int ino)
+ grub_le_to_cpu16 (sblock->zone_bmap_size))
<< GRUB_MINIX_LOG2_BSIZE);
if (data->version == 1)
{
block += ino / (GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_minix_inode));
int offs = (ino % (GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_minix_inode))
* sizeof (struct grub_minix_inode));
grub_disk_read (data->disk, block, offs,
sizeof (struct grub_minix_inode), &data->inode);
}
else
{
block += ino / (GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_minix2_inode));
int offs = (ino
% (GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_minix2_inode))
* sizeof (struct grub_minix2_inode));
grub_disk_read (data->disk, block, offs,
sizeof (struct grub_minix2_inode),&data->inode2);
}
block += ino / (GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_minix_inode));
int offs = (ino % (GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_minix_inode))
* sizeof (struct grub_minix_inode));
grub_disk_read (data->disk, block, offs,
sizeof (struct grub_minix_inode), &data->inode);
return GRUB_ERR_NONE;
}
@ -424,25 +409,9 @@ grub_minix_mount (grub_disk_t disk)
goto fail;
if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX_MAGIC)
{
data->version = 1;
data->filename_size = 14;
}
else if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX2_MAGIC)
{
data->version = 2;
data->filename_size = 14;
}
data->filename_size = 14;
else if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX_MAGIC_30)
{
data->version = 1;
data->filename_size = 30;
}
else if (grub_le_to_cpu16 (data->sblock.magic) == GRUB_MINIX2_MAGIC_30)
{
data->version = 2;
data->filename_size = 30;
}
data->filename_size = 30;
else
goto fail;
@ -453,7 +422,11 @@ grub_minix_mount (grub_disk_t disk)
fail:
grub_free (data);
#ifdef MODE_MINIX2
grub_error (GRUB_ERR_BAD_FS, "not a minix2 filesystem");
#else
grub_error (GRUB_ERR_BAD_FS, "not a minix filesystem");
#endif
return 0;
}
@ -583,32 +556,36 @@ grub_minix_close (grub_file_t file)
}
static grub_err_t
grub_minix_label (grub_device_t device __attribute ((unused)),
char **label __attribute ((unused)))
{
return GRUB_ERR_NONE;
}
static struct grub_fs grub_minix_fs =
{
#ifdef MODE_MINIX2
.name = "minix2",
#else
.name = "minix",
#endif
.dir = grub_minix_dir,
.open = grub_minix_open,
.read = grub_minix_read,
.close = grub_minix_close,
.label = grub_minix_label,
.next = 0
};
#ifdef MODE_MINIX2
GRUB_MOD_INIT(minix2)
#else
GRUB_MOD_INIT(minix)
#endif
{
grub_fs_register (&grub_minix_fs);
my_mod = mod;
}
#ifdef MODE_MINIX2
GRUB_MOD_FINI(minix2)
#else
GRUB_MOD_FINI(minix)
#endif
{
grub_fs_unregister (&grub_minix_fs);
}

2
grub-core/fs/minix2.c Normal file
View file

@ -0,0 +1,2 @@
#define MODE_MINIX2 1
#include "minix.c"

View file

@ -26,7 +26,6 @@
#include <grub/normal.h>
#include <grub/file.h>
#include <grub/kernel.h>
#include <grub/gzio.h>
#include <grub/i18n.h>
/*
@ -219,7 +218,7 @@ grub_gettext_translate (const char *orig)
return ret;
}
/* This is similar to grub_gzfile_open. */
/* This is similar to grub_file_open. */
static grub_file_t
grub_mofile_open (const char *filename)
{
@ -229,7 +228,7 @@ grub_mofile_open (const char *filename)
/* Using fd_mo and not another variable because
it's needed for grub_gettext_get_info. */
fd_mo = grub_gzfile_open (filename, 1);
fd_mo = grub_file_open (filename);
grub_errno = GRUB_ERR_NONE;
if (!fd_mo)

View file

@ -27,7 +27,7 @@
#include <grub/i18n.h>
static grub_err_t
grub_cmd_hello (struct grub_extcmd *cmd __attribute__ ((unused)),
grub_cmd_hello (grub_extcmd_context_t ctxt __attribute__ ((unused)),
int argc __attribute__ ((unused)),
char **args __attribute__ ((unused)))
{

View file

@ -74,6 +74,7 @@ grub_bufio_open (grub_file_t io, int size)
file->data = bufio;
file->read_hook = 0;
file->fs = &grub_bufio_fs;
file->not_easly_seekable = io->not_easly_seekable;
return file;
}

View file

@ -40,7 +40,7 @@
#include <grub/misc.h>
#include <grub/fs.h>
#include <grub/file.h>
#include <grub/gzio.h>
#include <grub/dl.h>
/*
* Window Size
@ -206,7 +206,7 @@ test_header (grub_file_t file)
|| ((hdr.flags & ORIG_NAME) && eat_field (gzio->file, -1))
|| ((hdr.flags & COMMENT) && eat_field (gzio->file, -1)))
{
grub_error (GRUB_ERR_BAD_GZIP_DATA, "unsupported gzip format");
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "unsupported gzip format");
return 0;
}
@ -214,12 +214,14 @@ test_header (grub_file_t file)
grub_file_seek (gzio->file, grub_file_size (gzio->file) - 4);
if (grub_file_read (gzio->file, &orig_len, 4) != 4)
if (grub_file_seekable (gzio->file))
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported gzip format");
return 0;
if (grub_file_read (gzio->file, &orig_len, 4) != 4)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported gzip format");
return 0;
}
}
/* FIXME: this does not handle files whose original size is over 4GB.
But how can we know the real original size? */
file->size = grub_le_to_cpu32 (orig_len);
@ -644,7 +646,7 @@ inflate_codes_in_window (grub_file_t file)
{
if (e == 99)
{
grub_error (GRUB_ERR_BAD_GZIP_DATA,
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"an unused code found");
return 1;
}
@ -683,7 +685,7 @@ inflate_codes_in_window (grub_file_t file)
{
if (e == 99)
{
grub_error (GRUB_ERR_BAD_GZIP_DATA,
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"an unused code found");
return 1;
}
@ -769,7 +771,7 @@ init_stored_block (grub_file_t file)
DUMPBITS (16);
NEEDBITS (16);
if (gzio->block_len != (int) ((~b) & 0xffff))
grub_error (GRUB_ERR_BAD_GZIP_DATA,
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"the length of a stored block does not match");
DUMPBITS (16);
@ -803,7 +805,7 @@ init_fixed_block (grub_file_t file)
if (huft_build (l, 288, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0)
{
if (grub_errno == GRUB_ERR_NONE)
grub_error (GRUB_ERR_BAD_GZIP_DATA,
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"failed in building a Huffman code table");
return;
}
@ -815,7 +817,7 @@ init_fixed_block (grub_file_t file)
if (huft_build (l, 30, 0, cpdist, cpdext, &gzio->td, &gzio->bd) > 1)
{
if (grub_errno == GRUB_ERR_NONE)
grub_error (GRUB_ERR_BAD_GZIP_DATA,
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"failed in building a Huffman code table");
huft_free (gzio->tl);
gzio->tl = 0;
@ -862,7 +864,7 @@ init_dynamic_block (grub_file_t file)
DUMPBITS (4);
if (nl > 286 || nd > 30)
{
grub_error (GRUB_ERR_BAD_GZIP_DATA, "too much data");
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too much data");
return;
}
@ -880,7 +882,7 @@ init_dynamic_block (grub_file_t file)
gzio->bl = 7;
if (huft_build (ll, 19, 19, NULL, NULL, &gzio->tl, &gzio->bl) != 0)
{
grub_error (GRUB_ERR_BAD_GZIP_DATA,
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"failed in building a Huffman code table");
return;
}
@ -904,7 +906,7 @@ init_dynamic_block (grub_file_t file)
DUMPBITS (2);
if ((unsigned) i + j > n)
{
grub_error (GRUB_ERR_BAD_GZIP_DATA, "too many codes found");
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found");
return;
}
while (j--)
@ -917,7 +919,7 @@ init_dynamic_block (grub_file_t file)
DUMPBITS (3);
if ((unsigned) i + j > n)
{
grub_error (GRUB_ERR_BAD_GZIP_DATA, "too many codes found");
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found");
return;
}
while (j--)
@ -932,7 +934,7 @@ init_dynamic_block (grub_file_t file)
DUMPBITS (7);
if ((unsigned) i + j > n)
{
grub_error (GRUB_ERR_BAD_GZIP_DATA, "too many codes found");
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found");
return;
}
while (j--)
@ -954,7 +956,7 @@ init_dynamic_block (grub_file_t file)
gzio->bl = lbits;
if (huft_build (ll, nl, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0)
{
grub_error (GRUB_ERR_BAD_GZIP_DATA,
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"failed in building a Huffman code table");
return;
}
@ -963,7 +965,7 @@ init_dynamic_block (grub_file_t file)
{
huft_free (gzio->tl);
gzio->tl = 0;
grub_error (GRUB_ERR_BAD_GZIP_DATA,
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"failed in building a Huffman code table");
return;
}
@ -1039,7 +1041,7 @@ inflate_window (grub_file_t file)
}
if (gzio->block_type > INFLATE_DYNAMIC)
grub_error (GRUB_ERR_BAD_GZIP_DATA,
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"unknown block type %d", gzio->block_type);
if (grub_errno != GRUB_ERR_NONE)
@ -1111,8 +1113,8 @@ initialize_tables (grub_file_t file)
/* Open a new decompressing object on the top of IO. If TRANSPARENT is true,
even if IO does not contain data compressed by gzip, return a valid file
object. Note that this function won't close IO, even if an error occurs. */
grub_file_t
grub_gzio_open (grub_file_t io, int transparent)
static grub_file_t
grub_gzio_open (grub_file_t io)
{
grub_file_t file;
grub_gzio_t gzio = 0;
@ -1135,6 +1137,7 @@ grub_gzio_open (grub_file_t io, int transparent)
file->data = gzio;
file->read_hook = 0;
file->fs = &grub_gzio_fs;
file->not_easly_seekable = 1;
if (! test_header (file))
{
@ -1142,33 +1145,11 @@ grub_gzio_open (grub_file_t io, int transparent)
grub_free (file);
grub_file_seek (io, 0);
if (grub_errno == GRUB_ERR_BAD_FILE_TYPE && transparent)
if (grub_errno == GRUB_ERR_BAD_FILE_TYPE)
{
grub_errno = GRUB_ERR_NONE;
return io;
}
else
return 0;
}
return file;
}
/* This is similar to grub_gzio_open, but takes a file name as an argument. */
grub_file_t
grub_gzfile_open (const char *name, int transparent)
{
grub_file_t io, file;
io = grub_file_open (name);
if (! io)
return 0;
file = grub_gzio_open (io, transparent);
if (! file)
{
grub_file_close (io);
return 0;
}
return file;
@ -1249,3 +1230,13 @@ static struct grub_fs grub_gzio_fs =
.label = 0,
.next = 0
};
GRUB_MOD_INIT(gzio)
{
grub_file_filter_register (GRUB_FILE_FILTER_GZIO, grub_gzio_open);
}
GRUB_MOD_FINI(gzio)
{
grub_file_filter_unregister (GRUB_FILE_FILTER_GZIO);
}

353
grub-core/io/xzio.c Normal file
View file

@ -0,0 +1,353 @@
/* xzio.c - decompression support for xz */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/file.h>
#include <grub/fs.h>
#include <grub/dl.h>
#include "xz.h"
#include "xz_stream.h"
#define XZBUFSIZ 0x2000
#define VLI_MAX_DIGITS 9
#define XZ_STREAM_FOOTER_SIZE 12
struct grub_xzio
{
grub_file_t file;
struct xz_buf buf;
struct xz_dec *dec;
grub_uint8_t inbuf[XZBUFSIZ];
grub_uint8_t outbuf[XZBUFSIZ];
grub_off_t saved_offset;
};
typedef struct grub_xzio *grub_xzio_t;
static struct grub_fs grub_xzio_fs;
static grub_size_t
decode_vli (const grub_uint8_t buf[], grub_size_t size_max,
grub_uint64_t * num)
{
if (size_max == 0)
return 0;
if (size_max > VLI_MAX_DIGITS)
size_max = VLI_MAX_DIGITS;
*num = buf[0] & 0x7F;
grub_size_t i = 0;
while (buf[i++] & 0x80)
{
if (i >= size_max || buf[i] == 0x00)
return 0;
*num |= (uint64_t) (buf[i] & 0x7F) << (i * 7);
}
return i;
}
static grub_ssize_t
read_vli (grub_file_t file, grub_uint64_t * num)
{
grub_uint8_t buf[VLI_MAX_DIGITS];
grub_ssize_t read;
grub_size_t dec;
read = grub_file_read (file, buf, VLI_MAX_DIGITS);
if (read < 0)
return -1;
dec = decode_vli (buf, read, num);
grub_file_seek (file, file->offset - (read - dec));
return dec;
}
/* Function xz_dec_run() should consume header and ask for more (XZ_OK)
* else file is corrupted (or options not supported) or not xz. */
static int
test_header (grub_file_t file)
{
grub_xzio_t xzio = file->data;
xzio->buf.in_size = grub_file_read (xzio->file, xzio->inbuf,
STREAM_HEADER_SIZE);
if (xzio->buf.in_size != STREAM_HEADER_SIZE)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, "no xz magic found");
return 0;
}
enum xz_ret ret = xz_dec_run (xzio->dec, &xzio->buf);
if (ret == XZ_FORMAT_ERROR)
{
grub_error (GRUB_ERR_BAD_FILE_TYPE, "no xz magic found");
return 0;
}
if (ret != XZ_OK)
{
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "not supported xz options");
return 0;
}
return 1;
}
/* Try to find out size of uncompressed data,
* also do some footer sanity checks. */
static int
test_footer (grub_file_t file)
{
grub_xzio_t xzio = file->data;
grub_uint8_t footer[FOOTER_MAGIC_SIZE];
grub_uint32_t backsize;
grub_uint8_t imarker;
grub_uint64_t uncompressed_size_total = 0;
grub_uint64_t uncompressed_size;
grub_uint64_t records;
grub_file_seek (xzio->file, xzio->file->size - FOOTER_MAGIC_SIZE);
if (grub_file_read (xzio->file, footer, FOOTER_MAGIC_SIZE) !=
FOOTER_MAGIC_SIZE
|| grub_memcmp (footer, FOOTER_MAGIC, FOOTER_MAGIC_SIZE) != 0)
goto ERROR;
grub_file_seek (xzio->file, xzio->file->size - 8);
if (grub_file_read (xzio->file, &backsize, sizeof (backsize))
!= sizeof (backsize))
goto ERROR;
/* Calculate real backward size. */
backsize = (grub_le_to_cpu32 (backsize) + 1) * 4;
/* Set file to the beginning of stream index. */
grub_file_seek (xzio->file,
xzio->file->size - XZ_STREAM_FOOTER_SIZE - backsize);
/* Test index marker. */
if (grub_file_read (xzio->file, &imarker, sizeof (imarker)) !=
sizeof (imarker) && imarker != 0x00)
goto ERROR;
if (read_vli (xzio->file, &records) <= 0)
goto ERROR;
for (; records != 0; records--)
{
if (read_vli (xzio->file, &uncompressed_size) <= 0) /* Ignore unpadded. */
goto ERROR;
if (read_vli (xzio->file, &uncompressed_size) <= 0) /* Uncompressed. */
goto ERROR;
uncompressed_size_total += uncompressed_size;
}
file->size = uncompressed_size_total;
grub_file_seek (xzio->file, STREAM_HEADER_SIZE);
return 1;
ERROR:
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "bad footer magic");
return 0;
}
static grub_file_t
grub_xzio_open (grub_file_t io)
{
grub_file_t file;
grub_xzio_t xzio;
file = (grub_file_t) grub_zalloc (sizeof (*file));
if (!file)
return 0;
xzio = grub_zalloc (sizeof (*xzio));
if (!xzio)
{
grub_free (file);
return 0;
}
xzio->file = io;
xzio->saved_offset = 0;
file->device = io->device;
file->offset = 0;
file->data = xzio;
file->read_hook = 0;
file->fs = &grub_xzio_fs;
file->size = GRUB_FILE_SIZE_UNKNOWN;
file->not_easly_seekable = 1;
if (grub_file_tell (xzio->file) != 0)
grub_file_seek (xzio->file, 0);
/* Allocated 64KiB for dictionary.
* Decoder will relocate if bigger is needed. */
xzio->dec = xz_dec_init (1 << 16);
if (!xzio->dec)
{
grub_free (file);
grub_free (xzio);
return 0;
}
xzio->buf.in = xzio->inbuf;
xzio->buf.in_pos = 0;
xzio->buf.in_size = 0;
xzio->buf.out = xzio->outbuf;
xzio->buf.out_pos = 0;
xzio->buf.out_size = XZBUFSIZ;
if (!test_header (file) || !(grub_file_seekable (io) && test_footer (file)))
{
grub_errno = GRUB_ERR_NONE;
grub_file_seek (io, 0);
xz_dec_end (xzio->dec);
grub_free (xzio);
grub_free (file);
return io;
}
return file;
}
static grub_ssize_t
grub_xzio_read (grub_file_t file, char *buf, grub_size_t len)
{
grub_ssize_t ret = 0;
grub_ssize_t readret;
enum xz_ret xzret;
grub_xzio_t xzio = file->data;
grub_off_t current_offset;
/* If seek backward need to reset decoder and start from beginning of file.
TODO Possible improvement by jumping blocks. */
if (file->offset < xzio->saved_offset)
{
xz_dec_reset (xzio->dec);
xzio->saved_offset = 0;
xzio->buf.out_pos = 0;
xzio->buf.in_pos = 0;
xzio->buf.in_size = 0;
grub_file_seek (xzio->file, 0);
}
current_offset = xzio->saved_offset;
while (len > 0)
{
xzio->buf.out_size = grub_min (file->offset + ret + len - current_offset,
XZBUFSIZ);
/* Feed input. */
if (xzio->buf.in_pos == xzio->buf.in_size)
{
readret = grub_file_read (xzio->file, xzio->inbuf, XZBUFSIZ);
if (readret < 0)
return -1;
xzio->buf.in_size = readret;
xzio->buf.in_pos = 0;
}
xzret = xz_dec_run (xzio->dec, &xzio->buf);
switch (xzret)
{
case XZ_MEMLIMIT_ERROR:
case XZ_FORMAT_ERROR:
case XZ_OPTIONS_ERROR:
case XZ_DATA_ERROR:
case XZ_BUF_ERROR:
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
"file corrupted or unsupported block options");
return -1;
default:
break;
}
{
grub_off_t new_offset = current_offset + xzio->buf.out_pos;
if (file->offset <= new_offset)
/* Store first chunk of data in buffer. */
{
grub_size_t delta = new_offset - (file->offset + ret);
grub_memmove (buf, xzio->buf.out + (xzio->buf.out_pos - delta),
delta);
len -= delta;
buf += delta;
ret += delta;
}
current_offset = new_offset;
}
xzio->buf.out_pos = 0;
if (xzret == XZ_STREAM_END) /* Stream end, EOF. */
break;
}
if (ret >= 0)
xzio->saved_offset = file->offset + ret;
return ret;
}
/* Release everything, including the underlying file object. */
static grub_err_t
grub_xzio_close (grub_file_t file)
{
grub_xzio_t xzio = file->data;
xz_dec_end (xzio->dec);
grub_file_close (xzio->file);
grub_free (xzio);
/* Device must not be closed twice. */
file->device = 0;
return grub_errno;
}
static struct grub_fs grub_xzio_fs = {
.name = "xzio",
.dir = 0,
.open = 0,
.read = grub_xzio_read,
.close = grub_xzio_close,
.label = 0,
.next = 0
};
GRUB_MOD_INIT (xzio)
{
grub_file_filter_register (GRUB_FILE_FILTER_XZIO, grub_xzio_open);
}
GRUB_MOD_FINI (xzio)
{
grub_file_filter_unregister (GRUB_FILE_FILTER_XZIO);
}

View file

@ -66,10 +66,33 @@ grub_efi_set_prefix (void)
path = grub_strdup (pptr);
}
if (!device || !path)
if ((!device || device[0] == ',' || !device[0]) || !path)
image = grub_efi_get_loaded_image (grub_efi_image_handle);
if (image && !device)
device = grub_efidisk_get_device_name (image->device_handle);
if (image)
{
if (!device)
device = grub_efidisk_get_device_name (image->device_handle);
else if (device[0] == ',' || !device[0])
{
/* We have a partition, but still need to fill in the drive. */
char *image_device, *comma, *new_device;
image_device = grub_efidisk_get_device_name (image->device_handle);
comma = grub_strchr (image_device, ',');
if (comma)
{
char *drive = grub_strndup (image_device, comma - image_device);
new_device = grub_xasprintf ("%s%s", drive, device);
grub_free (drive);
}
else
new_device = grub_xasprintf ("%s%s", image_device, device);
grub_free (image_device);
grub_free (device);
device = new_device;
}
}
if (image && !path)
{

View file

@ -21,7 +21,6 @@
#include <grub/elf.h>
#include <grub/elfload.h>
#include <grub/file.h>
#include <grub/gzio.h>
#include <grub/misc.h>
#include <grub/mm.h>
@ -95,7 +94,7 @@ grub_elf_open (const char *name)
grub_file_t file;
grub_elf_t elf;
file = grub_gzfile_open (name, 1);
file = grub_file_open (name);
if (! file)
return 0;

View file

@ -7,7 +7,20 @@
#elif defined(__sparc__)
#include "../sparc64/cache.S"
#elif defined(__mips__)
#include "../mips/cache.S"
/* On MIPS we must go through standard functions. */
#include <grub/symbol.h>
FUNCTION (grub_cpu_flush_cache)
FUNCTION (grub_arch_sync_caches)
.set nomacro
.set noreorder
lui $t0, %hi(_flush_cache)
addui $t0, $t0, %lo(_flush_cache)
move $a3, $zero
jr $t0
nop
.set reorder
.set macro
#elif defined(__powerpc__)
#include "../powerpc/cache.S"
#else

View file

@ -22,6 +22,7 @@
#include <grub/kernel.h>
#include <grub/misc.h>
#include <grub/emu/misc.h>
#include <grub/disk.h>
void
grub_register_exported_symbols (void)
@ -48,3 +49,21 @@ grub_emu_init (void)
{
grub_no_autoload = 1;
}
#ifdef GRUB_LINKER_HAVE_INIT
void
grub_arch_dl_init_linker (void)
{
}
#endif
void
grub_emu_post_init (void)
{
grub_lvm_fini ();
grub_mdraid_fini ();
grub_raid_fini ();
grub_raid_init ();
grub_mdraid_init ();
grub_lvm_init ();
}

View file

@ -38,3 +38,8 @@ grub_emu_init (void)
{
return;
}
void
grub_emu_post_init (void)
{
}

View file

@ -197,6 +197,8 @@ main (int argc, char *argv[])
grub_init_all ();
grub_emu_post_init ();
/* Make sure that there is a root device. */
if (! root_dev)
{

View file

@ -61,6 +61,15 @@
# include <sys/mount.h>
#endif
#ifdef HAVE_SYS_MNTTAB_H
# include <stdio.h> /* Needed by sys/mnttab.h. */
# include <sys/mnttab.h>
#endif
#ifdef HAVE_SYS_MKDEV_H
# include <sys/mkdev.h> /* makedev */
#endif
int verbosity;
void
@ -282,18 +291,52 @@ grub_get_libzfs_handle (void)
void
grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs)
{
struct statfs mnt;
char *slash;
*poolname = *poolfs = NULL;
if (statfs (dir, &mnt) != 0)
return;
#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
/* FreeBSD and GNU/kFreeBSD. */
{
struct statfs mnt;
if (strcmp (mnt.f_fstypename, "zfs") != 0)
return;
if (statfs (dir, &mnt) != 0)
return;
*poolname = xstrdup (mnt.f_mntfromname);
if (strcmp (mnt.f_fstypename, "zfs") != 0)
return;
*poolname = xstrdup (mnt.f_mntfromname);
}
#elif defined(HAVE_GETEXTMNTENT)
/* Solaris. */
{
struct stat st;
struct extmnttab mnt;
if (stat (dir, &st) != 0)
return;
FILE *mnttab = fopen ("/etc/mnttab", "r");
if (! mnttab)
return;
while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0)
{
if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev
&& !strcmp (mnt.mnt_fstype, "zfs"))
{
*poolname = xstrdup (mnt.mnt_special);
break;
}
}
fclose (mnttab);
}
#endif
if (! *poolname)
return;
slash = strchr (*poolname, '/');
if (slash)

View file

@ -24,6 +24,9 @@
#include <grub/fs.h>
#include <grub/device.h>
grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX];
grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX];
/* Get the device part of the filename NAME. It is enclosed by parentheses. */
char *
grub_file_get_device_name (const char *name)
@ -54,14 +57,15 @@ grub_file_get_device_name (const char *name)
grub_file_t
grub_file_open (const char *name)
{
grub_device_t device;
grub_file_t file = 0;
grub_device_t device = 0;
grub_file_t file = 0, last_file = 0;
char *device_name;
char *file_name;
grub_file_filter_id_t filter;
device_name = grub_file_get_device_name (name);
if (grub_errno)
return 0;
goto fail;
/* Get the file part of NAME. */
file_name = grub_strchr (name, ')');
@ -94,6 +98,19 @@ grub_file_open (const char *name)
if ((file->fs->open) (file, file_name) != GRUB_ERR_NONE)
goto fail;
for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters_enabled);
filter++)
if (grub_file_filters_enabled[filter])
{
last_file = file;
file = grub_file_filters_enabled[filter] (file);
}
if (!file)
grub_file_close (last_file);
grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
sizeof (grub_file_filters_enabled));
return file;
fail:
@ -104,6 +121,9 @@ grub_file_open (const char *name)
grub_free (file);
grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
sizeof (grub_file_filters_enabled));
return 0;
}

View file

@ -51,7 +51,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_DATA_END
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
/*
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).

View file

@ -51,7 +51,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_DATA_END
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
codestart:
movl %eax, EXT_C(grub_ieee1275_entry_fn)

View file

@ -16,7 +16,6 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/machine/init.h>
#include <grub/machine/memory.h>
#include <grub/types.h>
#include <grub/multiboot.h>

View file

@ -100,14 +100,6 @@ VARIABLE(grub_install_dos_part)
.long 0xFFFFFFFF
VARIABLE(grub_install_bsd_part)
.long 0xFFFFFFFF
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_DATA_END
#ifdef APPLE_CC
bss_start:
@ -450,6 +442,16 @@ gate_a20_check_state:
*/
. = _start + GRUB_KERNEL_MACHINE_RAW_SIZE
. = _start + GRUB_KERNEL_MACHINE_PREFIX
VARIABLE(grub_prefix)
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
/*
* grub_exit()

View file

@ -39,7 +39,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_DATA_END
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
codestart:
/* Relocate to low memory. First we figure out our location.

View file

@ -138,11 +138,16 @@ grub_ieee1275_find_options (void)
*/
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY);
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF);
}
if (is_qemu)
/* OpenFirmware hangs on qemu if one requests any memory below 1.5 MiB. */
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM);
{
/* OpenFirmware hangs on qemu if one requests any memory below 1.5 MiB. */
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM);
grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF);
}
if (! grub_ieee1275_finddevice ("/rom/boot-rom", &bootrom))
{

View file

@ -154,7 +154,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_DATA_END
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
#ifdef GRUB_MACHINE_MIPS_YEELOONG
VARIABLE (grub_arch_busclock)
.long 0

View file

@ -990,7 +990,7 @@ grub_abort (void)
grub_exit ();
}
#ifndef APPLE_CC
#if ! defined (APPLE_CC) && !defined (GRUB_UTIL)
/* GCC emits references to abort(). */
void abort (void) __attribute__ ((alias ("grub_abort")));
#endif

View file

@ -39,7 +39,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = _start + GRUB_KERNEL_MACHINE_DATA_END
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
codestart:
li 2, 0

View file

@ -42,7 +42,7 @@ VARIABLE(grub_prefix)
* Leave some breathing room for the prefix.
*/
. = EXT_C(_start) + GRUB_KERNEL_MACHINE_DATA_END
. = EXT_C(_start) + GRUB_KERNEL_MACHINE_PREFIX_END
codestart:
/* Copy the modules past the end of the kernel image.

View file

@ -209,8 +209,16 @@ parse_option (grub_extcmd_t cmd, int key, char *arg, struct grub_arg_list *usr)
if (found == -1)
return -1;
usr[found].set = 1;
usr[found].arg = arg;
if (opt->flags & GRUB_ARG_OPTION_REPEATABLE)
{
usr[found].args[usr[found].set++] = arg;
usr[found].args[usr[found].set] = NULL;
}
else
{
usr[found].set = 1;
usr[found].arg = arg;
}
}
}
@ -230,10 +238,15 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
grub_err_t add_arg (char *s)
{
argl = grub_realloc (argl, (++num) * sizeof (char *));
char **p = argl;
argl = grub_realloc (argl, (++num + 1) * sizeof (char *));
if (! argl)
return grub_errno;
{
grub_free (p);
return grub_errno;
}
argl[num - 1] = s;
argl[num] = NULL;
return 0;
}
@ -310,8 +323,11 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
if (option) {
arglen = option - arg - 2;
option++;
} else
} else {
arglen = grub_strlen (arg) - 2;
if (argv[curarg + 1])
option = argv[curarg + 1][0] == '-' ? 0 : argv[++curarg];
}
opt = find_long (cmd->options, arg + 2, arglen);
if (! opt)
@ -390,3 +406,43 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv,
fail:
return complete;
}
struct grub_arg_list*
grub_arg_list_alloc(grub_extcmd_t extcmd, int argc,
char **argv __attribute__((unused)))
{
int i;
char **args;
unsigned argcnt;
struct grub_arg_list *list;
const struct grub_arg_option *options;
options = extcmd->options;
if (! options)
return 0;
argcnt = 0;
for (i = 0; options[i].doc; i++)
{
if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
argcnt += (argc + 1) / 2 + 1; /* max possible for any option */
}
list = grub_zalloc (sizeof (*list) * i + sizeof (char*) * argcnt);
if (! list)
return 0;
args = (char**) (list + i);
for (i = 0; options[i].doc; i++)
{
list[i].set = 0;
list[i].arg = 0;
if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE)
{
list[i].args = args;
args += argc / 2 + 1;
}
}
return list;
}

View file

@ -59,7 +59,9 @@ extern grub_uint32_t grub_relocator32_ecx;
extern grub_uint32_t grub_relocator32_edx;
extern grub_uint32_t grub_relocator32_eip;
extern grub_uint32_t grub_relocator32_esp;
extern grub_uint32_t grub_relocator32_ebp;
extern grub_uint32_t grub_relocator32_esi;
extern grub_uint32_t grub_relocator32_edi;
extern grub_uint8_t grub_relocator64_start;
extern grub_uint8_t grub_relocator64_end;
@ -165,7 +167,9 @@ grub_relocator32_boot (struct grub_relocator *rel,
grub_relocator32_edx = state.edx;
grub_relocator32_eip = state.eip;
grub_relocator32_esp = state.esp;
grub_relocator32_ebp = state.ebp;
grub_relocator32_esi = state.esi;
grub_relocator32_edi = state.edi;
grub_memmove (get_virtual_current_address (ch), &grub_relocator32_start,
RELOCATOR_SIZEOF (32));

View file

@ -65,13 +65,27 @@ VARIABLE(grub_relocator32_esp)
movl %eax, %esp
/* mov imm32, %eax */
.byte 0xb8
VARIABLE(grub_relocator32_ebp)
.long 0
movl %eax, %ebp
/* mov imm32, %eax */
.byte 0xb8
VARIABLE(grub_relocator32_esi)
.long 0
movl %eax, %esi
/* mov imm32, %eax */
.byte 0xb8
VARIABLE(grub_relocator32_edi)
.long 0
movl %eax, %edi
/* mov imm32, %eax */
.byte 0xb8
VARIABLE(grub_relocator32_eax)

View file

@ -22,11 +22,14 @@
#include <grub/misc.h>
typedef grub_size_t size_t;
typedef int bool;
static const bool true = 1;
static const bool false = 0;
typedef enum { false = 0, true = 1 } bool;
#define ULONG_MAX GRUB_ULONG_MAX
#define UCHAR_MAX 0xff
typedef grub_uint8_t uint8_t;
typedef grub_uint16_t uint16_t;
typedef grub_uint32_t uint32_t;
typedef grub_uint64_t uint64_t;
#endif

180
grub-core/lib/xzembed/xz.h Normal file
View file

@ -0,0 +1,180 @@
/* xz.h - XZ decompressor */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is based on code from XZ embedded project
* http://tukaani.org/xz/embedded.html
*/
#ifndef XZ_H
#define XZ_H
#include <stdint.h>
/**
* enum xz_ret - Return codes
* @XZ_OK: Everything is OK so far. More input or more output
* space is required to continue.
* @XZ_STREAM_END: Operation finished successfully.
* @XZ_MEMLIMIT_ERROR: Not enough memory was preallocated at decoder
* initialization time.
* @XZ_FORMAT_ERROR: File format was not recognized (wrong magic bytes).
* @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
* compression options. In the decoder this means that
* the header CRC32 matches, but the header itself
* specifies something that we don't support.
* @XZ_DATA_ERROR: Compressed data is corrupt.
* @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
* different between multi-call and single-call mode;
* more information below.
*
* In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
* to XZ code cannot consume any input and cannot produce any new output.
* This happens when there is no new input available, or the output buffer
* is full while at least one output byte is still pending. Assuming your
* code is not buggy, you can get this error only when decoding a compressed
* stream that is truncated or otherwise corrupt.
*
* In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
* is too small, or the compressed input is corrupt in a way that makes the
* decoder produce more output than the caller expected. When it is
* (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
* is used instead of XZ_BUF_ERROR.
*/
enum xz_ret {
XZ_OK,
XZ_STREAM_END,
XZ_MEMLIMIT_ERROR,
XZ_FORMAT_ERROR,
XZ_OPTIONS_ERROR,
XZ_DATA_ERROR,
XZ_BUF_ERROR
};
/**
* struct xz_buf - Passing input and output buffers to XZ code
* @in: Beginning of the input buffer. This may be NULL if and only
* if in_pos is equal to in_size.
* @in_pos: Current position in the input buffer. This must not exceed
* in_size.
* @in_size: Size of the input buffer
* @out: Beginning of the output buffer. This may be NULL if and only
* if out_pos is equal to out_size.
* @out_pos: Current position in the output buffer. This must not exceed
* out_size.
* @out_size: Size of the output buffer
*
* Only the contents of the output buffer from out[out_pos] onward, and
* the variables in_pos and out_pos are modified by the XZ code.
*/
struct xz_buf {
const uint8_t *in;
size_t in_pos;
size_t in_size;
uint8_t *out;
size_t out_pos;
size_t out_size;
};
/**
* struct xz_dec - Opaque type to hold the XZ decoder state
*/
struct xz_dec;
/**
* xz_dec_init() - Allocate and initialize a XZ decoder state
* @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
* multi-call decoding, or special value of zero to indicate
* single-call decoding mode.
*
* If dict_max > 0, the decoder is initialized to work in multi-call mode.
* dict_max number of bytes of memory is preallocated for the LZMA2
* dictionary. This way there is no risk that xz_dec_run() could run out
* of memory, since xz_dec_run() will never allocate any memory. Instead,
* if the preallocated dictionary is too small for decoding the given input
* stream, xz_dec_run() will return XZ_MEMLIMIT_ERROR. Thus, it is important
* to know what kind of data will be decoded to avoid allocating excessive
* amount of memory for the dictionary.
*
* LZMA2 dictionary is always 2^n bytes or 2^n + 2^(n-1) bytes (the latter
* sizes are less common in practice). In the kernel, dictionary sizes of
* 64 KiB, 128 KiB, 256 KiB, 512 KiB, and 1 MiB are probably the only
* reasonable values.
*
* If dict_max == 0, the decoder is initialized to work in single-call mode.
* In single-call mode, xz_dec_run() decodes the whole stream at once. The
* caller must provide enough output space or the decoding will fail. The
* output space is used as the dictionary buffer, which is why there is
* no need to allocate the dictionary as part of the decoder's internal
* state.
*
* Because the output buffer is used as the workspace, streams encoded using
* a big dictionary are not a problem in single-call. It is enough that the
* output buffer is is big enough to hold the actual uncompressed data; it
* can be smaller than the dictionary size stored in the stream headers.
*
* On success, xz_dec_init() returns a pointer to struct xz_dec, which is
* ready to be used with xz_dec_run(). On error, xz_dec_init() returns NULL.
*/
struct xz_dec * xz_dec_init(uint32_t dict_max);
/**
* xz_dec_run() - Run the XZ decoder
* @s: Decoder state allocated using xz_dec_init()
* @b: Input and output buffers
*
* In multi-call mode, this function may return any of the values listed in
* enum xz_ret.
*
* In single-call mode, this function never returns XZ_OK. If an error occurs
* in single-call mode (return value is not XZ_STREAM_END), b->in_pos and
* b->out_pos are not modified, and the contents of the output buffer from
* b->out[b->out_pos] onward are undefined.
*
* NOTE: In single-call mode, the contents of the output buffer are undefined
* also after XZ_BUF_ERROR. This is because with some filter chains, there
* may be a second pass over the output buffer, and this pass cannot be
* properly done if the output buffer is truncated. Thus, you cannot give
* the single-call decoder a too small buffer and then expect to get that
* amount valid data from the beginning of the stream. You must use the
* multi-call decoder if you don't want to uncompress the whole stream.
*/
enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
/**
* xz_dec_reset() - Reset an already allocated decoder state
* @s: Decoder state allocated using xz_dec_init()
*
* This function can be used to reset the multi-call decoder state without
* freeing and reallocating memory with xz_dec_end() and xz_dec_init().
*
* In single-call mode, xz_dec_reset() is always called in the beginning of
* xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
* multi-call mode.
*/
void xz_dec_reset(struct xz_dec *s);
/**
* xz_dec_end() - Free the memory allocated for the decoder state
* @s: Decoder state allocated using xz_dec_init(). If s is NULL,
* this function does nothing.
*/
void xz_dec_end(struct xz_dec *s);
#endif

View file

@ -0,0 +1,141 @@
/* xz_config.h - Private includes and definitions for userspace use */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is based on code from XZ embedded project
* http://tukaani.org/xz/embedded.html
*/
#ifndef XZ_CONFIG_H
#define XZ_CONFIG_H
/* Enable BCJ filter decoders. */
#if defined(__i386__) || defined(__x86_64__)
#define XZ_DEC_X86
#endif
#ifdef __powerpc__
#define XZ_DEC_POWERPC
#endif
#ifdef __ia64__
#define XZ_DEC_IA64
#endif
#ifdef __arm__
#define XZ_DEC_ARM
#endif
#ifdef __thumb__
#define XZ_DEC_ARMTHUMB
#endif
#ifdef __sparc__
#define XZ_DEC_SPARC
#endif
#include "xz.h"
#include <stdlib.h>
#define kmalloc(size, flags) malloc(size)
#define kfree(ptr) free(ptr)
#define vmalloc(size) malloc(size)
#define vfree(ptr) free(ptr)
#define memeq(a, b, size) (memcmp(a, b, size) == 0)
#define memzero(buf, size) memset(buf, 0, size)
#define min(x, y) ((x) < (y) ? (x) : (y))
#define min_t(type, x, y) min(x, y)
/*
* Some functions have been marked with __always_inline to keep the
* performance reasonable even when the compiler is optimizing for
* small code size. You may be able to save a few bytes by #defining
* __always_inline to plain inline, but don't complain if the code
* becomes slow.
*
* NOTE: System headers on GNU/Linux may #define this macro already,
* so if you want to change it, it you need to #undef it first.
*/
#ifndef __always_inline
# ifdef __GNUC__
# define __always_inline \
inline __attribute__((__always_inline__))
# else
# define __always_inline inline
# endif
#endif
/*
* Some functions are marked to never be inlined to reduce stack usage.
* If you don't care about stack usage, you may want to modify this so
* that noinline_for_stack is #defined to be empty even when using GCC.
* Doing so may save a few bytes in binary size.
*/
#ifndef noinline_for_stack
# ifdef __GNUC__
# define noinline_for_stack __attribute__((__noinline__))
# else
# define noinline_for_stack
# endif
#endif
/* Inline functions to access unaligned unsigned 32-bit integers */
static inline uint32_t get_unaligned_le32(const uint8_t *buf)
{
return (uint32_t)buf[0]
| ((uint32_t)buf[1] << 8)
| ((uint32_t)buf[2] << 16)
| ((uint32_t)buf[3] << 24);
}
static inline uint32_t get_unaligned_be32(const uint8_t *buf)
{
return (uint32_t)(buf[0] << 24)
| ((uint32_t)buf[1] << 16)
| ((uint32_t)buf[2] << 8)
| (uint32_t)buf[3];
}
static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
{
buf[0] = (uint8_t)val;
buf[1] = (uint8_t)(val >> 8);
buf[2] = (uint8_t)(val >> 16);
buf[3] = (uint8_t)(val >> 24);
}
static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
{
buf[0] = (uint8_t)(val >> 24);
buf[1] = (uint8_t)(val >> 16);
buf[2] = (uint8_t)(val >> 8);
buf[3] = (uint8_t)val;
}
/*
* Use get_unaligned_le32() also for aligned access for simplicity. On
* little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
* could save a few bytes in code size.
*/
#define get_le32 get_unaligned_le32
#endif

View file

@ -0,0 +1,569 @@
/* xz_dec_bcj.c - Branch/Call/Jump (BCJ) filter decoders */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is based on code from XZ embedded project
* http://tukaani.org/xz/embedded.html
*/
#include "xz_private.h"
struct xz_dec_bcj {
/* Type of the BCJ filter being used */
enum {
BCJ_X86 = 4, /* x86 or x86-64 */
BCJ_POWERPC = 5, /* Big endian only */
BCJ_IA64 = 6, /* Big or little endian */
BCJ_ARM = 7, /* Little endian only */
BCJ_ARMTHUMB = 8, /* Little endian only */
BCJ_SPARC = 9 /* Big or little endian */
} type;
/*
* Return value of the next filter in the chain. We need to preserve
* this information across calls, because we must not call the next
* filter anymore once it has returned XZ_STREAM_END.
*/
enum xz_ret ret;
/* True if we are operating in single-call mode. */
bool single_call;
/*
* Absolute position relative to the beginning of the uncompressed
* data (in a single .xz Block). We care only about the lowest 32
* bits so this doesn't need to be uint64_t even with big files.
*/
uint32_t pos;
/* x86 filter state */
uint32_t x86_prev_mask;
/* Temporary space to hold the variables from struct xz_buf */
uint8_t *out;
size_t out_pos;
size_t out_size;
struct {
/* Amount of already filtered data in the beginning of buf */
size_t filtered;
/* Total amount of data currently stored in buf */
size_t size;
/*
* Buffer to hold a mix of filtered and unfiltered data. This
* needs to be big enough to hold Alignment + 2 * Look-ahead:
*
* Type Alignment Look-ahead
* x86 1 4
* PowerPC 4 0
* IA-64 16 0
* ARM 4 0
* ARM-Thumb 2 2
* SPARC 4 0
*/
uint8_t buf[16];
} temp;
};
#ifdef XZ_DEC_X86
/*
* This is macro used to test the most significant byte of a memory address
* in an x86 instruction.
*/
#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF)
static noinline_for_stack size_t bcj_x86(
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
static const bool mask_to_allowed_status[8]
= { true, true, true, false, true, false, false, false };
static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
size_t i;
size_t prev_pos = (size_t)-1;
uint32_t prev_mask = s->x86_prev_mask;
uint32_t src;
uint32_t dest;
uint32_t j;
uint8_t b;
if (size <= 4)
return 0;
size -= 4;
for (i = 0; i < size; ++i) {
if ((buf[i] & 0xFE) != 0xE8)
continue;
prev_pos = i - prev_pos;
if (prev_pos > 3) {
prev_mask = 0;
} else {
prev_mask = (prev_mask << (prev_pos - 1)) & 7;
if (prev_mask != 0) {
b = buf[i + 4 - mask_to_bit_num[prev_mask]];
if (!mask_to_allowed_status[prev_mask]
|| bcj_x86_test_msbyte(b)) {
prev_pos = i;
prev_mask = (prev_mask << 1) | 1;
continue;
}
}
}
prev_pos = i;
if (bcj_x86_test_msbyte(buf[i + 4])) {
src = get_unaligned_le32(buf + i + 1);
while (true) {
dest = src - (s->pos + (uint32_t)i + 5);
if (prev_mask == 0)
break;
j = mask_to_bit_num[prev_mask] * 8;
b = (uint8_t)(dest >> (24 - j));
if (!bcj_x86_test_msbyte(b))
break;
src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
}
dest &= 0x01FFFFFF;
dest |= (uint32_t)0 - (dest & 0x01000000);
put_unaligned_le32(dest, buf + i + 1);
i += 4;
} else {
prev_mask = (prev_mask << 1) | 1;
}
}
prev_pos = i - prev_pos;
s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
return i;
}
#endif
#ifdef XZ_DEC_POWERPC
static noinline_for_stack size_t bcj_powerpc(
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t instr;
for (i = 0; i + 4 <= size; i += 4) {
instr = get_unaligned_be32(buf + i);
if ((instr & 0xFC000003) == 0x48000001) {
instr &= 0x03FFFFFC;
instr -= s->pos + (uint32_t)i;
instr &= 0x03FFFFFC;
instr |= 0x48000001;
put_unaligned_be32(instr, buf + i);
}
}
return i;
}
#endif
#ifdef XZ_DEC_IA64
static noinline_for_stack size_t bcj_ia64(
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
static const uint8_t branch_table[32] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 4, 6, 6, 0, 0, 7, 7,
4, 4, 0, 0, 4, 4, 0, 0
};
/*
* The local variables take a little bit stack space, but it's less
* than what LZMA2 decoder takes, so it doesn't make sense to reduce
* stack usage here without doing that for the LZMA2 decoder too.
*/
/* Loop counters */
size_t i;
size_t j;
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
uint32_t slot;
/* Bitwise offset of the instruction indicated by slot */
uint32_t bit_pos;
/* bit_pos split into byte and bit parts */
uint32_t byte_pos;
uint32_t bit_res;
/* Address part of an instruction */
uint32_t addr;
/* Mask used to detect which instructions to convert */
uint32_t mask;
/* 41-bit instruction stored somewhere in the lowest 48 bits */
uint64_t instr;
/* Instruction normalized with bit_res for easier manipulation */
uint64_t norm;
for (i = 0; i + 16 <= size; i += 16) {
mask = branch_table[buf[i] & 0x1F];
for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
if (((mask >> slot) & 1) == 0)
continue;
byte_pos = bit_pos >> 3;
bit_res = bit_pos & 7;
instr = 0;
for (j = 0; j < 6; ++j)
instr |= (uint64_t)(buf[i + j + byte_pos])
<< (8 * j);
norm = instr >> bit_res;
if (((norm >> 37) & 0x0F) == 0x05
&& ((norm >> 9) & 0x07) == 0) {
addr = (norm >> 13) & 0x0FFFFF;
addr |= ((uint32_t)(norm >> 36) & 1) << 20;
addr <<= 4;
addr -= s->pos + (uint32_t)i;
addr >>= 4;
norm &= ~((uint64_t)0x8FFFFF << 13);
norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
norm |= (uint64_t)(addr & 0x100000)
<< (36 - 20);
instr &= (1 << bit_res) - 1;
instr |= norm << bit_res;
for (j = 0; j < 6; j++)
buf[i + j + byte_pos]
= (uint8_t)(instr >> (8 * j));
}
}
}
return i;
}
#endif
#ifdef XZ_DEC_ARM
static noinline_for_stack size_t bcj_arm(
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t addr;
for (i = 0; i + 4 <= size; i += 4) {
if (buf[i + 3] == 0xEB) {
addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
| ((uint32_t)buf[i + 2] << 16);
addr <<= 2;
addr -= s->pos + (uint32_t)i + 8;
addr >>= 2;
buf[i] = (uint8_t)addr;
buf[i + 1] = (uint8_t)(addr >> 8);
buf[i + 2] = (uint8_t)(addr >> 16);
}
}
return i;
}
#endif
#ifdef XZ_DEC_ARMTHUMB
static noinline_for_stack size_t bcj_armthumb(
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t addr;
for (i = 0; i + 4 <= size; i += 2) {
if ((buf[i + 1] & 0xF8) == 0xF0
&& (buf[i + 3] & 0xF8) == 0xF8) {
addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
| ((uint32_t)buf[i] << 11)
| (((uint32_t)buf[i + 3] & 0x07) << 8)
| (uint32_t)buf[i + 2];
addr <<= 1;
addr -= s->pos + (uint32_t)i + 4;
addr >>= 1;
buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
buf[i] = (uint8_t)(addr >> 11);
buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
buf[i + 2] = (uint8_t)addr;
i += 2;
}
}
return i;
}
#endif
#ifdef XZ_DEC_SPARC
static noinline_for_stack size_t bcj_sparc(
struct xz_dec_bcj *s, uint8_t *buf, size_t size)
{
size_t i;
uint32_t instr;
for (i = 0; i + 4 <= size; i += 4) {
instr = get_unaligned_be32(buf + i);
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
instr <<= 2;
instr -= s->pos + (uint32_t)i;
instr >>= 2;
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
| 0x40000000 | (instr & 0x3FFFFF);
put_unaligned_be32(instr, buf + i);
}
}
return i;
}
#endif
/*
* Apply the selected BCJ filter. Update *pos and s->pos to match the amount
* of data that got filtered.
*
* NOTE: This is implemented as a switch statement to avoid using function
* pointers, which could be problematic in the kernel boot code, which must
* avoid pointers to static data (at least on x86).
*/
static void bcj_apply(struct xz_dec_bcj *s,
uint8_t *buf, size_t *pos, size_t size)
{
size_t filtered;
buf += *pos;
size -= *pos;
switch (s->type) {
#ifdef XZ_DEC_X86
case BCJ_X86:
filtered = bcj_x86(s, buf, size);
break;
#endif
#ifdef XZ_DEC_POWERPC
case BCJ_POWERPC:
filtered = bcj_powerpc(s, buf, size);
break;
#endif
#ifdef XZ_DEC_IA64
case BCJ_IA64:
filtered = bcj_ia64(s, buf, size);
break;
#endif
#ifdef XZ_DEC_ARM
case BCJ_ARM:
filtered = bcj_arm(s, buf, size);
break;
#endif
#ifdef XZ_DEC_ARMTHUMB
case BCJ_ARMTHUMB:
filtered = bcj_armthumb(s, buf, size);
break;
#endif
#ifdef XZ_DEC_SPARC
case BCJ_SPARC:
filtered = bcj_sparc(s, buf, size);
break;
#endif
default:
/* Never reached but silence compiler warnings. */
filtered = 0;
break;
}
*pos += filtered;
s->pos += filtered;
}
/*
* Flush pending filtered data from temp to the output buffer.
* Move the remaining mixture of possibly filtered and unfiltered
* data to the beginning of temp.
*/
static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
{
size_t copy_size;
copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
b->out_pos += copy_size;
s->temp.filtered -= copy_size;
s->temp.size -= copy_size;
memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
}
/*
* The BCJ filter functions are primitive in sense that they process the
* data in chunks of 1-16 bytes. To hide this issue, this function does
* some buffering.
*/
enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
struct xz_dec_lzma2 *lzma2, struct xz_buf *b)
{
size_t out_start;
/*
* Flush pending already filtered data to the output buffer. Return
* immediatelly if we couldn't flush everything, or if the next
* filter in the chain had already returned XZ_STREAM_END.
*/
if (s->temp.filtered > 0) {
bcj_flush(s, b);
if (s->temp.filtered > 0)
return XZ_OK;
if (s->ret == XZ_STREAM_END)
return XZ_STREAM_END;
}
/*
* If we have more output space than what is currently pending in
* temp, copy the unfiltered data from temp to the output buffer
* and try to fill the output buffer by decoding more data from the
* next filter in the chain. Apply the BCJ filter on the new data
* in the output buffer. If everything cannot be filtered, copy it
* to temp and rewind the output buffer position accordingly.
*/
if (s->temp.size < b->out_size - b->out_pos) {
out_start = b->out_pos;
memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
b->out_pos += s->temp.size;
s->ret = xz_dec_lzma2_run(lzma2, b);
if (s->ret != XZ_STREAM_END
&& (s->ret != XZ_OK || s->single_call))
return s->ret;
bcj_apply(s, b->out, &out_start, b->out_pos);
/*
* As an exception, if the next filter returned XZ_STREAM_END,
* we can do that too, since the last few bytes that remain
* unfiltered are meant to remain unfiltered.
*/
if (s->ret == XZ_STREAM_END)
return XZ_STREAM_END;
s->temp.size = b->out_pos - out_start;
b->out_pos -= s->temp.size;
memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
}
/*
* If we have unfiltered data in temp, try to fill by decoding more
* data from the next filter. Apply the BCJ filter on temp. Then we
* hopefully can fill the actual output buffer by copying filtered
* data from temp. A mix of filtered and unfiltered data may be left
* in temp; it will be taken care on the next call to this function.
*/
if (s->temp.size > 0) {
/* Make b->out{,_pos,_size} temporarily point to s->temp. */
s->out = b->out;
s->out_pos = b->out_pos;
s->out_size = b->out_size;
b->out = s->temp.buf;
b->out_pos = s->temp.size;
b->out_size = sizeof(s->temp.buf);
s->ret = xz_dec_lzma2_run(lzma2, b);
s->temp.size = b->out_pos;
b->out = s->out;
b->out_pos = s->out_pos;
b->out_size = s->out_size;
if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
return s->ret;
bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
/*
* If the next filter returned XZ_STREAM_END, we mark that
* everything is filtered, since the last unfiltered bytes
* of the stream are meant to be left as is.
*/
if (s->ret == XZ_STREAM_END)
s->temp.filtered = s->temp.size;
bcj_flush(s, b);
if (s->temp.filtered > 0)
return XZ_OK;
}
return s->ret;
}
struct xz_dec_bcj * xz_dec_bcj_create(bool single_call)
{
struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (s != NULL)
s->single_call = single_call;
return s;
}
enum xz_ret xz_dec_bcj_reset(
struct xz_dec_bcj *s, uint8_t id)
{
switch (id) {
#ifdef XZ_DEC_X86
case BCJ_X86:
#endif
#ifdef XZ_DEC_POWERPC
case BCJ_POWERPC:
#endif
#ifdef XZ_DEC_IA64
case BCJ_IA64:
#endif
#ifdef XZ_DEC_ARM
case BCJ_ARM:
#endif
#ifdef XZ_DEC_ARMTHUMB
case BCJ_ARMTHUMB:
#endif
#ifdef XZ_DEC_SPARC
case BCJ_SPARC:
#endif
break;
default:
/* Unsupported Filter ID */
return XZ_OPTIONS_ERROR;
}
s->type = id;
s->ret = XZ_OK;
s->pos = 0;
s->x86_prev_mask = 0;
s->temp.filtered = 0;
s->temp.size = 0;
return XZ_OK;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,854 @@
/* xz_dec_stream.c - .xz Stream decoder */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is based on code from XZ embedded project
* http://tukaani.org/xz/embedded.html
*/
#include "xz_config.h"
#include "xz_private.h"
#include "xz_stream.h"
#include <grub/crypto.h>
/* Hash used to validate the Index field */
struct xz_dec_hash {
vli_type unpadded;
vli_type uncompressed;
uint8_t *crc32_context;
};
struct xz_dec {
/* Position in dec_main() */
enum {
SEQ_STREAM_HEADER,
SEQ_BLOCK_START,
SEQ_BLOCK_HEADER,
SEQ_BLOCK_UNCOMPRESS,
SEQ_BLOCK_PADDING,
SEQ_BLOCK_CHECK,
SEQ_INDEX,
SEQ_INDEX_PADDING,
SEQ_INDEX_CRC32,
SEQ_STREAM_FOOTER
} sequence;
/* Position in variable-length integers and Check fields */
uint32_t pos;
/* Variable-length integer decoded by dec_vli() */
vli_type vli;
/* Saved in_pos and out_pos */
size_t in_start;
size_t out_start;
/* CRC32 value in Block or Index */
uint32_t crc32_temp; /* need for crc32_validate*/
uint8_t *crc32_context;
/* True if CRC32 is calculated from uncompressed data */
bool has_crc32;
/* True if we are operating in single-call mode. */
bool single_call;
/*
* True if the next call to xz_dec_run() is allowed to return
* XZ_BUF_ERROR.
*/
bool allow_buf_error;
/* Information stored in Block Header */
struct {
/*
* Value stored in the Compressed Size field, or
* VLI_UNKNOWN if Compressed Size is not present.
*/
vli_type compressed;
/*
* Value stored in the Uncompressed Size field, or
* VLI_UNKNOWN if Uncompressed Size is not present.
*/
vli_type uncompressed;
/* Size of the Block Header field */
uint32_t size;
} block_header;
/* Information collected when decoding Blocks */
struct {
/* Observed compressed size of the current Block */
vli_type compressed;
/* Observed uncompressed size of the current Block */
vli_type uncompressed;
/* Number of Blocks decoded so far */
vli_type count;
/*
* Hash calculated from the Block sizes. This is used to
* validate the Index field.
*/
struct xz_dec_hash hash;
} block;
/* Variables needed when verifying the Index field */
struct {
/* Position in dec_index() */
enum {
SEQ_INDEX_COUNT,
SEQ_INDEX_UNPADDED,
SEQ_INDEX_UNCOMPRESSED
} sequence;
/* Size of the Index in bytes */
vli_type size;
/* Number of Records (matches block.count in valid files) */
vli_type count;
/*
* Hash calculated from the Records (matches block.hash in
* valid files).
*/
struct xz_dec_hash hash;
} index;
/*
* Temporary buffer needed to hold Stream Header, Block Header,
* and Stream Footer. The Block Header is the biggest (1 KiB)
* so we reserve space according to that. buf[] has to be aligned
* to a multiple of four bytes; the size_t variables before it
* should guarantee this.
*/
struct {
size_t pos;
size_t size;
uint8_t buf[1024];
} temp;
struct xz_dec_lzma2 *lzma2;
#ifdef XZ_DEC_BCJ
struct xz_dec_bcj *bcj;
bool bcj_active;
#endif
};
/*
* Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
* must have set s->temp.pos to indicate how much data we are supposed
* to copy into s->temp.buf. Return true once s->temp.pos has reached
* s->temp.size.
*/
static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
{
size_t copy_size = min_t(size_t,
b->in_size - b->in_pos, s->temp.size - s->temp.pos);
memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
b->in_pos += copy_size;
s->temp.pos += copy_size;
if (s->temp.pos == s->temp.size) {
s->temp.pos = 0;
return true;
}
return false;
}
/* Decode a variable-length integer (little-endian base-128 encoding) */
static enum xz_ret dec_vli(struct xz_dec *s,
const uint8_t *in, size_t *in_pos, size_t in_size)
{
uint8_t byte;
if (s->pos == 0)
s->vli = 0;
while (*in_pos < in_size) {
byte = in[*in_pos];
++*in_pos;
s->vli |= (vli_type)(byte & 0x7F) << s->pos;
if ((byte & 0x80) == 0) {
/* Don't allow non-minimal encodings. */
if (byte == 0 && s->pos != 0)
return XZ_DATA_ERROR;
s->pos = 0;
return XZ_STREAM_END;
}
s->pos += 7;
if (s->pos == 7 * VLI_BYTES_MAX)
return XZ_DATA_ERROR;
}
return XZ_OK;
}
/*
* Decode the Compressed Data field from a Block. Update and validate
* the observed compressed and uncompressed sizes of the Block so that
* they don't exceed the values possibly stored in the Block Header
* (validation assumes that no integer overflow occurs, since vli_type
* is normally uint64_t). Update the CRC32 if presence of the CRC32
* field was indicated in Stream Header.
*
* Once the decoding is finished, validate that the observed sizes match
* the sizes possibly stored in the Block Header. Update the hash and
* Block count, which are later used to validate the Index field.
*/
static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
{
enum xz_ret ret;
s->in_start = b->in_pos;
s->out_start = b->out_pos;
#ifdef XZ_DEC_BCJ
if (s->bcj_active)
ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
else
#endif
ret = xz_dec_lzma2_run(s->lzma2, b);
s->block.compressed += b->in_pos - s->in_start;
s->block.uncompressed += b->out_pos - s->out_start;
/*
* There is no need to separately check for VLI_UNKNOWN, since
* the observed sizes are always smaller than VLI_UNKNOWN.
*/
if (s->block.compressed > s->block_header.compressed
|| s->block.uncompressed
> s->block_header.uncompressed)
return XZ_DATA_ERROR;
if (s->has_crc32)
GRUB_MD_CRC32->write(s->crc32_context,b->out + s->out_start,
b->out_pos - s->out_start);
if (ret == XZ_STREAM_END) {
if (s->block_header.compressed != VLI_UNKNOWN
&& s->block_header.compressed
!= s->block.compressed)
return XZ_DATA_ERROR;
if (s->block_header.uncompressed != VLI_UNKNOWN
&& s->block_header.uncompressed
!= s->block.uncompressed)
return XZ_DATA_ERROR;
s->block.hash.unpadded += s->block_header.size
+ s->block.compressed;
if (s->has_crc32)
s->block.hash.unpadded += 4;
s->block.hash.uncompressed += s->block.uncompressed;
GRUB_MD_CRC32->write(s->block.hash.crc32_context,
(const uint8_t *)&s->block.hash, sizeof(s->block.hash));
++s->block.count;
}
return ret;
}
/* Update the Index size and the CRC32 value. */
static void index_update(struct xz_dec *s, const struct xz_buf *b)
{
size_t in_used = b->in_pos - s->in_start;
s->index.size += in_used;
GRUB_MD_CRC32->write(s->crc32_context,b->in + s->in_start, in_used);
}
/*
* Decode the Number of Records, Unpadded Size, and Uncompressed Size
* fields from the Index field. That is, Index Padding and CRC32 are not
* decoded by this function.
*
* This can return XZ_OK (more input needed), XZ_STREAM_END (everything
* successfully decoded), or XZ_DATA_ERROR (input is corrupt).
*/
static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
{
enum xz_ret ret;
do {
ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
if (ret != XZ_STREAM_END) {
index_update(s, b);
return ret;
}
switch (s->index.sequence) {
case SEQ_INDEX_COUNT:
s->index.count = s->vli;
/*
* Validate that the Number of Records field
* indicates the same number of Records as
* there were Blocks in the Stream.
*/
if (s->index.count != s->block.count)
return XZ_DATA_ERROR;
s->index.sequence = SEQ_INDEX_UNPADDED;
break;
case SEQ_INDEX_UNPADDED:
s->index.hash.unpadded += s->vli;
s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
break;
case SEQ_INDEX_UNCOMPRESSED:
s->index.hash.uncompressed += s->vli;
GRUB_MD_CRC32->write(s->index.hash.crc32_context,
(const uint8_t *)&s->index.hash,
sizeof(s->index.hash));
--s->index.count;
s->index.sequence = SEQ_INDEX_UNPADDED;
break;
}
} while (s->index.count > 0);
return XZ_STREAM_END;
}
/*
* Validate that the next four input bytes match the value of s->crc32.
* s->pos must be zero when starting to validate the first byte.
*/
static enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b)
{
if(s->crc32_temp == 0)
{
GRUB_MD_CRC32->final(s->crc32_context);
s->crc32_temp = get_unaligned_be32(GRUB_MD_CRC32->read(s->crc32_context));
}
do {
if (b->in_pos == b->in_size)
return XZ_OK;
if (((s->crc32_temp >> s->pos) & 0xFF) != b->in[b->in_pos++])
return XZ_DATA_ERROR;
s->pos += 8;
} while (s->pos < 32);
GRUB_MD_CRC32->init(s->crc32_context);
s->crc32_temp = 0;
s->pos = 0;
return XZ_STREAM_END;
}
/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
static enum xz_ret dec_stream_header(struct xz_dec *s)
{
if (! memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
return XZ_FORMAT_ERROR;
uint8_t crc32_context[GRUB_MD_CRC32->contextsize];
GRUB_MD_CRC32->init(crc32_context);
GRUB_MD_CRC32->write(crc32_context,s->temp.buf + HEADER_MAGIC_SIZE, 2);
GRUB_MD_CRC32->final(crc32_context);
uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context));
uint32_t readcrc = get_unaligned_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2);
if(resultcrc != readcrc)
return XZ_DATA_ERROR;
/*
* Decode the Stream Flags field. Of integrity checks, we support
* only none (Check ID = 0) and CRC32 (Check ID = 1).
*/
if (s->temp.buf[HEADER_MAGIC_SIZE] != 0
|| s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1)
return XZ_OPTIONS_ERROR;
s->has_crc32 = s->temp.buf[HEADER_MAGIC_SIZE + 1];
return XZ_OK;
}
/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
static enum xz_ret dec_stream_footer(struct xz_dec *s)
{
if (! memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
return XZ_DATA_ERROR;
uint8_t crc32_context[GRUB_MD_CRC32->contextsize];
GRUB_MD_CRC32->init(crc32_context);
GRUB_MD_CRC32->write(crc32_context, s->temp.buf + 4, 6);
GRUB_MD_CRC32->final(crc32_context);
uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context));
uint32_t readcrc = get_unaligned_le32(s->temp.buf);
if(resultcrc != readcrc)
return XZ_DATA_ERROR;
/*
* Validate Backward Size. Note that we never added the size of the
* Index CRC32 field to s->index.size, thus we use s->index.size / 4
* instead of s->index.size / 4 - 1.
*/
if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
return XZ_DATA_ERROR;
if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->has_crc32)
return XZ_DATA_ERROR;
/*
* Use XZ_STREAM_END instead of XZ_OK to be more convenient
* for the caller.
*/
return XZ_STREAM_END;
}
/* Decode the Block Header and initialize the filter chain. */
static enum xz_ret dec_block_header(struct xz_dec *s)
{
enum xz_ret ret;
/*
* Validate the CRC32. We know that the temp buffer is at least
* eight bytes so this is safe.
*/
s->temp.size -= 4;
uint8_t crc32_context[GRUB_MD_CRC32->contextsize];
GRUB_MD_CRC32->init(crc32_context);
GRUB_MD_CRC32->write(crc32_context, s->temp.buf, s->temp.size);
GRUB_MD_CRC32->final(crc32_context);
uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context));
uint32_t readcrc = get_unaligned_le32(s->temp.buf + s->temp.size);
if (resultcrc != readcrc)
return XZ_DATA_ERROR;
s->temp.pos = 2;
/*
* Catch unsupported Block Flags. We support only one or two filters
* in the chain, so we catch that with the same test.
*/
#ifdef XZ_DEC_BCJ
if (s->temp.buf[1] & 0x3E)
#else
if (s->temp.buf[1] & 0x3F)
#endif
return XZ_OPTIONS_ERROR;
/* Compressed Size */
if (s->temp.buf[1] & 0x40) {
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
!= XZ_STREAM_END)
return XZ_DATA_ERROR;
s->block_header.compressed = s->vli;
} else {
s->block_header.compressed = VLI_UNKNOWN;
}
/* Uncompressed Size */
if (s->temp.buf[1] & 0x80) {
if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
!= XZ_STREAM_END)
return XZ_DATA_ERROR;
s->block_header.uncompressed = s->vli;
} else {
s->block_header.uncompressed = VLI_UNKNOWN;
}
#ifdef XZ_DEC_BCJ
/* If there are two filters, the first one must be a BCJ filter. */
s->bcj_active = s->temp.buf[1] & 0x01;
if (s->bcj_active) {
if (s->temp.size - s->temp.pos < 2)
return XZ_OPTIONS_ERROR;
ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
if (ret != XZ_OK)
return ret;
/*
* We don't support custom start offset,
* so Size of Properties must be zero.
*/
if (s->temp.buf[s->temp.pos++] != 0x00)
return XZ_OPTIONS_ERROR;
}
#endif
/* Valid Filter Flags always take at least two bytes. */
if (s->temp.size - s->temp.pos < 2)
return XZ_DATA_ERROR;
/* Filter ID = LZMA2 */
if (s->temp.buf[s->temp.pos++] != 0x21)
return XZ_OPTIONS_ERROR;
/* Size of Properties = 1-byte Filter Properties */
if (s->temp.buf[s->temp.pos++] != 0x01)
return XZ_OPTIONS_ERROR;
/* Filter Properties contains LZMA2 dictionary size. */
if (s->temp.size - s->temp.pos < 1)
return XZ_DATA_ERROR;
ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
if (ret != XZ_OK)
return ret;
/* The rest must be Header Padding. */
while (s->temp.pos < s->temp.size)
if (s->temp.buf[s->temp.pos++] != 0x00)
return XZ_OPTIONS_ERROR;
s->temp.pos = 0;
s->block.compressed = 0;
s->block.uncompressed = 0;
return XZ_OK;
}
static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
{
enum xz_ret ret;
/*
* Store the start position for the case when we are in the middle
* of the Index field.
*/
s->in_start = b->in_pos;
while (true) {
switch (s->sequence) {
case SEQ_STREAM_HEADER:
/*
* Stream Header is copied to s->temp, and then
* decoded from there. This way if the caller
* gives us only little input at a time, we can
* still keep the Stream Header decoding code
* simple. Similar approach is used in many places
* in this file.
*/
if (!fill_temp(s, b))
return XZ_OK;
ret = dec_stream_header(s);
if (ret != XZ_OK)
return ret;
s->sequence = SEQ_BLOCK_START;
case SEQ_BLOCK_START:
/* We need one byte of input to continue. */
if (b->in_pos == b->in_size)
return XZ_OK;
/* See if this is the beginning of the Index field. */
if (b->in[b->in_pos] == 0) {
s->in_start = b->in_pos++;
s->sequence = SEQ_INDEX;
break;
}
/*
* Calculate the size of the Block Header and
* prepare to decode it.
*/
s->block_header.size
= ((uint32_t)b->in[b->in_pos] + 1) * 4;
s->temp.size = s->block_header.size;
s->temp.pos = 0;
s->sequence = SEQ_BLOCK_HEADER;
case SEQ_BLOCK_HEADER:
if (!fill_temp(s, b))
return XZ_OK;
ret = dec_block_header(s);
if (ret != XZ_OK)
return ret;
s->sequence = SEQ_BLOCK_UNCOMPRESS;
case SEQ_BLOCK_UNCOMPRESS:
ret = dec_block(s, b);
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_BLOCK_PADDING;
case SEQ_BLOCK_PADDING:
/*
* Size of Compressed Data + Block Padding
* must be a multiple of four. We don't need
* s->block.compressed for anything else
* anymore, so we use it here to test the size
* of the Block Padding field.
*/
while (s->block.compressed & 3) {
if (b->in_pos == b->in_size)
return XZ_OK;
if (b->in[b->in_pos++] != 0)
return XZ_DATA_ERROR;
++s->block.compressed;
}
s->sequence = SEQ_BLOCK_CHECK;
case SEQ_BLOCK_CHECK:
if (s->has_crc32) {
ret = crc32_validate(s, b);
if (ret != XZ_STREAM_END)
return ret;
}
s->sequence = SEQ_BLOCK_START;
break;
case SEQ_INDEX:
ret = dec_index(s, b);
if (ret != XZ_STREAM_END)
return ret;
s->sequence = SEQ_INDEX_PADDING;
case SEQ_INDEX_PADDING:
while ((s->index.size + (b->in_pos - s->in_start))
& 3) {
if (b->in_pos == b->in_size) {
index_update(s, b);
return XZ_OK;
}
if (b->in[b->in_pos++] != 0)
return XZ_DATA_ERROR;
}
/* Finish the CRC32 value and Index size. */
index_update(s, b);
/* Compare the hashes to validate the Index field. */
if (! memeq(&s->block.hash, &s->index.hash, sizeof(s->block.hash)))
return XZ_DATA_ERROR;
s->sequence = SEQ_INDEX_CRC32;
case SEQ_INDEX_CRC32:
ret = crc32_validate(s, b);
if (ret != XZ_STREAM_END)
return ret;
s->temp.size = STREAM_HEADER_SIZE;
s->sequence = SEQ_STREAM_FOOTER;
case SEQ_STREAM_FOOTER:
if (!fill_temp(s, b))
return XZ_OK;
return dec_stream_footer(s);
}
}
/* Never reached */
}
/*
* xz_dec_run() is a wrapper for dec_main() to handle some special cases in
* multi-call and single-call decoding.
*
* In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
* are not going to make any progress anymore. This is to prevent the caller
* from calling us infinitely when the input file is truncated or otherwise
* corrupt. Since zlib-style API allows that the caller fills the input buffer
* only when the decoder doesn't produce any new output, we have to be careful
* to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
* after the second consecutive call to xz_dec_run() that makes no progress.
*
* In single-call mode, if we couldn't decode everything and no error
* occurred, either the input is truncated or the output buffer is too small.
* Since we know that the last input byte never produces any output, we know
* that if all the input was consumed and decoding wasn't finished, the file
* must be corrupt. Otherwise the output buffer has to be too small or the
* file is corrupt in a way that decoding it produces too big output.
*
* If single-call decoding fails, we reset b->in_pos and b->out_pos back to
* their original values. This is because with some filter chains there won't
* be any valid uncompressed data in the output buffer unless the decoding
* actually succeeds (that's the price to pay of using the output buffer as
* the workspace).
*/
enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
{
size_t in_start;
size_t out_start;
enum xz_ret ret;
if (s->single_call)
xz_dec_reset(s);
in_start = b->in_pos;
out_start = b->out_pos;
ret = dec_main(s, b);
if (s->single_call) {
if (ret == XZ_OK)
ret = b->in_pos == b->in_size
? XZ_DATA_ERROR : XZ_BUF_ERROR;
if (ret != XZ_STREAM_END) {
b->in_pos = in_start;
b->out_pos = out_start;
}
} else if (ret == XZ_OK && in_start == b->in_pos
&& out_start == b->out_pos) {
if (s->allow_buf_error)
ret = XZ_BUF_ERROR;
s->allow_buf_error = true;
} else {
s->allow_buf_error = false;
}
return ret;
}
struct xz_dec * xz_dec_init(uint32_t dict_max)
{
struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (s == NULL)
return NULL;
/* prepare CRC32 calculators */
if(GRUB_MD_CRC32 == NULL)
{
kfree(s);
return NULL;
}
s->crc32_context = kmalloc(GRUB_MD_CRC32->contextsize, GFP_KERNEL);
if (s->crc32_context == NULL)
{
kfree(s);
return NULL;
}
s->index.hash.crc32_context = kmalloc(GRUB_MD_CRC32->contextsize, GFP_KERNEL);
if (s->index.hash.crc32_context == NULL)
{
kfree(s->crc32_context);
kfree(s);
return NULL;
}
s->block.hash.crc32_context = kmalloc(GRUB_MD_CRC32->contextsize, GFP_KERNEL);
if (s->block.hash.crc32_context == NULL)
{
kfree(s->index.hash.crc32_context);
kfree(s->crc32_context);
kfree(s);
return NULL;
}
GRUB_MD_CRC32->init(s->crc32_context);
s->crc32_temp = 0;
GRUB_MD_CRC32->init(s->index.hash.crc32_context);
GRUB_MD_CRC32->init(s->block.hash.crc32_context);
s->single_call = dict_max == 0;
#ifdef XZ_DEC_BCJ
s->bcj = xz_dec_bcj_create(s->single_call);
if (s->bcj == NULL)
goto error_bcj;
#endif
s->lzma2 = xz_dec_lzma2_create(dict_max);
if (s->lzma2 == NULL)
goto error_lzma2;
xz_dec_reset(s);
return s;
error_lzma2:
#ifdef XZ_DEC_BCJ
xz_dec_bcj_end(s->bcj);
error_bcj:
#endif
kfree(s);
return NULL;
}
void xz_dec_reset(struct xz_dec *s)
{
s->sequence = SEQ_STREAM_HEADER;
s->allow_buf_error = false;
s->pos = 0;
memzero(&s->block, sizeof(s->block));
memzero(&s->index, sizeof(s->index));
s->temp.pos = 0;
s->temp.size = STREAM_HEADER_SIZE;
GRUB_MD_CRC32->init(s->crc32_context);
s->crc32_temp = 0;
GRUB_MD_CRC32->init(s->index.hash.crc32_context);
GRUB_MD_CRC32->init(s->block.hash.crc32_context);
}
void xz_dec_end(struct xz_dec *s)
{
if (s != NULL) {
xz_dec_lzma2_end(s->lzma2);
#ifdef XZ_DEC_BCJ
xz_dec_bcj_end(s->bcj);
#endif
kfree(s);
}
}

View file

@ -0,0 +1,236 @@
/* xz_lzma2.h - LZMA2 definitions */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is based on code from XZ embedded project
* http://tukaani.org/xz/embedded.html
*/
#ifndef XZ_LZMA2_H
#define XZ_LZMA2_H
/* dictionary size hard limit
* actual size limit is calculated as shown in 5.3.1
* http://tukaani.org/xz/xz-file-format.txt
*
* if bits > 39 dictionary_size = UINT32_MAX
* else
* dictionary_size = 2 | (bits & 1);
* dictionary_size <<= bits / 2 + 11;
*
* i.e.
* 0 - 4 KiB
* 6 - 32 KiB
* 30 - 128MiB
* 39 - 3072 MiB
* 40 - 4096 MiB - 1 B
* note: implementation supports 39 at maximum
*/
#define DICT_BIT_SIZE 30
/* Range coder constants */
#define RC_SHIFT_BITS 8
#define RC_TOP_BITS 24
#define RC_TOP_VALUE (1 << RC_TOP_BITS)
#define RC_BIT_MODEL_TOTAL_BITS 11
#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
#define RC_MOVE_BITS 5
/*
* Maximum number of position states. A position state is the lowest pb
* number of bits of the current uncompressed offset. In some places there
* are different sets of probabilities for different position states.
*/
#define POS_STATES_MAX (1 << 4)
/*
* This enum is used to track which LZMA symbols have occurred most recently
* and in which order. This information is used to predict the next symbol.
*
* Symbols:
* - Literal: One 8-bit byte
* - Match: Repeat a chunk of data at some distance
* - Long repeat: Multi-byte match at a recently seen distance
* - Short repeat: One-byte repeat at a recently seen distance
*
* The symbol names are in from STATE_oldest_older_previous. REP means
* either short or long repeated match, and NONLIT means any non-literal.
*/
enum lzma_state {
STATE_LIT_LIT,
STATE_MATCH_LIT_LIT,
STATE_REP_LIT_LIT,
STATE_SHORTREP_LIT_LIT,
STATE_MATCH_LIT,
STATE_REP_LIT,
STATE_SHORTREP_LIT,
STATE_LIT_MATCH,
STATE_LIT_LONGREP,
STATE_LIT_SHORTREP,
STATE_NONLIT_MATCH,
STATE_NONLIT_REP
};
/* Total number of states */
#define STATES 12
/* The lowest 7 states indicate that the previous state was a literal. */
#define LIT_STATES 7
/* Indicate that the latest symbol was a literal. */
static inline void lzma_state_literal(enum lzma_state *state)
{
if (*state <= STATE_SHORTREP_LIT_LIT)
*state = STATE_LIT_LIT;
else if (*state <= STATE_LIT_SHORTREP)
*state -= 3;
else
*state -= 6;
}
/* Indicate that the latest symbol was a match. */
static inline void lzma_state_match(enum lzma_state *state)
{
*state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
}
/* Indicate that the latest state was a long repeated match. */
static inline void lzma_state_long_rep(enum lzma_state *state)
{
*state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
}
/* Indicate that the latest symbol was a short match. */
static inline void lzma_state_short_rep(enum lzma_state *state)
{
*state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
}
/* Test if the previous symbol was a literal. */
static inline bool lzma_state_is_literal(enum lzma_state state)
{
return state < LIT_STATES;
}
/* Each literal coder is divided in three sections:
* - 0x001-0x0FF: Without match byte
* - 0x101-0x1FF: With match byte; match bit is 0
* - 0x201-0x2FF: With match byte; match bit is 1
*
* Match byte is used when the previous LZMA symbol was something else than
* a literal (that is, it was some kind of match).
*/
#define LITERAL_CODER_SIZE 0x300
/* Maximum number of literal coders */
#define LITERAL_CODERS_MAX (1 << 4)
/* Minimum length of a match is two bytes. */
#define MATCH_LEN_MIN 2
/* Match length is encoded with 4, 5, or 10 bits.
*
* Length Bits
* 2-9 4 = Choice=0 + 3 bits
* 10-17 5 = Choice=1 + Choice2=0 + 3 bits
* 18-273 10 = Choice=1 + Choice2=1 + 8 bits
*/
#define LEN_LOW_BITS 3
#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
#define LEN_MID_BITS 3
#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
#define LEN_HIGH_BITS 8
#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
/*
* Maximum length of a match is 273 which is a result of the encoding
* described above.
*/
#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
/*
* Different sets of probabilities are used for match distances that have
* very short match length: Lengths of 2, 3, and 4 bytes have a separate
* set of probabilities for each length. The matches with longer length
* use a shared set of probabilities.
*/
#define DIST_STATES 4
/*
* Get the index of the appropriate probability array for decoding
* the distance slot.
*/
static inline uint32_t lzma_get_dist_state(uint32_t len)
{
return len < DIST_STATES + MATCH_LEN_MIN
? len - MATCH_LEN_MIN : DIST_STATES - 1;
}
/*
* The highest two bits of a 32-bit match distance are encoded using six bits.
* This six-bit value is called a distance slot. This way encoding a 32-bit
* value takes 6-36 bits, larger values taking more bits.
*/
#define DIST_SLOT_BITS 6
#define DIST_SLOTS (1 << DIST_SLOT_BITS)
/* Match distances up to 127 are fully encoded using probabilities. Since
* the highest two bits (distance slot) are always encoded using six bits,
* the distances 0-3 don't need any additional bits to encode, since the
* distance slot itself is the same as the actual distance. DIST_MODEL_START
* indicates the first distance slot where at least one additional bit is
* needed.
*/
#define DIST_MODEL_START 4
/*
* Match distances greater than 127 are encoded in three pieces:
* - distance slot: the highest two bits
* - direct bits: 2-26 bits below the highest two bits
* - alignment bits: four lowest bits
*
* Direct bits don't use any probabilities.
*
* The distance slot value of 14 is for distances 128-191.
*/
#define DIST_MODEL_END 14
/* Distance slots that indicate a distance <= 127. */
#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
/*
* For match distances greater than 127, only the highest two bits and the
* lowest four bits (alignment) is encoded using probabilities.
*/
#define ALIGN_BITS 4
#define ALIGN_SIZE (1 << ALIGN_BITS)
#define ALIGN_MASK (ALIGN_SIZE - 1)
/* Total number of all probability variables */
#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
/*
* LZMA remembers the four most recent match distances. Reusing these
* distances tends to take less space than re-encoding the actual
* distance value.
*/
#define REPS 4
#endif

View file

@ -0,0 +1,96 @@
/* xz_private.h - Private includes and definitions */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is based on code from XZ embedded project
* http://tukaani.org/xz/embedded.html
*/
#ifndef XZ_PRIVATE_H
#define XZ_PRIVATE_H
/*
* For userspace builds, use a separate header to define the required
* macros and functions. This makes it easier to adapt the code into
* different environments and avoids clutter in the Linux kernel tree.
*/
#include "xz_config.h"
/*
* If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
* XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
*/
#ifndef XZ_DEC_BCJ
# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
|| defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
|| defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
|| defined(XZ_DEC_SPARC)
# define XZ_DEC_BCJ
# endif
#endif
/*
* Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
* before calling xz_dec_lzma2_run().
*/
struct xz_dec_lzma2 * xz_dec_lzma2_create(
uint32_t dict_max);
/*
* Decode the LZMA2 properties (one byte) and reset the decoder. Return
* XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
* big enough, and XZ_OPTIONS_ERROR if props indicates something that this
* decoder doesn't support.
*/
enum xz_ret xz_dec_lzma2_reset(
struct xz_dec_lzma2 *s, uint8_t props);
/* Decode raw LZMA2 stream from b->in to b->out. */
enum xz_ret xz_dec_lzma2_run(
struct xz_dec_lzma2 *s, struct xz_buf *b);
/* Free the memory allocated for the LZMA2 decoder. */
void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
/*
* Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
* calling xz_dec_bcj_run().
*/
struct xz_dec_bcj * xz_dec_bcj_create(bool single_call);
/*
* Decode the Filter ID of a BCJ filter. This implementation doesn't
* support custom start offsets, so no decoding of Filter Properties
* is needed. Returns XZ_OK if the given Filter ID is supported.
* Otherwise XZ_OPTIONS_ERROR is returned.
*/
enum xz_ret xz_dec_bcj_reset(
struct xz_dec_bcj *s, uint8_t id);
/*
* Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
* a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
* must be called directly.
*/
enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
struct xz_dec_lzma2 *lzma2, struct xz_buf *b);
/* Free the memory allocated for the BCJ filters. */
#define xz_dec_bcj_end(s) kfree(s)
#endif

View file

@ -0,0 +1,53 @@
/* xz_stream.h - Definitions for handling the .xz file format */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is based on code from XZ embedded project
* http://tukaani.org/xz/embedded.html
*/
#ifndef XZ_STREAM_H
#define XZ_STREAM_H
/*
* See the .xz file format specification at
* http://tukaani.org/xz/xz-file-format.txt
* to understand the container format.
*/
#define STREAM_HEADER_SIZE 12
#define HEADER_MAGIC "\3757zXZ\0"
#define HEADER_MAGIC_SIZE 6
#define FOOTER_MAGIC "YZ"
#define FOOTER_MAGIC_SIZE 2
/*
* Variable-length integer can hold a 63-bit unsigned integer, or a special
* value to indicate that the value is unknown.
*/
typedef uint64_t vli_type;
#define VLI_MAX ((vli_type)-1 / 2)
#define VLI_UNKNOWN ((vli_type)-1)
/* Maximum encoded size of a VLI */
#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
#endif

View file

@ -28,7 +28,6 @@
#include <grub/elfload.h>
#include <grub/env.h>
#include <grub/misc.h>
#include <grub/gzio.h>
#include <grub/aout.h>
#include <grub/command.h>
#include <grub/extcmd.h>
@ -746,6 +745,7 @@ grub_freebsd_boot (void)
grub_memcpy (&stack[9], &bi, sizeof (bi));
state.eip = entry;
state.esp = stack_target;
state.ebp = stack_target;
stack[0] = entry; /* "Return" address. */
stack[1] = bootflags | FREEBSD_RB_BOOTINFO;
stack[2] = bootdev;
@ -830,7 +830,8 @@ grub_openbsd_boot (void)
#endif
state.eip = entry;
state.esp = ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target;
state.ebp = state.esp
= ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target;
stack[0] = entry;
stack[1] = bootflags;
stack[2] = openbsd_root;
@ -1045,6 +1046,7 @@ grub_netbsd_boot (void)
state.eip = entry;
state.esp = stack_target;
state.ebp = stack_target;
stack[0] = entry;
stack[1] = bootflags;
stack[2] = 0;
@ -1323,7 +1325,7 @@ grub_bsd_load (int argc, char *argv[])
goto fail;
}
file = grub_gzfile_open (argv[0], 1);
file = grub_file_open (argv[0]);
if (!file)
goto fail;
@ -1369,10 +1371,10 @@ grub_bsd_parse_flags (const struct grub_arg_list *state,
}
static grub_err_t
grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[])
grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
{
kernel_type = KERNEL_TYPE_FREEBSD;
bootflags = grub_bsd_parse_flags (cmd->state, freebsd_flags);
bootflags = grub_bsd_parse_flags (ctxt->state, freebsd_flags);
if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
{
@ -1393,7 +1395,7 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[])
if (err)
return err;
file = grub_gzfile_open (argv[0], 1);
file = grub_file_open (argv[0]);
if (! file)
return grub_errno;
@ -1426,16 +1428,16 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[])
}
static grub_err_t
grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
{
grub_uint32_t bootdev;
kernel_type = KERNEL_TYPE_OPENBSD;
bootflags = grub_bsd_parse_flags (cmd->state, openbsd_flags);
bootflags = grub_bsd_parse_flags (ctxt->state, openbsd_flags);
if (cmd->state[OPENBSD_ROOT_ARG].set)
if (ctxt->state[OPENBSD_ROOT_ARG].set)
{
const char *arg = cmd->state[OPENBSD_ROOT_ARG].arg;
const char *arg = ctxt->state[OPENBSD_ROOT_ARG].arg;
int unit, part;
if (*(arg++) != 'w' || *(arg++) != 'd')
return grub_error (GRUB_ERR_BAD_ARGUMENT,
@ -1456,7 +1458,7 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
else
bootdev = 0;
if (cmd->state[OPENBSD_SERIAL_ARG].set)
if (ctxt->state[OPENBSD_SERIAL_ARG].set)
{
struct grub_openbsd_bootarg_console serial;
char *ptr;
@ -1465,9 +1467,9 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
grub_memset (&serial, 0, sizeof (serial));
if (cmd->state[OPENBSD_SERIAL_ARG].arg)
if (ctxt->state[OPENBSD_SERIAL_ARG].arg)
{
ptr = cmd->state[OPENBSD_SERIAL_ARG].arg;
ptr = ctxt->state[OPENBSD_SERIAL_ARG].arg;
if (grub_memcmp (ptr, "com", sizeof ("com") - 1) != 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
"only com0-com3 are supported");
@ -1511,11 +1513,11 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[])
}
static grub_err_t
grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
grub_cmd_netbsd (grub_extcmd_context_t ctxt, int argc, char *argv[])
{
grub_err_t err;
kernel_type = KERNEL_TYPE_NETBSD;
bootflags = grub_bsd_parse_flags (cmd->state, netbsd_flags);
bootflags = grub_bsd_parse_flags (ctxt->state, netbsd_flags);
if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE)
{
@ -1523,7 +1525,7 @@ grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
{
grub_file_t file;
file = grub_gzfile_open (argv[0], 1);
file = grub_file_open (argv[0]);
if (! file)
return grub_errno;
@ -1548,15 +1550,15 @@ grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
grub_bsd_add_meta (NETBSD_BTINFO_BOOTPATH, bootpath, sizeof (bootpath));
}
if (cmd->state[NETBSD_ROOT_ARG].set)
if (ctxt->state[NETBSD_ROOT_ARG].set)
{
char root[GRUB_NETBSD_MAX_ROOTDEVICE_LEN];
grub_memset (root, 0, sizeof (root));
grub_strncpy (root, cmd->state[NETBSD_ROOT_ARG].arg,
grub_strncpy (root, ctxt->state[NETBSD_ROOT_ARG].arg,
sizeof (root) - 1);
grub_bsd_add_meta (NETBSD_BTINFO_ROOTDEVICE, root, sizeof (root));
}
if (cmd->state[NETBSD_SERIAL_ARG].set)
if (ctxt->state[NETBSD_SERIAL_ARG].set)
{
struct grub_netbsd_btinfo_serial serial;
char *ptr;
@ -1564,9 +1566,9 @@ grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[])
grub_memset (&serial, 0, sizeof (serial));
grub_strcpy (serial.devname, "com");
if (cmd->state[NETBSD_SERIAL_ARG].arg)
if (ctxt->state[NETBSD_SERIAL_ARG].arg)
{
ptr = cmd->state[NETBSD_SERIAL_ARG].arg;
ptr = ctxt->state[NETBSD_SERIAL_ARG].arg;
if (grub_memcmp (ptr, "com", sizeof ("com") - 1) == 0)
{
ptr += sizeof ("com") - 1;
@ -1627,7 +1629,7 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
file = grub_gzfile_open (argv[0], 1);
file = grub_file_open (argv[0]);
if ((!file) || (!file->size))
goto fail;
@ -1728,7 +1730,7 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)),
return 0;
}
file = grub_gzfile_open (argv[0], 1);
file = grub_file_open (argv[0]);
if ((!file) || (!file->size))
goto fail;
@ -1779,7 +1781,7 @@ grub_netbsd_module_load (char *filename, grub_uint32_t type)
void *src;
grub_err_t err;
file = grub_gzfile_open (filename, 1);
file = grub_file_open (filename);
if ((!file) || (!file->size))
goto fail;
@ -1865,7 +1867,7 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)),
return 0;
}
file = grub_gzfile_open (argv[0], 1);
file = grub_file_open (argv[0]);
if (!file)
return grub_errno;
if (!file->size)
@ -1901,7 +1903,7 @@ grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)),
if (!openbsd_ramdisk.max_size)
return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD doesn't support ramdisk");
file = grub_gzfile_open (args[0], 1);
file = grub_file_open (args[0]);
if (! file)
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
"couldn't load ramdisk");
@ -1937,6 +1939,9 @@ static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk;
GRUB_MOD_INIT (bsd)
{
/* Net and OpenBSD kernels are often compressed. */
grub_dl_load ("gzio");
cmd_freebsd = grub_register_extcmd ("kfreebsd", grub_cmd_freebsd,
GRUB_COMMAND_FLAG_BOTH,
N_("FILE"), N_("Load kernel of FreeBSD."),

View file

@ -716,7 +716,7 @@ grub_linux_boot (void)
/* FIXME. */
/* asm volatile ("lidt %0" : : "m" (idt_desc)); */
state.ebx = 0;
state.ebp = state.edi = state.ebx = 0;
state.esi = real_mode_target;
state.esp = real_mode_target;
state.eip = params->code32_start;
@ -1069,6 +1069,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
grub_file_filter_disable_compression ();
file = grub_file_open (argv[0]);
if (! file)
goto fail;

View file

@ -69,6 +69,7 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
grub_dl_ref (my_mod);
grub_file_filter_disable_compression ();
file = grub_file_open (filename);
if (! file)
goto fail;

View file

@ -401,6 +401,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
addr_min = GRUB_LINUX_BZIMAGE_ADDR + grub_linux16_prot_size;
grub_file_filter_disable_compression ();
file = grub_file_open (argv[0]);
if (!file)
goto fail;

View file

@ -31,7 +31,6 @@
#include <grub/charset.h>
#include <grub/term.h>
#include <grub/command.h>
#include <grub/gzio.h>
#include <grub/i18n.h>
#include <grub/bitmap_scale.h>
@ -535,7 +534,7 @@ grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)),
if (argc != 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
file = grub_gzfile_open (args[0], 1);
file = grub_file_open (args[0]);
if (! file)
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
"couldn't load device-propertie dump");
@ -836,6 +835,7 @@ grub_xnu_boot_resume (void)
struct grub_relocator32_state state;
state.esp = grub_xnu_stack;
state.ebp = grub_xnu_stack;
state.eip = grub_xnu_entry_point;
state.eax = grub_xnu_arg1;
@ -1114,6 +1114,7 @@ grub_xnu_boot (void)
state.eip = grub_xnu_entry_point;
state.eax = grub_xnu_arg1;
state.esp = grub_xnu_stack;
state.ebp = grub_xnu_stack;
return grub_relocator32_boot (grub_xnu_relocator, state);
}

View file

@ -26,7 +26,6 @@
#include <grub/cpu/macho.h>
#include <grub/machoload.h>
#include <grub/file.h>
#include <grub/gzio.h>
#include <grub/misc.h>
#include <grub/mm.h>
@ -149,7 +148,7 @@ grub_macho_open (const char *name)
grub_file_t file;
grub_macho_t macho;
file = grub_gzfile_open (name, 1);
file = grub_file_open (name);
if (! file)
return 0;

View file

@ -344,6 +344,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
if (initrd_loaded)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd can be loaded.");
grub_file_filter_disable_compression ();
file = grub_file_open (argv[0]);
if (! file)
return grub_errno;

View file

@ -39,7 +39,6 @@
#include <grub/dl.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/gzio.h>
#include <grub/env.h>
#include <grub/cpu/relocator.h>
#include <grub/video.h>
@ -225,7 +224,7 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified");
file = grub_gzfile_open (argv[0], 1);
file = grub_file_open (argv[0]);
if (! file)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file");
@ -291,9 +290,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
"you need to load the multiboot kernel first");
if (nounzip)
file = grub_file_open (argv[0]);
else
file = grub_gzfile_open (argv[0], 1);
grub_file_filter_disable_compression ();
file = grub_file_open (argv[0]);
if (! file)
return grub_errno;

View file

@ -301,6 +301,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
grub_file_filter_disable_compression ();
file = grub_file_open (argv[0]);
if (! file)
goto fail;

View file

@ -305,7 +305,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
goto out;
}
file = grub_gzfile_open (argv[0], 1);
file = grub_file_open (argv[0]);
if (!file)
goto out;
@ -393,6 +393,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
grub_file_filter_disable_compression ();
file = grub_file_open (argv[0]);
if (! file)
goto fail;

Some files were not shown because too many files have changed in this diff Show more