diff --git a/.bzrignore b/.bzrignore index 3c7150afb..d4817ad8c 100644 --- a/.bzrignore +++ b/.bzrignore @@ -4,6 +4,8 @@ 30_os-prober 40_custom 41_custom +*.1 +*.8 aclocal.m4 ascii.bitmaps ascii.h @@ -13,13 +15,12 @@ build_env.mk config.cache config.guess config.h -config.h.in +config-util.h +config-util.h.in config.log config.status config.sub configure -conf/*.mk -*.d DISTLIST docs/*.info docs/stamp-vti @@ -39,7 +40,9 @@ grub-fstest grub_fstest_init.c grub_fstest_init.h grub-install +grub-kbdcomp grub-macho2img +grub-menulst2cfg grub-mk* grub-pbkdf2 grub-pe2elf @@ -58,23 +61,30 @@ grub-set-default grub-setup grub_setup_init.c grub_setup_init.h +grub-shell +grub-shell-tester *.img +*.image include/grub/cpu include/grub/machine install-sh lib/libgcrypt-grub +libgrub_a_init.c *.lst +*.marker Makefile *.mod mod-*.c missing *.pf2 +*.pp po/*.mo po/grub.pot stamp-h stamp-h1 stamp-h.in symlist.c +symlist.h trigtables.c update-grub_lib unidata.c @@ -91,7 +101,13 @@ 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/genmod.sh +grub-core/gensyminfo.sh +grub-core/*.module +grub-core/*.pp +util/bash-completion.d/grub diff --git a/ChangeLog b/ChangeLog index f624a70ad..d27ebad1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,1337 @@ +2010-09-20 Yves Blusseau + + * .bzrignore: Add grub-kbdcomp, grub-menulst2cfg, *.marker, + grub-core/genmod.sh and grub-core/gensyminfo.sh + +2010-09-20 BVK Chaitanya + + Add a test for echo command options. + + * tests/grub_cmd_echo.in: New test. + * Makefile.util.def: Rules for new test. + +2010-09-20 Szymon Janc + + Remove crc.mod and move crc command to hashsum.mod. + Remove lib/crc.c - users updated to use gcrypt implementation. + + * grub-core/commands/crc.c: Removed. + * grub-core/Makefile.core.def (crc): Module removed. + * grub-core/commands/hashsum.c (aliases[]): Add crc alias. + * grub-core/commands/hashsum.c (GRUB_MOD_INIT): Register crc command. + * grub-core/commands/hashsum.c (GRUB_MOD_FINI): Unregister crc command. + * grub-core/lib/crc.c: Removed. + * include/grub/lib/crc.h: Removed. + * Makefile.util.def (crc): Remove lib/crc.c + * grub-core/Makefile.core.def (libgrub.a): Remove grub-core/lib/crc.c. + * util/grub-fstest.c (cmd_crd): Use libgcrypt crc implementation. + * Makefile.util.def (libgrub.a): Add grub-core/lib/libgcrypt-grub/cipher/crc.c. + * Makefile.util.def (grub-fstest): Add CFLAGS_GCRY to cflags. + * Makefile.util.def (grub-fstest): Add CPPFLAGS_GCRY to cppflags. + * grub-core/efiemu/prepare.c (grub_efiemu_crc): Use libgcrypt crc implementation. + +2010-09-20 Vladimir Serbinenko + + * grub-core/boot/i386/pc/boot.S: Ignore %dl if it's not in a sane range. + +2010-09-19 Vladimir Serbinenko + + Split config.h for util and core. + + * acinclude.m4 (HAVE_ASM_USCORE): Transformed into a variable. + (ADDR32): Likewise. + (DATA32): Likewise. + (BSS_START_SYMBOL): Likewise. + (END_SYMBOL): Likewise. + (NEED_ENABLE_EXECUTE_STACK): Likewise. All users updated. + (grub_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK): Removed. + * config.h.in: New file. + * configure.ac: Use config-util.h as config define file. + Rename MACHINE into GRUB_MACHINE. All users updated. + (NEED_REGISTER_FRAME_INFO): Transformed into a variable. All users + updated. + (NESTED_FUNC_ATTR): Likewise. + Substitue new variables. + (COND_HAVE_ASM_USCORE): New conditional. + * grub-core/Makefile.am (ASM_PREFIX): New variable. + (kernel_syms.lst): Use ASM_PREFIX. + * grub-core/kern/emu/console.c: Include config-util.h. + * grub-core/kern/emu/misc.c: Likewise. + * grub-core/kern/emu/mm.c: Likewise. + * include/grub/emu/misc.h: Likewise. + * include/grub/libgcc.h: Likewise. + +2010-09-19 Vladimir Serbinenko + + * grub-core/term/efi/console.c (efi_codes): Fix GRUB_TERM_KEY_* + constants usage. + * grub-core/kern/emu/console.c (grub_ncurses_getkey): + Fix GRUB_TERM_KEY_* constants usage. + * grub-core/kern/emu/misc.c (asprintf): Fix vasprintf usage. + +2010-09-19 Vladimir Serbinenko + + * grub-core/bus/usb/ohci.c (grub_ohci_cancel_transfer): Use %p to + print pointer. + * grub-core/bus/usb/uhci.c: Remove empty define. + (grub_uhci_check_transfer): Add missing cast. + * grub-core/bus/usb/usbhub.c (poll_nonroot_hub): Use %p to + print pointer. + * grub-core/term/usb_keyboard.c (grub_usb_keyboard_getkey): Use + PRIuGRUB_SIZE. + * include/grub/types.h (PRIuGRUB_SIZE): New definition. + +2010-09-19 Vladimir Serbinenko + + * grub-core/Makefile.core.def (legacycfg): Add + lib/i386/pc/vesa_modes_table.c on emu. + +2010-09-19 BVK Chaitanya + + Reduce number of temporary files generated by build system. + + * grub-core/gencmdlist.sh: Removed. + * grub-core/genfslist.sh: Removed. + * grub-core/genhandlerlist.sh: Removed. + * grub-core/genmodsrc.sh: Removed. + * grub-core/genpartmaplist.sh: Removed. + * grub-core/genparttoollist.sh: Removed. + * grub-core/gentermiinallist.sh: Removed. + * grub-core/genvideolist.sh: Removed. + + * grub-core/genmod.sh.in: New file. + * grub-core/gensyminfo.sh.in: New file. + + * conf/Makefile.common (CPPFLAGS_*_LIST): New marker flags. + * conf/Makefile.extra-dist: Update with new files. + * gentpl.py: Remove rules related to unnecessary temporary files. + * grub-core/Makefile.am (syminfo.lst): New replacement for def-* + and und-* files. + * grub-core/Makefile.core.def: New rules for gensyminfo.sh and + genmod.sh scripts. + * grub-core/bus/usb/uhci.c: Remove empty #define. + * grub-core/genmoddep.awk: Updated with new syminfo format. + * util/bash-completion.d/Makefile.am: Add config.log to + CLEANFILES. + +2010-09-19 Yves Blusseau + + * Makefile.util.def: Add forgotten $(LIBINTL) library. + +2010-09-19 BVK Chaitanya + + * util/grub-mkconfig.in: Check the config script for syntax errors + before saving. + +2010-09-19 Colin Watson +2010-09-19 Vladimir Serbinenko + + * Makefile.util.def (grub-install): Use util/grub-install.in on all + platforms. + * util/grub-install.in: Add EFI and IEEE1275 support. + * util/i386/efi/grub-install.in: Removed. + * util/ieee1275/grub-install.in: Likewise. + +2010-09-19 Vladimir Serbinenko + + * grub-core/commands/i386/cmostest.c (+parse_args): New function. + (grub_cmd_cmosclean): Likewise. + (GRUB_MOD_INIT): Register command cmosclean. + * util/grub-mkconfig.in: Export GRUB_BUTTON_CMOS_CLEAN. + * util/grub.d/00_header.in: Handle GRUB_BUTTON_CMOS_CLEAN. + +2010-09-18 Carles Pina i Estany +2010-09-18 Aleš Nesrsta +2010-09-18 Vladimir Serbinenko + + Add keyboard layouts support. + + * Makefile.util.def (grub-mklayout): New file. + (grub-kbdcomp): New script. + * grub-core/Makefile.am (KERNEL_HEADER_FILES) [COND_mips_yeeloong]: + Add keyboard_layouts.h. + * grub-core/Makefile.core.def (kernel): Add commands/keylayouts.c and + commands/boot.c on yeeloong. + (keylayouts): New module. + * grub-core/bus/usb/ohci.c + * grub-core/bus/usb/uhci.c + * grub-core/bus/usb/usbhub.c (rescan): New variable. + (grub_usb_add_hub): Poll interrupt pipe for device handling. + (attach_root_port): Likewise. + (poll_nonroot_hub): Likewise. + (grub_usb_poll_devices): Likewise. + (detach_device): Close transfer. + * grub-core/bus/usb/usbtrans.c (grub_usb_execute_and_wait_transfer): New + function. + (grub_usb_bulk_setup_readwrite): Likewise. + (grub_usb_bulk_finish_readwrite): Likewise. + * grub-core/commands/keylayouts.c: New file. + * grub-core/commands/keystatus.c (grub_getkeystatus): New function. + * grub-core/commands/menuentry.c (hotkey_aliases): All several new + aliases. + * grub-core/term/at_keyboard.c: Restructured to use keylayouts and + support scancode 2. + * grub-core/term/usb_keyboard.c: Restructured to use keylayouts. + * include/grub/keyboard_layouts.h: New file. + * util/grub-mklayout.c: New file. + * util/grub-kbdcomp.in: Likewise. + +2010-09-18 Vladimir Serbinenko + + Unify memory types. + + * grub-core/Makefile.am (KERNEL_HEADER_FILES): Include memory.h. + * grub-core/commands/lsmmap.c (grub_cmd_lsmmap): Output user-readable + types. + * grub-core/kern/i386/multiboot_mmap.c (grub_lower_mem): Removed. + (grub_upper_mem): Likewise. + * grub-core/kern/ieee1275/init.c (grub_upper_mem): Likewise. + * include/grub/memory.h (grub_memory_type_t): New enum. + All users updated. + +2010-09-18 Vladimir Serbinenko + + * grub-core/Makefile.core.def (lsapm): New module. + * grub-core/commands/i386/pc/lsapm.c: New file. + * grub-core/loader/i386/multiboot_mbi.c (make_mbi) [GRUB_MACHINE_PCBIOS]: Pass APM info. + * grub-core/loader/multiboot_mbi2.c (make_mbi) [GRUB_MACHINE_PCBIOS]: + Likewise. + * include/grub/i386/pc/apm.h: New file. + * include/multiboot.h (multiboot_apm_info): New struct. + +2010-09-18 Vladimir Serbinenko + + GRUB-legacy configuration file support. + + * Makefile.util.def (grub-menulst2cfg): New util. + * docs/man/grub-menulst2cfg.h2m: New file. + * grub-core/Makefile.core.def (legacycfg): New module. + * grub-core/commands/legacycfg.c: New file. + * grub-core/commands/menuentry.c (append_menu_entry): Rename to ... + (grub_normal_add_menu_entry): ... this. + * grub-core/commands/password.c (grub_cmd_password): Split main part to ... + (grub_normal_set_password): ...this. + * grub-core/commands/videoinfo.c (grub_cmd_videoinfo): Support MODE. + * grub-core/loader/i386/linux.c (linux_vesafb_res): Move to .., + * grub-core/lib/i386/pc/vesa_modes_table.c: ... here. + * grub-core/lib/legacy_parse.c: New file. + * grub-core/normal/auth.c (grub_cmd_authenticate): New command. + * include/grub/i386/pc/vesa_modes_table.h: New file. + * include/grub/legacy_parse.h: Likewise. + * include/grub/normal.h (grub_normal_add_menu_entry): New proto. + * util/grub-menulst2cfg.c: New file. + +2010-09-17 Colin Watson + + * grub-core/kern/emu/hostdisk.c + (convert_system_partition_to_system_disk): Initialise node. + +2010-09-17 Colin Watson + + * grub-core/kern/emu/hostdisk.c + (convert_system_partition_to_system_disk): Fix devmapper memory pool + leak. + Reported and based on patch by: Modestas Vainius. + +2010-09-17 Colin Watson + + Fix DM-RAID probing with recent versions of device-mapper udev + rules. + + * grub-core/kern/emu/hostdisk.c (read_device_map): Don't + canonicalise device paths under /dev/mapper/. + (convert_system_partition_to_system_disk): Compare the + uncanonicalised path to /dev/mapper/ rather than the canonicalised + path, since device nodes under /dev/mapper/ are often symlinks. + +2010-09-17 Yves Blusseau + + * .bzrignore: *.d removed (old rule), add *.image and symlist.h. + +2010-09-16 Yves Blusseau + + * configure.ac: Avoid some annoying error messages if freetype-config + program is not found. + +2010-09-16 Colin Watson + + Support RAID on virtio devices, and others. + + * grub-core/kern/emu/getroot.c [__MINGW32__] (find_root_device): + Rename to ... + [__MINGW32__] (grub_find_device): ... this. + [! __MINGW32__ && ! __CYGWIN__] (find_root_device): Rename to ... + [! __MINGW32__ && ! __CYGWIN__] (grub_find_device): ... this. Use a + reasonable default if dir is NULL. + [! __MINGW32__ && __CYGWIN__] (find_cygwin_root_device): Rename to + ... + [! __MINGW32__ && __CYGWIN__] (grub_find_device): ... this. + (grub_guess_root_device): Update callers. + * include/grub/emu/getroot.h (grub_find_device): Add prototype. + + * util/raid.c (grub_util_getdiskname): Remove. + (grub_util_raid_getmembers): Use grub_find_device rather than + grub_util_getdiskname. + +2010-09-16 Colin Watson + + * docs/grub.texi (serial): Remove obsolete comment about GRUB + needing to be compiled with serial support. + (ls): Indicate that multiple files are accepted. + * grub-core/commands/ls.c (GRUB_MOD_INIT): Update help text to + indicate that multiple files are accepted. + +2010-09-16 Colin Watson + + * .bzrignore: Add *.1, *.8, grub-shell, grub-shell-tester, + libgrub_a_init.c, and util/bash-completion.d/grub. + +2010-09-15 Vladimir Serbinenko + + * util/grub-setup.c (setup): Fix incorrect container semantics. + +2010-09-15 Vladimir Serbinenko + + * grub-core/commands/parttool.c (grub_cmd_parttool): Fix a variable + misusage. + Reported by: J. Nick Terry + +2010-09-15 Vladimir Serbinenko + + Move embedding routines to partmap sources files. + + * grub-core/partmap/gpt.c (grub_gpt_partition_type_bios_boot) + [GRUB_UTIL]: New variable. + (gpt_partition_map_iterate): Set part.parent. + (gpt_partition_map_embed) [GRUB_UTIL]: New function. + (grub_gpt_partition_map) [GRUB_UTIL]: Set .embed. + * grub-core/partmap/msdos.c (pc_partition_map_embed) [GRUB_UTIL]: + New function. + (grub_msdos_partition_map) [GRUB_UTIL]: Set .embed. + * include/grub/partition.h (grub_embed_type_t) [GRUB_UTIL]: New type. + (grub_partition_map) [GRUB_UTIL]: New field embed. + * util/grub-setup.c (grub_gpt_partition_type_bios_boot): Removed. + (setup): Use ->embed. + +2010-09-15 Vladimir Serbinenko + + * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy): New + function. + * include/grub/emu/hostdisk.h (grub_util_biosdisk_is_floppy): New proto. + * util/grub-setup.c (setup): Use grub_util_biosdisk_is_floppy. + +2010-09-15 Yves Blusseau + + Add function to get completions from usage. + + * util/bash-completion.d/grub-completion.bash.in: Add function to get + completions from usage. Use LC_ALL=C to get options properly. + +2010-09-15 Vladimir Serbinenko + + * grub-core/gnulib/basename-lgpl.c: Imported. + * grub-core/gnulib/basename.c: Likewise. + * grub-core/gnulib/dirname-lgpl.c: Likewise. + * grub-core/gnulib/dirname.c: Likewise. + * grub-core/gnulib/dirname.h: Likewise. + * grub-core/gnulib/stripslash.c: Likewise. + +2010-09-15 Vladimir Serbinenko + + * grub-core/gnulib/error.c: Resynced. + * grub-core/gnulib/getopt.c: Likewise. + * grub-core/gnulib/getopt_int.h: Likewise. + * grub-core/gnulib/regex.h: Likewise. + * grub-core/gnulib/regex_internal.c: Likewise. + * grub-core/gnulib/regex_internal.h: Likewise. + +2010-09-15 Szymon Janc + + * grub-core/lib/xzembed/xz_dec_stream.c (dec_main): Fix index and block + CRC calculations and validity checks. + * grub-core/lib/xzembed/xz_dec_stream.c (dec_index): Fix index CRC + calculations. + +2010-09-15 Szymon Janc + + * grub-core/lib/xzembed/xz_dec_stream.c (xz_dec_end): Fix memory leak. + +2010-09-14 Vladimir Serbinenko + + Fix incorrect echo options handling. + Reported by: Yves Blusseau. + + * include/grub/command.h (grub_command_flags_t): New flags + GRUB_COMMAND_ACCEPT_DASH and GRUB_COMMAND_OPTIONS_AT_START. + * grub-core/lib/arg.c (grub_arg_parse): Handle new flags. + * grub-core/commands/echo.c (GRUB_MOD_INIT): Use new flags. + +2010-09-14 Vladimir Serbinenko + + * include/grub/command.h (GRUB_COMMAND_FLAG_CMDLINE): Removed. All + users updated. + (GRUB_COMMAND_FLAG_MENU): Likewise. + (GRUB_COMMAND_FLAG_BOTH): Likewise. + (GRUB_COMMAND_FLAG_TITLE): Removed. + (GRUB_COMMAND_FLAG_NO_ECHO): Likewise. + (GRUB_COMMAND_FLAG_EXTCMD): Moved into enum. + (GRUB_COMMAND_FLAG_DYNCMD): Likewise. + (GRUB_COMMAND_FLAG_BLOCKS): Likewise. + (grub_command_flags_t): New enum. All users updated. + +2010-09-14 Seth Goldberg + + Fix solaris compilation. + + * grub-core/Makefile.core.def (kernel): Include gnulib/error.c on emu. + (grub-emu): Add LIBZFS and LIBNVPAIR to ldadd. + (grub-emu-list): Likewise. + +2010-09-14 Vladimir Serbinenko + + Remove deprecated root command. + + * grub-core/commands/minicmd.c (grub_mini_cmd_root): Removed. All users + updated. + +2010-09-14 Vladimir Serbinenko + + * util/i386/pc/grub-setup.c: Merge this ... + * util/sparc64/ieee1275/grub-setup.c: ... and this ... + * util/grub-setup.c: ... into this. + * include/grub/sparc64/ieee1275/boot.h (grub_boot_blocklist) [ASM_FILE]: + New struct. + +2010-09-14 Vladimir Serbinenko + + * grub-core/fs/ext2.c (grub_ext2_open): Use return error value when + possible. + +2010-09-14 Vladimir Serbinenko + + * grub-core/partmap/sun.c (sun_partition_map_iterate): Don't needlesly + allocate p. + +2010-09-14 Vladimir Serbinenko + + * util/grub-mkconfig_lib.in (prepare_grub_to_access_device): Add + explicit root argument to set to prevent UUID to be interpreted as + argument to set. + +2010-09-14 Vladimir Serbinenko + + * grub-core/kern/sparc64/ieee1275/crt0.S: Align stack. + +2010-09-14 Vladimir Serbinenko + + Don't export grub_gate_a20. + + * grub-core/kern/i386/pc/init.c: Remove leftovers. + * grub-core/kern/i386/pc/startup.S (FUNCTION(grub_gate_a20)): Rename + to ... + (grub_gate_a20): ... this. All users updated. + * include/grub/i386/pc/init.h: Removed. All users updated. + +2010-09-14 Vladimir Serbinenko + + Create euro.pf2 which supports most European languages. + + * Makefile.am (grubdata_DATA): Add euro.pf2. + (euro.pf2): New target. + (CLEANFILES): Add euro.pf2. + +2010-09-14 Vladimir Serbinenko + + * configure.ac: Disable emu-usb by default to prevent inadvertent + device takeover. + +2010-09-13 Vladimir Serbinenko + + Disable usbserial on grub-emu since our libusb code isn't good enough + yet. + + * grub-core/Makefile.core.def (usbserial_common): Disable on emu. + (usbserial_pl2303): Likewise. + (usbserial_ftdi): Likewise. + +2010-09-13 Vladimir Serbinenko + + * include/grub/disk.h (grub_disk): Remove has_partitions. + All users updated. + * disk/loopback.c (grub_loopback): Remove has_partitions. + All users updated. + (options): Remove partitions. All users updated. + * util/grub-fstest.c (fstest): Don't pass "-p" to loopback. + * util/i386/pc/grub-setup.c (setup): copy partition table only when + actual partition table is found. + +2010-09-13 Vladimir Serbinenko + + Remove readability checks (too many false negatives). + + * util/grub-install.in: Remove readability checks. + * util/grub-mkconfig.in: Likewise. + * util/grub.d/10_hurd.in: Likewise. + * util/grub.d/10_kfreebsd.in: Likewise. + * util/grub.d/10_linux.in: Likewise. + * util/grub-mkconfig_lib.in (is_path_readable_by_grub): Revert to old + way. + +2010-09-13 Vladimir Serbinenko + + Enable acpi shutdown on all ACPI platforms. + + * grub-core/Makefile.core.def (halt): Inlude commands/acpihalt.c + on coreboo, multiboot and EFI. + * grub-core/commands/acpihalt.c (get_sleep_type): Add missing casts. + (grub_acpi_halt): Likewise. + * grub-core/commands/i386/pc/halt.c (grub_halt): Call grub_acpi_halt. + (grub_cmd_halt): Don't call grub_acpi_halt directly. + * grub-core/lib/efi/halt.c (grub_halt): Call grub_acpi_halt. + * grub-core/lib/i386/halt.c (grub_halt) + [GRUB_MACHINE_COREBOOT || GRUB_MACHINE_MULTIBOOT]: Likewise. + +2010-09-13 Vladimir Serbinenko + + * grub-core/commands/iorw.c (grub_cmd_read): Declare buf in smallest + context. + +2010-09-13 Vladimir Serbinenko + + * grub-core/video/efi_gop.c: Fix over-80-chars line. + * grub-core/video/efi_uga.c: Likewise. + +2010-09-13 Vladimir Serbinenko + + Filter devaliases and never open same device twice. + + * grub-core/disk/ieee1275/ofdisk.c (last_devpath): New variable. + (last_ihandle): Likewise. + (ofdisk_hash_ent): New member shortest. + (ofdisk_hash_add): Add canonical path too. + (scan): New function. + (grub_ofdisk_iterate): Iterate over hashed entries. + (compute_dev_path): Don't add :0. + (grub_ofdisk_open): Don't really open the disk. + (grub_ofdisk_close): Avoid closing unrelated disk. + (grub_ofdisk_read): Implement reopen logic. + * grub-core/kern/ieee1275/openfw.c (grub_ieee1275_canonicalise_devname): + New function. + * include/grub/ieee1275/ieee1275.h (grub_ieee1275_canonicalise_devname): + New proto. + +2010-09-13 Vladimir Serbinenko + + Fix sparc64. + + * configure.ac (GRUB_KERNEL_MACHINE_LINK_ADDR): Removed. + * grub-core/Makefile.core.def (kernel): Make ldflags just use the + right address. Add sparc64_ieee1275_ldflags. + * grub-core/loader/sparc64/ieee1275/linux.c: Remove leftover include. + * util/grub-mkimagexx.c (locate_sections): Correct grub_host_to_target32 + to grub_host_to_target_addr + (load_image): Likewise. + +2010-09-13 Vladimir Serbinenko + + * grub-core/normal/completion.c (complete_file): Handle device + containing slash. + Fix based on patch by Doug Nazar. + +2010-09-13 Vladimir Serbinenko + + grub-mknetdir script. + + * Makefile.util.def (grub-mknetdir): New module. + * tests/util/grub-shell.in: Support boot=net + * util/grub-mknetdir.in: New file. + +2010-09-13 Vladimir Serbinenko + + videoinfo on non-vbe. + + * grub-core/Makefile.core.def (vbeinfo): Removed. + (vbetest): Removed. + (videoinfo): New module. + * grub-core/commands/i386/pc/vbeinfo.c: Removed. + * grub-core/commands/i386/pc/vbetest.c: Removed. + * grub-core/commands/videoinfo.c: New file. + * grub-core/commands/videotest.c (grub_cmd_videotest): Support mode + specification. + (grub_cmd_videotest) [GRUB_MACHINE_PCBIOS]: Load vbe.mod when invoked + as vbetest. + (GRUB_MOD_INIT) [GRUB_MACHINE_PCBIOS]: New command vbetest. + (GRUB_MOD_FINI) [GRUB_MACHINE_PCBIOS]: Unregister vbetest. + * grub-core/video/efi_gop.c (grub_video_gop_fill_mode_info): Fill + mode_number. New parameter mode. All users updated. + (grub_video_gop_iterate): New function. + (grub_video_efi_gop): New member iterate. + * grub-core/video/i386/pc/vbe.c (framebuffer): Removed leftover fields. + (grub_vbe_set_video_mode): Remove setting useless fields. + (vbe2videoinfo): New function. + (grub_video_vbe_iterate): Likewise. + (grub_video_vbe_setup): Use vbe2videoinfo. + (grub_video_vbe_print_adapter_specific_info): New function. + (grub_video_vbe_adapter): New fields iterate and + print_adapter_specific_info. + * include/grub/video.h (GRUB_VIDEO_MODE_*): Transform into enum. + All users updated. + (grub_video_mode_info): New field mode_number. + (grub_video_adapter): New fields iterate and + print_adapter_specific_info. + +2010-09-13 Tristan Gingold +2010-09-13 Robert Millan +2010-09-13 Vladimir Serbinenko + + * grub-core/commands/efi/lsefisystab.c: New file. + * grub-core/commands/efi/lssal.c: Likewise. + * grub-core/Makefile.core.def (lsacpi): New module. + (lsefisystab): Likewise. + * include/grub/efi/api.h (GRUB_EFI_SAL_TABLE_GUID): New definition. + (GRUB_EFI_HCDP_TABLE_GUID): Likewise. + (grub_efi_sal_system_table): New struct. + (grub_efi_sal_system_table_entrypoint_descriptor): Likewise. + (grub_efi_sal_system_table_memory_descriptor): Likewise. + (grub_efi_sal_system_table_platform_features): Likewise. + (grub_efi_sal_system_table_translation_register_descriptor): Likewise. + (grub_efi_sal_system_table_purge_translation_coherence): Likewise. + (grub_efi_sal_system_table_ap_wakeup): Likewise. + * include/grub/types.h (PRIuGRUB_UINT64_T): New definition. + +2010-09-13 Vladimir Serbinenko + + Support explicit user claim that a device is BIOS-visible. + + * grub-core/kern/emu/getroot.c (grub_util_get_dev_abstraction): + Return GRUB_DEV_ABSTRACTION_NONE if device is in device.map. + * grub-core/kern/emu/hostdisk.c + (convert_system_partition_to_system_disk): Support mdX. + (find_system_device): New parameter add. All users updated. + (grub_util_biosdisk_is_present): New function. + * include/grub/emu/hostdisk.h (grub_util_biosdisk_is_present): New + proto. + +2010-09-13 Vladimir Serbinenko + + Search hints support. + + * commands/search.c (FUNC_NAME): New arguments hints and nhints. + All users updated. + +2010-09-13 Yves Blusseau + + Bash completion script for util commands + + * Makefile.am: Add util/bash-completion.d directory + * configure.ac: Likewise. + * util/bash-completion.d/Makefile.am: New file. + * util/bash-completion.d/grub-completion.bash.in: Likewise. + +2010-09-12 Vladimir Serbinenko + + * grub-core/normal/term.c (put_glyphs_terminal): Correct sign. + (print_backlog): set backlog_ucs4 and backlog_glyphs. + Reported by: Yves Blusseau. + +2010-09-12 Vladimir Serbinenko + + * grub-core/normal/misc.c (grub_normal_print_device_info): Show + partition size and offset. + +2010-09-12 Vladimir Serbinenko + + * grub-core/commands/wildcard.c (make_regex): Escape brackets. + +2010-09-12 Vladimir Serbinenko + + * grub-core/commands/ls.c (grub_cmd_ls): Accept multiple files. + +2010-09-12 Vladimir Serbinenko + + * grub-core/kern/misc.c (grub_vprintf): Use va_copy when necessary. + (grub_xvasprintf): Likewise. + +2010-09-12 Vladimir Serbinenko + + * grub-core/kern/emu/main.c (main): Call hostfs_init only after init_all. + +2010-09-12 Vladimir Serbinenko + + * grub-core/commands/menuentry.c (append_menu_entry): Don't rely on + args ending with NULL. + +2010-09-12 Vladimir Serbinenko + + * grub-core/lib/xzembed/xz_dec_stream.c (xz_dec_reset): Preserve context + pointer. + +2010-09-11 Szymon Janc + + * grub-core/commands/lsacpi.c (grub_cmd_lsacpi): Fix prototype. + +2010-09-11 Vladimir Serbinenko + + 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 +2010-09-11 Robert Millan +2010-09-11 Vladimir Serbinenko + + * 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 + + 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 +2010-09-11 Colin Watson + + * 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 + + 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 + + * util/grub-install.in: Don't try to verify core.img until after + running grub-mkimage to create it. + +2010-09-10 Robert Millan + + * 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 + + * 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 + + 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 + `'. + [HAVE_SYS_MKDEV_H]: Include `'. + [HAVE_GETEXTMNTENT] (grub_find_zpool_from_dir): Add getextmntent() + method for finding zpool name. + +2010-09-10 Colin Watson + + 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 + + * 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 + + * 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 + + * 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 + + * tests/partmap_test.in: New test for partitions. + * Makefile.util.def: Rules for new test. + +2010-09-09 Robert Millan + + * util/grub-probe.c (probe): Fix a pair of unhandled error + conditions. + +2010-09-09 Robert Millan + + 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 + + * 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 + + 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 + + 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 + + * util/grub-mkconfig.in: Use new variable. + +2010-09-08 Yves Blusseau + + * configure.ac: Define some useful variables. + +2010-09-08 Vladimir Serbinenko + + * 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 + + * 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 + + * 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 + + * util/grub-mkconfig.in: Pass `--device ${GRUB_DEVICE}' when + initializing `GRUB_FS'. + +2010-09-08 BVK Chaitanya + + 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 + + * grub-core/commands/wildcard.c (wildcard_expand): Fix wrong + grub_free. + +2010-09-07 BVK Chaitanya + + * docs/grub.texi (Shell-like scripting): Fix @dots to @dots{}. + +2010-09-07 BVK Chaitanya + + * docs/grub.texi (Shell-like scripting): Documentation for break, + continue, shift and return commands. + +2010-09-06 Vladimir Serbinenko + + 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 + + * 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 + + * grub-core/disk/lvm.c (grub_lvm_scan_device) [GRUB_UTIL]: Output more + diagnostic info. + +2010-09-05 Jo Shields + + * util/grub.d/30_os-prober.in: Add missing classes. + +2010-09-05 Vladimir Serbinenko + + * docs/grub.texi (Theme file format): Document new position format. + +2010-09-05 Vladimir Serbinenko + + * 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 + + Gfxmenu documentation. + + * docs/grub.texi (Theme file format): New chapter. + +2010-09-05 Szymon Janc + + * 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 + + * 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 + + * 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 + + 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 + + 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 + + * 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 + + * include/grub/crypto.h (GRUB_MD_CRC32): New definition. + +2010-09-05 Vladimir Serbinenko + + * 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 + + 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 + + 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 + + * 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 + + 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 + + "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 + + "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 + + * grub-core/normal/completion.c (grub_normal_do_completion): Fix + grub_free order. + +2010-09-04 BVK Chaitanya + + 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 + + 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 + + * grub-core/kern/misc.c: Don't add abort alias in utils. + Reported by: echoline. + +2010-09-03 BVK Chaitanya + + 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 + + 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 + + * 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 + + * configure.ac: Clean LIBS variable after tests. + +2010-09-02 Colin Watson + + * INSTALL: Document that libdevmapper needs to be 1.02.34 or later. + +2010-09-02 Vladimir Serbinenko + + * configure.ac: Check for dm_log_with_errno_init in libdevmapper and + echo if libdevmapper will be used. + +2010-09-02 Ian Turner + + * grub-core/fs/i386/pc/pxe.c (grub_pxefs_read): Keep the blocksize + constant for the same file. + +2010-09-02 Vladimir Serbinenko + + * grub-core/kern/i386/multiboot_mmap.c: Remove leftover include. + +2010-09-02 Colin Watson + + * .bzrignore: Add *.pp, **/.dirstamp, grub-core/*.module, and + grub-core/*.pp. + +2010-09-02 Colin Watson + + 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 + + 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 + + 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 + + * NEWS: Document most of the important changes since 1.98. + +2010-09-01 Colin Watson + + * util/grub-mkrescue.in (usage): Tidy up usage output (and hence + generated manual page) a little. + +2010-09-01 Colin Watson + + * docs/grub.texi: Add myself as an author. + +2010-09-01 Vladimir Serbinenko + + * Makefile.util.def (libgrub.a): Add missing sunpc. + Reported by: Seth Goldberg. + 2010-08-30 Vladimir Serbinenko Interrupt wrapping and code simplifications. @@ -251,6 +1585,15 @@ * util/grub-mkimage.c (generate_image): Remove font support. All users updated. +2010-08-30 Vladimir Serbinenko + + Remove leftover embedding of font objects. + + * include/grub/kernel.h (OBJ_TYPE_FONT): Removed. + * util/grub-install.in (font): Removed. + * util/grub-mkimage.c (generate_image): Remove font support. All users + updated. + 2010-08-30 Vladimir Serbinenko * docs/grub.texi (Network): Fix reference to pxe_blksize. diff --git a/ChangeLog.gingold1 b/ChangeLog.gingold1 deleted file mode 100644 index b2bef5d0c..000000000 --- a/ChangeLog.gingold1 +++ /dev/null @@ -1,17 +0,0 @@ -2008-01-28 Tristan Gingold -2010-01-18 Robert Millan -2010-08-31 Vladimir Serbinenko - - * 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. diff --git a/ChangeLog.gingold2 b/ChangeLog.gingold2 deleted file mode 100644 index 517a2cce1..000000000 --- a/ChangeLog.gingold2 +++ /dev/null @@ -1,18 +0,0 @@ -2008-01-28 Tristan Gingold -2010-01-18 Robert Millan -2010-08-31 Vladimir Serbinenko - - * grub-core/commands/efi/lsefisystab.c: New file. - * grub-core/commands/efi/lssal.c: Likewise. - * grub-core/Makefile.core.def (lsacpi): New module. - (lsefisystab): Likewise. - * include/grub/efi/api.h (GRUB_EFI_SAL_TABLE_GUID): New definition. - (GRUB_EFI_HCDP_TABLE_GUID): Likewise. - (grub_efi_sal_system_table): New struct. - (grub_efi_sal_system_table_entrypoint_descriptor): Likewise. - (grub_efi_sal_system_table_memory_descriptor): Likewise. - (grub_efi_sal_system_table_platform_features): Likewise. - (grub_efi_sal_system_table_translation_register_descriptor): Likewise. - (grub_efi_sal_system_table_purge_translation_coherence): Likewise. - (grub_efi_sal_system_table_ap_wakeup): Likewise. - * include/grub/types.h (PRIuGRUB_UINT64_T): New definition. diff --git a/INSTALL b/INSTALL index bbfa01f0a..e325fa2b2 100644 --- a/INSTALL +++ b/INSTALL @@ -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: diff --git a/Makefile.am b/Makefile.am index 1cf2297bd..9ef8feaac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ AUTOMAKE_OPTIONS = subdir-objects DEPDIR = .deps-util -SUBDIRS = . grub-core po docs +SUBDIRS = . grub-core po docs util/bash-completion.d include $(top_srcdir)/conf/Makefile.common include $(top_srcdir)/conf/Makefile.extra-dist @@ -44,9 +44,23 @@ 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 +grubdata_DATA = unicode.pf2 ascii.pf2 euro.pf2 ascii.h widthspec.h endif endif @@ -62,6 +76,10 @@ ascii.pf2: $(FONT_SOURCE) grub-mkfont $(builddir)/grub-mkfont -o $@ $(FONT_SOURCE) -r 0x0-0x7f,$(UNICODE_ARROWS),$(UNICODE_LINES) CLEANFILES += ascii.pf2 +euro.pf2: $(FONT_SOURCE) grub-mkfont + $(builddir)/grub-mkfont -o $@ $(FONT_SOURCE) -r 0x0-0x4ff,0x1e00-0x1fff,$(UNICODE_ARROWS),$(UNICODE_LINES) +CLEANFILES += euro.pf2 + ascii.bitmaps: $(FONT_SOURCE) grub-mkfont $(builddir)/grub-mkfont --ascii-bitmaps -o $@ $(FONT_SOURCE) CLEANFILES += ascii.bitmaps diff --git a/Makefile.util.def b/Makefile.util.def index 9565dde65..c19f66115 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -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; @@ -72,11 +72,11 @@ library = { common = grub-core/kern/list.c; common = grub-core/kern/partition.c; common = grub-core/lib/arg.c; - common = grub-core/lib/crc.c; common = grub-core/lib/crypto.c; common = grub-core/lib/envblk.c; common = grub-core/lib/hexdump.c; common = grub-core/lib/libgcrypt-grub/cipher/sha512.c; + common = grub-core/lib/libgcrypt-grub/cipher/crc.c; common = grub-core/lib/LzFind.c; common = grub-core/lib/LzmaEnc.c; common = grub-core/lib/pbkdf2.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,15 @@ 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; + cflags = '$(CFLAGS_GCRY)'; + cppflags = '$(CPPFLAGS_GCRY)'; }; program = { @@ -229,14 +234,11 @@ program = { name = grub-setup; installdir = sbin; mansection = 8; - i386_pc = util/i386/pc/grub-setup.c; - i386_pc = util/raid.c; - i386_pc = util/lvm.c; + common = util/grub-setup.c; + common = util/raid.c; + common = util/lvm.c; sparc64_ieee1275 = util/ieee1275/ofpath.c; - sparc64_ieee1275 = util/sparc64/ieee1275/grub-setup.c; - sparc64_ieee1275 = util/raid.c; - sparc64_ieee1275 = util/lvm.c; ldadd = libgrub.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)'; @@ -256,6 +258,16 @@ program = { enable = sparc64_ieee1275; }; +program = { + name = grub-mklayout; + mansection = 1; + + common = util/grub-mklayout.c; + + ldadd = libgrub.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; +}; + data = { common = util/grub.d/README; installdir = grubconf; @@ -345,20 +357,18 @@ script = { installdir = sbin; name = grub-install; - mips = util/grub-install.in; - i386_pc = util/grub-install.in; - i386_qemu = util/grub-install.in; - i386_coreboot = util/grub-install.in; - i386_multiboot = util/grub-install.in; - sparc64_ieee1275 = util/grub-install.in; - - x86_efi = util/i386/efi/grub-install.in; - i386_ieee1275 = util/ieee1275/grub-install.in; - powerpc_ieee1275 = util/ieee1275/grub-install.in; - + common = util/grub-install.in; enable = noemu; }; +script = { + mansection = 8; + installdir = sbin; + name = grub-mknetdir; + + common = util/grub-mknetdir.in; +}; + script = { name = grub-mkconfig; common = util/grub-mkconfig.in; @@ -392,6 +402,11 @@ script = { installdir = noinst; }; +script = { + name = grub-kbdcomp; + common = util/grub-kbdcomp.in; +}; + script = { name = grub-shell; common = tests/util/grub-shell.in; @@ -500,6 +515,54 @@ 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; +}; + +script = { + testcase; + name = grub_cmd_echo; + common = tests/grub_cmd_echo.in; +}; + program = { testcase; name = example_unit_test; @@ -512,3 +575,14 @@ program = { ldadd = libgrub.a; ldadd = '$(LIBDEVMAPPER)'; }; + +program = { + name = grub-menulst2cfg; + mansection = 1; + common = util/grub-menulst2cfg.c; + common = grub-core/lib/legacy_parse.c; + common = grub-core/lib/i386/pc/vesa_modes_table.c; + + ldadd = libgrub.a; + ldflags = '$(LIBINTL) $(LIBDEVMAPPER)'; +}; diff --git a/NEWS b/NEWS index e16504342..bb6b8df3f 100644 --- a/NEWS +++ b/NEWS @@ -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. diff --git a/acinclude.m4 b/acinclude.m4 index e8dd3dc7b..7c38155d4 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -58,18 +58,15 @@ else fi if $EGREP '(^|[^_[:alnum]])_func' conftest.s >/dev/null 2>&1; then + HAVE_ASM_USCORE=1 grub_cv_asm_uscore=yes else + HAVE_ASM_USCORE=0 grub_cv_asm_uscore=no fi rm -f conftest*]) -if test "x$grub_cv_asm_uscore" = xyes; then - AC_DEFINE_UNQUOTED([HAVE_ASM_USCORE], $grub_cv_asm_uscore, - [Define if C symbols get an underscore after compilation]) -fi - AC_MSG_RESULT([$grub_cv_asm_uscore]) ]) @@ -237,44 +234,12 @@ else grub_tmp_data32="data32;" fi -AC_DEFINE_UNQUOTED([ADDR32], $grub_tmp_addr32, - [Define it to \"addr32\" or \"addr32;\" to make GAS happy]) -AC_DEFINE_UNQUOTED([DATA32], $grub_tmp_data32, - [Define it to \"data32\" or \"data32;\" to make GAS happy]) +ADDR32=$grub_tmp_addr32 +DATA32=$grub_tmp_data32 AC_MSG_RESULT([$grub_cv_i386_asm_prefix_requirement])]) -dnl Older versions of GAS require that absolute indirect calls/jumps are -dnl not prefixed with `*', while later versions warn if not prefixed. -AC_DEFUN([grub_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK], -[AC_REQUIRE([AC_PROG_CC]) -AC_MSG_CHECKING(dnl -[whether an absolute indirect call/jump must not be prefixed with an asterisk]) -AC_CACHE_VAL(grub_cv_i386_asm_absolute_without_asterisk, -[cat > conftest.s <<\EOF - lcall *(offset) -offset: - .long 0 - .word 0 -EOF - -if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -c conftest.s]) && test -s conftest.o; then - grub_cv_i386_asm_absolute_without_asterisk=no -else - grub_cv_i386_asm_absolute_without_asterisk=yes -fi - -rm -f conftest*]) - -if test "x$grub_cv_i386_asm_absolute_without_asterisk" = xyes; then - AC_DEFINE([ABSOLUTE_WITHOUT_ASTERISK], 1, - [Define it if GAS requires that absolute indirect calls/jumps are not prefixed with an asterisk]) -fi - -AC_MSG_RESULT([$grub_cv_i386_asm_absolute_without_asterisk])]) - - dnl Check what symbol is defined as a bss start symbol. dnl Written by Michael Hohmoth and Yoshinori K. Okuji. AC_DEFUN([grub_CHECK_BSS_START_SYMBOL], @@ -306,14 +271,12 @@ AC_CACHE_VAL(grub_cv_check_uscore_edata_symbol, AC_MSG_RESULT([$grub_cv_check_uscore_edata_symbol]) -AH_TEMPLATE([BSS_START_SYMBOL], [Define it to one of __bss_start, edata and _edata]) - if test "x$grub_cv_check_uscore_uscore_bss_start_symbol" = xyes; then - AC_DEFINE([BSS_START_SYMBOL], [__bss_start]) + BSS_START_SYMBOL=__bss_start elif test "x$grub_cv_check_edata_symbol" = xyes; then - AC_DEFINE([BSS_START_SYMBOL], [edata]) + BSS_START_SYMBOL=edata elif test "x$grub_cv_check_uscore_edata_symbol" = xyes; then - AC_DEFINE([BSS_START_SYMBOL], [_edata]) + BSS_START_SYMBOL=_edata else AC_MSG_ERROR([none of __bss_start, edata or _edata is defined]) fi @@ -341,12 +304,10 @@ AC_CACHE_VAL(grub_cv_check_uscore_end_symbol, AC_MSG_RESULT([$grub_cv_check_uscore_end_symbol]) -AH_TEMPLATE([END_SYMBOL], [Define it to either end or _end]) - if test "x$grub_cv_check_end_symbol" = xyes; then - AC_DEFINE([END_SYMBOL], [end]) + END_SYMBOL=end elif test "x$grub_cv_check_uscore_end_symbol" = xyes; then - AC_DEFINE([END_SYMBOL], [_end]) + END_SYMBOL=_end else AC_MSG_ERROR([neither end nor _end is defined]) fi @@ -369,10 +330,10 @@ else AC_MSG_ERROR([${CC-cc} failed to produce assembly code]) fi if grep __enable_execute_stack conftest.s >/dev/null 2>&1; then - AC_DEFINE([NEED_ENABLE_EXECUTE_STACK], 1, - [Define to 1 if GCC generates calls to __enable_execute_stack()]) + NEED_ENABLE_EXECUTE_STACK=1 AC_MSG_RESULT([yes]) else + NEED_ENABLE_EXECUTE_STACK=0 AC_MSG_RESULT([no]) fi rm -f conftest* diff --git a/conf/Makefile.common b/conf/Makefile.common index fe14c0e18..a861c25e6 100644 --- a/conf/Makefile.common +++ b/conf/Makefile.common @@ -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 @@ -83,20 +88,26 @@ CPPFLAGS_POSIX = -I$(top_srcdir)/grub-core/lib/posix_wrap CPPFLAGS_EFIEMU = -I$(top_srcdir)/grub-core/efiemu/runtime +# List file macros for recognizing /interesting/ modules +CPPFLAGS_FS_LIST = -Dgrub_fs_register=FS_LIST_MARKER +CPPFLAGS_VIDEO_LIST= -Dgrub_video_register=VIDEO_LIST_MARKER +CPPFLAGS_PARTMAP_LIST = -Dgrub_partition_map_register=PARTMAP_LIST_MARKER +CPPFLAGS_PARTTOOL_LIST = -Dgrub_parttool_register=PARTTOOL_LIST_MARKER +CPPFLAGS_TERMINAL_LIST = '-Dgrub_term_register_input(...)=INPUT_TERMINAL_LIST_MARKER(__VA_ARGS__)' +CPPFLAGS_TERMINAL_LIST += '-Dgrub_term_register_output(...)=OUTPUT_TERMINAL_LIST_MARKER(__VA_ARGS__)' +CPPFLAGS_COMMAND_LIST = '-Dgrub_register_command(...)=COMMAND_LIST_MARKER(__VA_ARGS__)' +CPPFLAGS_COMMAND_LIST += '-Dgrub_register_extcmd(...)=EXTCOMMAND_LIST_MARKER(__VA_ARGS__)' +CPPFLAGS_COMMAND_LIST += '-Dgrub_register_command_p1(...)=P1COMMAND_LIST_MARKER(__VA_ARGS__)' +CPPFLAGS_MARKER = $(CPPFLAGS_FS_LIST) $(CPPFLAGS_VIDEO_LIST) \ + $(CPPFLAGS_PARTTOOL_LIST) $(CPPFLAGS_PARTMAP_LIST) \ + $(CPPFLAGS_TERMINAL_LIST) $(CPPFLAGS_COMMAND_LIST) + # Define these variables to calm down automake -FS_FILES = -DEF_FILES = -UND_FILES = IMG_FILES = MOD_FILES = -VIDEO_FILES = MODULE_FILES = -HANDLER_FILES = -PARTMAP_FILES = -COMMAND_FILES = -PARTTOOL_FILES = -TERMINAL_FILES = +MARKER_FILES = KERNEL_HEADER_FILES = man_MANS = @@ -115,6 +126,7 @@ pkglib_SCRIPTS = noinst_PROGRAMS = grubconf_SCRIPTS = noinst_LIBRARIES = +dist_noinst_DATA = TESTS = EXTRA_DIST = diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist index 3acef7af7..68989d333 100644 --- a/conf/Makefile.extra-dist +++ b/conf/Makefile.extra-dist @@ -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 @@ -14,20 +19,14 @@ EXTRA_DIST += grub-core/Makefile.core.def EXTRA_DIST += grub-core/Makefile.gcry.def EXTRA_DIST += grub-core/genmoddep.awk -EXTRA_DIST += grub-core/genmodsrc.sh -EXTRA_DIST += grub-core/genfslist.sh -EXTRA_DIST += grub-core/gencmdlist.sh +EXTRA_DIST += grub-core/genmod.sh.in +EXTRA_DIST += grub-core/gensyminfo.sh.in EXTRA_DIST += grub-core/gensymlist.sh EXTRA_DIST += grub-core/genemuinit.sh -EXTRA_DIST += grub-core/genvideolist.sh -EXTRA_DIST += grub-core/genhandlerlist.sh -EXTRA_DIST += grub-core/genpartmaplist.sh -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/lib -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') diff --git a/config.h.in b/config.h.in new file mode 100644 index 000000000..4ac9ab5d6 --- /dev/null +++ b/config.h.in @@ -0,0 +1,38 @@ +#if defined (GRUB_UTIL) || !defined (GRUB_MACHINE) +#include +#define NESTED_FUNC_ATTR +#else +/* Define if C symbols get an underscore after compilation. */ +#define HAVE_ASM_USCORE @HAVE_ASM_USCORE@ +/* Define it to \"addr32\" or \"addr32;\" to make GAS happy. */ +#define ADDR32 @ADDR32@ +/* Define it to \"data32\" or \"data32;\" to make GAS happy. */ +#define DATA32 @DATA32@ +/* Define it to one of __bss_start, edata and _edata. */ +#define BSS_START_SYMBOL @BSS_START_SYMBOL@ +/* Define it to either end or _end. */ +#define END_SYMBOL @END_SYMBOL@ +/* Name of package. */ +#define PACKAGE "@PACKAGE@" +/* Version number of package. */ +#define VERSION "@VERSION@" +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "@PACKAGE_STRING@" +/* Define to the version of this package. */ +#define PACKAGE_VERSION "@PACKAGE_VERSION@" +/* Define to the full name of this package. */ +#define PACKAGE_NAME "@PACKAGE_NAME@" +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" +/* Define to 1 if GCC generates calls to __enable_execute_stack(). */ +#define NEED_ENABLE_EXECUTE_STACK @NEED_ENABLE_EXECUTE_STACK@ +/* Define to 1 if GCC generates calls to __register_frame_info(). */ +#define NEED_REGISTER_FRAME_INFO @NEED_REGISTER_FRAME_INFO@ + +#if defined(__i386__) +#define NESTED_FUNC_ATTR __attribute__ ((__regparm__ (1))) +#else +#define NESTED_FUNC_ATTR +#endif + +#endif diff --git a/configure.ac b/configure.ac index 9fa460620..75fa43d53 100644 --- a/configure.ac +++ b/configure.ac @@ -44,7 +44,7 @@ AC_CANONICAL_TARGET AM_INIT_AUTOMAKE() AC_PREREQ(2.60) AC_CONFIG_SRCDIR([include/grub/dl.h]) -AC_CONFIG_HEADER([config.h]) +AC_CONFIG_HEADER([config-util.h]) # Program name transformations AC_ARG_PROGRAM @@ -164,7 +164,7 @@ case "$target_cpu" in mips) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS=1" ;; sparc64) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_SPARC64=1" ;; esac -machine_CPPFLAGS="$machine_CPPFLAGS -DMACHINE=`echo ${target_cpu}_$platform | sed y,abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ,`" +machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE=`echo ${target_cpu}_$platform | sed y,abcdefghijklmnopqrstuvwxyz,ABCDEFGHIJKLMNOPQRSTUVWXYZ,`" HOST_CPPFLAGS="$HOST_CPPFLAGS $machine_CPPFLAGS" TARGET_CPPFLAGS="$TARGET_CPPFLAGS $machine_CPPFLAGS" @@ -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 +#include ]) + +AC_CHECK_MEMBERS([struct statfs.f_mntfromname],,,[$ac_includes_default +#include +#include ]) # For opendisk() and getrawpartition() on NetBSD. # Used in util/deviceiter.c and in util/hostdisk.c. @@ -410,10 +431,9 @@ AC_MSG_CHECKING([for command to convert module to ELF format]) case "${host_os}" in cygwin) TARGET_OBJ2ELF='$(grub_utildir)/grub-pe2elf'; # FIXME: put proper test here - AC_DEFINE([NEED_REGISTER_FRAME_INFO], 1, - [Define to 1 if GCC generates calls to __register_frame_info()]) + NEED_REGISTER_FRAME_INFO=1 ;; - *) ;; + *) NEED_REGISTER_FRAME_INFO=0 ;; esac AC_MSG_RESULT([$TARGET_OBJ2ELF]) @@ -569,17 +589,8 @@ if test "x$target_cpu" = xi386; then CFLAGS="$TARGET_CFLAGS" grub_I386_ASM_PREFIX_REQUIREMENT grub_I386_ASM_ADDR32 - grub_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK -else - AC_DEFINE([NESTED_FUNC_ATTR], [], [Catch gcc bug]) fi -AH_BOTTOM([#if defined(__i386__) && !defined(GRUB_UTIL) -#define NESTED_FUNC_ATTR __attribute__ ((__regparm__ (1))) -#else -#define NESTED_FUNC_ATTR -#endif]) - AC_ARG_ENABLE([efiemu], [AS_HELP_STRING([--enable-efiemu], [build and install the efiemu runtimes (default=guessed)])]) @@ -677,8 +688,8 @@ if test x"$missing_ncurses" = xtrue ; then AC_MSG_ERROR([grub-emu can't be compiled without ncurses]) fi -if test x"$enable_grub_emu_usb" = xno ; then - grub_emu_usb_excuse="explicitly disabled" +if test x"$enable_grub_emu_usb" != xyes ; then + grub_emu_usb_excuse="not enabled" fi if test x"$enable_grub_emu_pci" = xyes ; then @@ -762,19 +773,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)])]) @@ -788,12 +786,12 @@ if test x"$grub_mkfont_excuse" = x ; then if test "x$FREETYPE" = x ; then grub_mkfont_excuse=["need freetype2 library"] fi - freetype_cflags=`freetype-config --cflags` - freetype_libs=`freetype-config --libs` fi if test x"$grub_mkfont_excuse" = x ; then # Check for freetype libraries. + freetype_cflags=`freetype-config --cflags` + freetype_libs=`freetype-config --libs` SAVED_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $freetype_cflags" AC_CHECK_HEADERS([ft2build.h], [], @@ -822,12 +820,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,27 +851,27 @@ 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) AC_SUBST([FONT_SOURCE]) -AS_IF([test x$target_cpu = xi386 -a x$platform = xpc], - [AC_SUBST([GRUB_KERNEL_MACHINE_LINK_ADDR], 0x8200)]) -AS_IF([test x$target_cpu = xi386 -a x$platform = xcoreboot], - [AC_SUBST([GRUB_KERNEL_MACHINE_LINK_ADDR], 0x8200)]) -AS_IF([test x$target_cpu = xi386 -a x$platform = xmultiboot], - [AC_SUBST([GRUB_KERNEL_MACHINE_LINK_ADDR], 0x8200)]) -AS_IF([test x$target_cpu = xmips -a x$platform = xyeeloong], - [AC_SUBST([GRUB_KERNEL_MACHINE_LINK_ADDR], 0x80200000)]) -AS_IF([test x$target_cpu = xpowerpc -a x$platform = xieee1275], - [AC_SUBST([GRUB_KERNEL_MACHINE_LINK_ADDR], 0x200000)]) AS_IF([test x$target_cpu = xi386 -a x$platform = xqemu], [AC_SUBST([GRUB_BOOT_MACHINE_LINK_ADDR], 0xffe00)]) -AS_IF([test x$target_cpu = xi386 -a x$platform = xieee1275], - [AC_SUBST([GRUB_KERNEL_MACHINE_LINK_ADDR], 0x10000)]) AS_IF([test x$TARGET_APPLE_CC = x1], [AC_SUBST([USE_APPLE_CC_FIXES], yes)]) +AC_SUBST(HAVE_ASM_USCORE) +AC_SUBST(ADDR32) +AC_SUBST(DATA32) +AC_SUBST(BSS_START_SYMBOL) +AC_SUBST(END_SYMBOL) +AC_SUBST(PACKAGE) +AC_SUBST(VERSION) +AC_SUBST(NEED_ENABLE_EXECUTE_STACK) +AC_SUBST(NEED_REGISTER_FRAME_INFO) + # # Automake conditionals # @@ -879,6 +888,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,11 +902,12 @@ 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]) +AM_CONDITIONAL([COND_HAVE_ASM_USCORE], [test x$HAVE_ASM_USCORE = x1]) + # Output files. grub_CHECK_LINK_DIR if test x"$link_dir" = xyes ; then @@ -918,7 +929,9 @@ AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([grub-core/Makefile]) AC_CONFIG_FILES([po/Makefile]) AC_CONFIG_FILES([docs/Makefile]) +AC_CONFIG_FILES([util/bash-completion.d/Makefile]) AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h]) +AC_CONFIG_FILES([config.h]) AC_OUTPUT [ @@ -942,6 +955,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 +970,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 diff --git a/docs/grub.texi b/docs/grub.texi index 18dc39389..076adfd6c 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -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 @@ -2006,8 +2415,7 @@ The serial port is not used as a communication channel unless the @command{terminal_input} or @command{terminal_output} command is used (@pxref{terminal_input}, @pxref{terminal_output}). -This command is only available if GRUB is compiled with serial -support. See also @ref{Serial terminal}. +See also @ref{Serial terminal}. @end deffn @@ -2498,7 +2906,7 @@ This command is only available on x86 systems. @node ls @subsection ls -@deffn Command ls [arg] +@deffn Command ls [arg @dots{}] List devices or files. With no arguments, print all devices known to GRUB. diff --git a/docs/man/grub-menulst2cfg.h2m b/docs/man/grub-menulst2cfg.h2m new file mode 100644 index 000000000..0c0570f27 --- /dev/null +++ b/docs/man/grub-menulst2cfg.h2m @@ -0,0 +1,3 @@ +[NAME] +grub-menulst2cfg \- transform legacy menu.lst into grub.cfg + diff --git a/docs/man/grub-mklayout.h2m b/docs/man/grub-mklayout.h2m new file mode 100644 index 000000000..e0ae9dedb --- /dev/null +++ b/docs/man/grub-mklayout.h2m @@ -0,0 +1,2 @@ +[NAME] +grub-mklayout \- generate a GRUB keyboard layout file diff --git a/docs/man/grub-mknetdir.h2m b/docs/man/grub-mknetdir.h2m new file mode 100644 index 000000000..26defe876 --- /dev/null +++ b/docs/man/grub-mknetdir.h2m @@ -0,0 +1,2 @@ +[NAME] +grub-mknetdir \- prepare a GRUB netboot directory. diff --git a/gentpl.py b/gentpl.py index abfb20444..3fe995dc0 100644 --- a/gentpl.py +++ b/gentpl.py @@ -276,75 +276,13 @@ def module(platform): r += gvar_add("BUILT_SOURCES", "$(nodist_" + cname() + "_SOURCES)") r += gvar_add("CLEANFILES", "$(nodist_" + cname() + "_SOURCES)") - r += gvar_add("DEF_FILES", "def-[+ name +].lst") - r += gvar_add("UND_FILES", "und-[+ name +].lst") r += gvar_add("MOD_FILES", "[+ name +].mod") - r += gvar_add("platform_DATA", "[+ name +].mod") - r += gvar_add("CLEANFILES", "def-[+ name +].lst und-[+ name +].lst mod-[+ name +].c mod-[+ name +].o [+ name +].mod") - - r += gvar_add("COMMAND_FILES", "command-[+ name +].lst") - r += gvar_add("FS_FILES", "fs-[+ name +].lst") - r += gvar_add("VIDEO_FILES", "video-[+ name +].lst") - r += gvar_add("PARTMAP_FILES", "partmap-[+ name +].lst") - r += gvar_add("HANDLER_FILES", "handler-[+ name +].lst") - r += gvar_add("PARTTOOL_FILES", "parttool-[+ name +].lst") - r += gvar_add("TERMINAL_FILES", "terminal-[+ name +].lst") - r += gvar_add("CLEANFILES", "command-[+ name +].lst fs-[+ name +].lst") - r += gvar_add("CLEANFILES", "handler-[+ name +].lst terminal-[+ name +].lst") - r += gvar_add("CLEANFILES", "video-[+ name +].lst partmap-[+ name +].lst parttool-[+ name +].lst") - - r += gvar_add("CLEANFILES", "[+ name +].pp") + r += gvar_add("MARKER_FILES", "[+ name +].marker") + r += gvar_add("CLEANFILES", "[+ name +].marker") r += """ -[+ name +].pp: $(""" + cname() + """_SOURCES) $(nodist_""" + cname() + """_SOURCES) - $(TARGET_CPP) -DGRUB_LST_GENERATOR $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(""" + cname() + """_CPPFLAGS) $(CPPFLAGS) $^ > $@ || (rm -f $@; exit 1) - -def-[+ name +].lst: [+ name +].module$(EXEEXT) - if test x$(USE_APPLE_CC_FIXES) = xyes; then \ - $(NM) -g -P -p $< | grep -E '^[a-zA-Z0-9_]* [TDS]' | sed "s/^\\([^ ]*\\).*/\\1 [+ name +]/" >> $@; \ - else \ - $(NM) -g --defined-only -P -p $< | sed "s/^\\([^ ]*\\).*/\\1 [+ name +]/" >> $@; \ - fi - -und-[+ name +].lst: [+ name +].module$(EXEEXT) - $(NM) -u -P -p $< | sed "s/^\\([^ ]*\\).*/\\1 [+ name +]/" >> $@ - -mod-[+ name +].c: [+ name +].module$(EXEEXT) moddep.lst genmodsrc.sh - sh $(srcdir)/genmodsrc.sh [+ name +] moddep.lst > $@ || (rm -f $@; exit 1) - -mod-[+ name +].o: mod-[+ name +].c - $(TARGET_CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(""" + cname() + """_CPPFLAGS) $(CPPFLAGS) $(""" + cname() + """_CFLAGS) $(CFLAGS) -c -o $@ $< - -[+ name +].mod: [+ name +].module$(EXEEXT) mod-[+ name +].o - if test x$(USE_APPLE_CC_FIXES) = xyes; then \ - $(CCLD) $(""" + cname() + """_LDFLAGS) $(LDFLAGS) -o $@.bin $^; \ - $(OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -wd1106 -nu -nd $@.bin $@; \ - rm -f $@.bin; \ - else \ - $(CCLD) -o $@ $(""" + cname() + """_LDFLAGS) $(LDFLAGS) $^; \ - if test ! -z '$(TARGET_OBJ2ELF)'; then $(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi; \ - $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@; \ - fi - -command-[+ name +].lst: [+ name +].pp $(srcdir)/gencmdlist.sh - cat $< | sh $(srcdir)/gencmdlist.sh [+ name +] > $@ || (rm -f $@; exit 1) - -fs-[+ name +].lst: [+ name +].pp $(srcdir)/genfslist.sh - cat $< | sh $(srcdir)/genfslist.sh [+ name +] > $@ || (rm -f $@; exit 1) - -video-[+ name +].lst: [+ name +].pp $(srcdir)/genvideolist.sh - cat $< | sh $(srcdir)/genvideolist.sh [+ name +] > $@ || (rm -f $@; exit 1) - -partmap-[+ name +].lst: [+ name +].pp $(srcdir)/genpartmaplist.sh - cat $< | sh $(srcdir)/genpartmaplist.sh [+ name +] > $@ || (rm -f $@; exit 1) - -parttool-[+ name +].lst: [+ name +].pp $(srcdir)/genparttoollist.sh - cat $< | sh $(srcdir)/genparttoollist.sh [+ name +] > $@ || (rm -f $@; exit 1) - -handler-[+ name +].lst: [+ name +].pp $(srcdir)/genhandlerlist.sh - cat $< | sh $(srcdir)/genhandlerlist.sh [+ name +] > $@ || (rm -f $@; exit 1) - -terminal-[+ name +].lst: [+ name +].pp $(srcdir)/genterminallist.sh - cat $< | sh $(srcdir)/genterminallist.sh [+ name +] > $@ || (rm -f $@; exit 1) +[+ name +].marker: $(""" + cname() + """_SOURCES) $(nodist_""" + cname() + """_SOURCES) + $(TARGET_CPP) -DGRUB_LST_GENERATOR $(CPPFLAGS_MARKER) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(""" + cname() + """_CPPFLAGS) $(CPPFLAGS) $^ > $@.new || (rm -f $@; exit 1) + grep 'MARKER' $@.new > $@; rm -f $@.new """ return r @@ -471,14 +409,13 @@ def script(platform): r += "[+ IF mansection +]" + manpage() + "[+ ENDIF +]" r += "[+ ENDIF +]" - r += rule("[+ name +]", "$(top_builddir)/config.status " + platform_sources(platform), """ -$(top_builddir)/config.status --file=-:""" + platform_sources(platform) + """ \ - | sed -e 's,@pkglib_DATA@,$(pkglib_DATA),g' > $@ + r += rule("[+ name +]", platform_sources(platform) + " $(top_builddir)/config.status", """ +$(top_builddir)/config.status --file=-:$< | sed -e 's,@pkglib_DATA@,$(pkglib_DATA),g' > $@ 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(): diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 5d13d0313..addc83417 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -74,9 +74,10 @@ 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 +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h if COND_i386_pc -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h @@ -92,24 +93,20 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_coreboot -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_multiboot -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_qemu -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_ieee1275 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif @@ -122,8 +119,8 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_mips_yeeloong +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/cache.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bitmap.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video.h @@ -132,19 +129,17 @@ 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 +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/serial.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h 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 @@ -178,13 +173,19 @@ symlist.c: symlist.h gensymlist.sh CLEANFILES += symlist.c BUILT_SOURCES += symlist.c +if COND_HAVE_ASM_USCORE +ASM_PREFIX=1 +else +ASM_PREFIX= +endif + noinst_DATA += kernel_syms.lst + kernel_syms.lst: $(KERNEL_HEADER_FILES) $(top_builddir)/config.h $(TARGET_CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS_KERNEL) $(CPPFLAGS) $(CFLAGS) -DGRUB_SYMBOL_GENERATOR=1 $^ >kernel_syms.input - if grep "^#define HAVE_ASM_USCORE" $(top_builddir)/config.h; then u="_"; else u=""; fi; \ cat kernel_syms.input | grep -v '^#' | sed -n \ - -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/'"$$u"'\1 kernel/;p;}' \ - -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/'"$$u"'\1 kernel/;p;}' \ + -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/defined '"$(ASM_PREFIX)"'kernel \1/;p;}' \ + -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/defined '"$(ASM_PREFIX)"' kernel \1/;p;}' \ | sort -u >$@ rm -f kernel_syms.input CLEANFILES += kernel_syms.lst @@ -204,61 +205,91 @@ grub_emu_init.c: grub_emu_init.h genemuinit.sh $(MOD_FILES) CLEANFILES += grub_emu_init.c endif -# .lst files -platform_DATA += moddep.lst -platform_DATA += fs.lst -platform_DATA += command.lst -platform_DATA += partmap.lst -platform_DATA += handler.lst -platform_DATA += terminal.lst -platform_DATA += parttool.lst -platform_DATA += video.lst -platform_DATA += crypto.lst -CLEANFILES += moddep.lst -CLEANFILES += handler.lst -CLEANFILES += terminal.lst -CLEANFILES += parttool.lst -CLEANFILES += video.lst -CLEANFILES += crypto.lst +# List files -fs.lst: $(FS_FILES) - cat $^ /dev/null | sort | uniq > $@ +fs.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + if grep 'FS_LIST_MARKER' $$pp >/dev/null 2>&1; then \ + echo $$b; \ + fi; \ + done) | sort -u > $@ +platform_DATA += fs.lst CLEANFILES += fs.lst -command.lst: $(COMMAND_FILES) - cat $^ /dev/null | sort | uniq > $@ +command.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + sed -n \ + -e "/COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" \ + -e "/EXTCOMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" \ + -e "/P1COMMAND_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $$b/;p;}" $$pp; \ + done) | sort -u > $@ +platform_DATA += command.lst CLEANFILES += command.lst -partmap.lst: $(PARTMAP_FILES) - cat $^ /dev/null | sort | uniq > $@ +partmap.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + if grep 'PARTMAP_LIST_MARKER' $$pp >/dev/null 2>&1; then \ + echo $$b; \ + fi; \ + done) | sort -u > $@ +platform_DATA += partmap.lst CLEANFILES += partmap.lst -handler.lst: $(HANDLER_FILES) - cat $^ /dev/null | sort | uniq > $@ -CLEANFILES += handler.lst - -terminal.lst: $(TERMINAL_FILES) - cat $^ /dev/null | sort | uniq > $@ +terminal.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + sed -n \ + -e "/INPUT_TERMINAL_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $$b/;p;}" \ + -e "/OUTPUT_TERMINAL_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $$b/;p;}" $$pp; \ + done) | sort -u > $@ +platform_DATA += terminal.lst CLEANFILES += terminal.lst -parttool.lst: $(PARTTOOL_FILES) - cat $^ /dev/null | sort | uniq > $@ +parttool.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + sed -n \ + -e "/PARTTOOL_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $$b/;p;}" $$pp; \ + done) | sort -u > $@ +platform_DATA += parttool.lst CLEANFILES += parttool.lst -video.lst: $(VIDEO_FILES) - cat $^ /dev/null | sort | uniq > $@ +video.lst: $(MARKER_FILES) + (for pp in $^; do \ + b=`basename $$pp .marker`; \ + if grep 'VIDEO_LIST_MARKER' $$pp >/dev/null 2>&1; then \ + echo $$b; \ + fi; \ + done) | sort -u > $@ +platform_DATA += video.lst CLEANFILES += video.lst # but, crypto.lst is simply copied crypto.lst: $(srcdir)/lib/libgcrypt-grub/cipher/crypto.lst cp $^ $@ +platform_DATA += crypto.lst CLEANFILES += crypto.lst +syminfo.lst: gensyminfo.sh kernel_syms.lst $(MODULE_FILES) + cat kernel_syms.lst > $@.new + for m in $(MODULE_FILES); do \ + sh $< $$m >> $@.new || exit 1; \ + done + mv $@.new $@ + # generate global module dependencies list -moddep.lst: kernel_syms.lst genmoddep.awk $(DEF_FILES) $(UND_FILES) - cat $(DEF_FILES) kernel_syms.lst /dev/null \ - | $(AWK) -f $(srcdir)/genmoddep.awk $(UND_FILES) > $@ \ - || (rm -f $@; exit 1) +moddep.lst: syminfo.lst genmoddep.awk + cat $< | sort | awk -f $(srcdir)/genmoddep.awk > $@ || (rm -f $@; exit 1) +platform_DATA += moddep.lst +CLEANFILES += config.log syminfo.lst moddep.lst + +$(MOD_FILES): %.mod : genmod.sh moddep.lst %.module$(EXEEXT) + sh $^ $@ +platform_DATA += $(MOD_FILES) +CLEANFILES += $(MOD_FILES) if COND_ENABLE_EFIEMU efiemu32.o: efiemu/runtime/efiemu.c $(TARGET_OBJ2ELF) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 576490fbf..22182f327 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1,5 +1,17 @@ AutoGen definitions Makefile.tpl; +script = { + installdir = noinst; + name = gensyminfo.sh; + common = gensyminfo.sh.in; +}; + +script = { + installdir = noinst; + name = genmod.sh; + common = genmod.sh.in; +}; + kernel = { name = kernel; @@ -10,20 +22,20 @@ kernel = { x86_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment'; i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)'; - i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),$(GRUB_KERNEL_MACHINE_LINK_ADDR)'; + i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200'; i386_qemu_ldflags = '$(TARGET_IMG_LDFLAGS)'; - i386_qemu_ldflags = '$(TARGET_IMG_BASE_LDOPT),$(GRUB_KERNEL_MACHINE_LINK_ADDR)'; + i386_qemu_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x8200'; - i386_coreboot_ldflags = '-Wl,-Ttext=$(GRUB_KERNEL_MACHINE_LINK_ADDR)'; - i386_multiboot_ldflags = '-Wl,-Ttext=$(GRUB_KERNEL_MACHINE_LINK_ADDR)'; - i386_ieee1275_ldflags = '-Wl,-Ttext=$(GRUB_KERNEL_MACHINE_LINK_ADDR)'; - mips_yeeloong_ldflags = '-Wl,-Ttext,$(GRUB_KERNEL_MACHINE_LINK_ADDR)'; - powerpc_ieee1275_ldflags = '-Wl,-Ttext,$(GRUB_KERNEL_MACHINE_LINK_ADDR)'; + i386_coreboot_ldflags = '-Wl,-Ttext=0x8200'; + i386_multiboot_ldflags = '-Wl,-Ttext=0x8200'; + i386_ieee1275_ldflags = '-Wl,-Ttext=0x10000'; + mips_yeeloong_ldflags = '-Wl,-Ttext,0x80200000'; + powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000'; + sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400'; mips_yeeloong_cppflags = '-DUSE_ASCII_FAILBACK'; i386_qemu_cppflags = '-DGRUB_BOOT_MACHINE_LINK_ADDR=$(GRUB_BOOT_MACHINE_LINK_ADDR)'; - i386_qemu_ccasflags = '-DGRUB_KERNEL_MACHINE_LINK_ADDR=$(GRUB_KERNEL_MACHINE_LINK_ADDR)'; emu_cflags = '$(CFLAGS_GNULIB)'; emu_cppflags = '$(CPPFLAGS_GNULIB)'; @@ -137,6 +149,8 @@ kernel = { mips_yeeloong = term/at_keyboard.c; mips_yeeloong = term/serial.c; mips_yeeloong = video/sm712.c; + extra_dist = video/sm712_init.c; + mips_yeeloong = commands/keylayouts.c; powerpc_ieee1275 = kern/ieee1275/init.c; powerpc_ieee1275 = kern/powerpc/cache.S; @@ -149,6 +163,7 @@ kernel = { emu = disk/host.c; emu = gnulib/progname.c; + emu = gnulib/error.c; emu = kern/emu/console.c; emu = kern/emu/getroot.c; emu = kern/emu/hostdisk.c; @@ -172,6 +187,8 @@ kernel = { videoinkernel = video/fb/video_fb.c; videoinkernel = video/video.c; + videoinkernel = commands/boot.c; + extra_dist = kern/i386/realmode.S; extra_dist = kern/i386/pc/lzma_decode.S; extra_dist = kern/mips/cache_flush.S; @@ -186,7 +203,7 @@ program = { ldadd = 'kernel.img$(EXEEXT)'; ldadd = '$(MODULE_FILES)'; - ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER)'; + ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; enable = emu; }; @@ -199,7 +216,7 @@ program = { emu_nodist = symlist.c; ldadd = 'kernel.img$(EXEEXT)'; - ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER)'; + ldadd = '$(LIBUTIL) $(LIBCURSES) $(LIBSDL) $(LIBUSB) $(LIBPCIACCESS) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR)'; enable = emu; }; @@ -318,25 +335,19 @@ module = { module = { name = usbserial_common; common = bus/usb/serial/common.c; - enable = emu; enable = usb; - emu_condition = COND_GRUB_EMU_USB; }; module = { name = usbserial_pl2303; common = bus/usb/serial/pl2303.c; - enable = emu; enable = usb; - emu_condition = COND_GRUB_EMU_USB; }; module = { name = usbserial_ftdi; common = bus/usb/serial/ftdi.c; - enable = emu; enable = usb; - emu_condition = COND_GRUB_EMU_USB; }; module = { @@ -394,6 +405,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)'; @@ -458,6 +470,7 @@ module = { name = boot; common = commands/boot.c; i386_pc = lib/i386/pc/biosnum.c; + enable = videomodules; }; module = { @@ -481,12 +494,6 @@ module = { enable = x86; }; -module = { - name = crc; - common = commands/crc.c; - common = lib/crc.c; -}; - module = { name = date; common = commands/date.c; @@ -526,6 +533,10 @@ module = { name = halt; nopc = commands/halt.c; i386_pc = commands/i386/pc/halt.c; + i386_pc = commands/acpihalt.c; + i386_coreboot = commands/acpihalt.c; + i386_multiboot = commands/acpihalt.c; + x86_efi = commands/acpihalt.c; i386_multiboot = lib/i386/halt.c; i386_coreboot = lib/i386/halt.c; i386_qemu = lib/i386/halt.c; @@ -706,15 +717,8 @@ module = { }; module = { - name = vbeinfo; - i386_pc = commands/i386/pc/vbeinfo.c; - enable = i386_pc; -}; - -module = { - name = vbetest; - i386_pc = commands/i386/pc/vbetest.c; - enable = i386_pc; + name = videoinfo; + common = commands/videoinfo.c; }; module = { @@ -868,6 +872,11 @@ module = { common = fs/befs_be.c; }; +module = { + name = btrfs; + common = fs/btrfs.c; +}; + module = { name = cpio; common = fs/cpio.c; @@ -913,6 +922,11 @@ module = { common = fs/minix.c; }; +module = { + name = minix2; + common = fs/minix2.c; +}; + module = { name = nilfs2; common = fs/nilfs2.c; @@ -1044,6 +1058,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; @@ -1119,6 +1136,7 @@ module = { module = { name = linux; x86 = loader/i386/linux.c; + i386_pc = lib/i386/pc/vesa_modes_table.c; mips = loader/mips/linux.c; powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; @@ -1195,6 +1213,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; @@ -1411,3 +1431,43 @@ module = { name = datehook; common = hook/datehook.c; }; + +module = { + name = legacycfg; + common = commands/legacycfg.c; + common = lib/legacy_parse.c; + emu = lib/i386/pc/vesa_modes_table.c; + enable = i386_pc; + enable = emu; +}; + +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; +}; + +module = { + name = lsapm; + common = commands/i386/pc/lsapm.c; + enable = i386_pc; +}; + +module = { + name = keylayouts; + common = commands/keylayouts.c; + enable = videomodules; +}; diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S index 6b16a913a..320918566 100644 --- a/grub-core/boot/i386/pc/boot.S +++ b/grub-core/boot/i386/pc/boot.S @@ -112,12 +112,16 @@ LOCAL(after_BPB): */ . = _start + GRUB_BOOT_MACHINE_DRIVE_CHECK boot_drive_check: - jmp 1f /* grub-setup may overwrite this jump */ + jmp 3f /* grub-setup may overwrite this jump */ testb $0x80, %dl - jnz 1f + jz 2f +3: + /* Ignore %dl different from 0-0x0f and 0x80-0x8f. */ + testb $0x70, %dl + jz 1f +2: movb $0x80, %dl 1: - /* * ljmp to the next instruction because some bogus BIOSes * jump to 07C0:0000 instead of 0000:7C00. diff --git a/grub-core/boot/i386/pc/lnxboot.S b/grub-core/boot/i386/pc/lnxboot.S index b4f0030b8..9348553c3 100644 --- a/grub-core/boot/i386/pc/lnxboot.S +++ b/grub-core/boot/i386/pc/lnxboot.S @@ -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 diff --git a/grub-core/boot/i386/qemu/boot.S b/grub-core/boot/i386/qemu/boot.S index fe14f0f06..97aeab9e6 100644 --- a/grub-core/boot/i386/qemu/boot.S +++ b/grub-core/boot/i386/qemu/boot.S @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c index 587a36420..bf5aaa7c0 100644 --- a/grub-core/bus/usb/ohci.c +++ b/grub-core/bus/usb/ohci.c @@ -98,7 +98,6 @@ struct grub_ohci struct grub_pci_dma_chunk *td_chunk; struct grub_ohci *next; grub_ohci_td_t td_free; /* Pointer to first free TD */ - int bad_OHCI; }; static struct grub_ohci *ohci; @@ -149,8 +148,8 @@ typedef enum #define GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE (1 << 4) #define GRUB_OHCI_RESET_CONNECT_CHANGE (1 << 16) -#define GRUB_OHCI_CTRL_EDS 16 -#define GRUB_OHCI_BULK_EDS 16 +#define GRUB_OHCI_CTRL_EDS 256 +#define GRUB_OHCI_BULK_EDS 510 #define GRUB_OHCI_TDS 256 #define GRUB_OHCI_ED_ADDR_MASK 0x7ff @@ -442,8 +441,10 @@ grub_ohci_pci_iter (grub_pci_device_t dev, (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBA) & ~GRUB_OHCI_RHUB_PORT_POWER_MASK) | GRUB_OHCI_RHUB_PORT_ALL_POWERED); +#if 0 /* We don't need it at all, handled via hotplugging */ /* Now we have hot-plugging, we need to wait for stable power only */ grub_millisleep (100); +#endif /* Link to ohci now that initialisation is successful. */ o->next = ohci; @@ -623,7 +624,8 @@ grub_ohci_transaction (grub_ohci_td_t td, break; } - /* Set the token (Always generate interrupt - bits 21-23 = 0). */ + /* Set the token */ + token |= ( 7 << 21); /* Never generate interrupt */ token |= toggle << 24; token |= 1 << 25; @@ -652,36 +654,31 @@ grub_ohci_transaction (grub_ohci_td_t td, td->next_td = 0; } +struct grub_ohci_transfer_controller_data +{ + grub_uint32_t tderr_phys; + grub_uint32_t td_last_phys; + grub_ohci_ed_t ed_virt; + grub_ohci_td_t td_current_virt; + grub_ohci_td_t td_head_virt; +}; + static grub_usb_err_t -grub_ohci_transfer (grub_usb_controller_t dev, - grub_usb_transfer_t transfer, int timeout, - grub_size_t *actual) +grub_ohci_setup_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) { struct grub_ohci *o = (struct grub_ohci *) dev->data; - grub_ohci_ed_t ed_virt; int bulk = 0; - grub_ohci_td_t td_head_virt; - grub_ohci_td_t td_current_virt; grub_ohci_td_t td_next_virt; - grub_ohci_td_t tderr_virt = NULL; grub_uint32_t target; grub_uint32_t td_head_phys; grub_uint32_t td_tail_phys; - grub_uint32_t td_last_phys; - grub_uint32_t tderr_phys = 0; - grub_uint32_t status; - grub_uint32_t control; - grub_uint8_t errcode = 0; - grub_usb_err_t err = GRUB_USB_ERR_NONE; int i; - grub_uint64_t maxtime; - grub_uint64_t bad_OHCI_delay = 0; - int err_halt = 0; - int err_timeout = 0; - int err_unrec = 0; - grub_uint32_t intstatus; + struct grub_ohci_transfer_controller_data *cdata; - *actual = 0; + cdata = grub_zalloc (sizeof (*cdata)); + if (!cdata) + return GRUB_USB_ERR_INTERNAL; /* Pre-set target for ED - we need it to find proper ED */ /* Set the device address. */ @@ -703,21 +700,23 @@ grub_ohci_transfer (grub_usb_controller_t dev, case GRUB_USB_TRANSACTION_TYPE_CONTROL: break; - default : + default: + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } /* Find proper ED or add new ED */ - ed_virt = grub_ohci_find_ed (o, bulk, target); - if (!ed_virt) + cdata->ed_virt = grub_ohci_find_ed (o, bulk, target); + if (!cdata->ed_virt) { grub_dprintf ("ohci","Fatal: No free ED !\n"); + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } /* Take pointer to first TD from ED */ - td_head_phys = grub_le_to_cpu32 (ed_virt->td_head) & ~0xf; - td_tail_phys = grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf; + td_head_phys = grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf; + td_tail_phys = grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xf; /* Sanity check - td_head should be equal to td_tail */ if (td_head_phys != td_tail_phys) /* Should never happen ! */ @@ -726,6 +725,7 @@ grub_ohci_transfer (grub_usb_controller_t dev, grub_dprintf ("ohci", "HEAD = 0x%02x, TAIL = 0x%02x\n", td_head_phys, td_tail_phys); /* XXX: Fix: What to do ? */ + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } @@ -733,65 +733,62 @@ grub_ohci_transfer (grub_usb_controller_t dev, * we must allocate the first TD. */ if (!td_head_phys) { - td_head_virt = grub_ohci_alloc_td (o); - if (!td_head_virt) + cdata->td_head_virt = grub_ohci_alloc_td (o); + if (!cdata->td_head_virt) return GRUB_USB_ERR_INTERNAL; /* We don't need de-allocate ED */ /* We can set td_head only when ED is not active, i.e. * when it is newly allocated. */ - ed_virt->td_head = grub_cpu_to_le32 ( grub_ohci_td_virt2phys (o, - td_head_virt) ); - ed_virt->td_tail = ed_virt->td_head; + cdata->ed_virt->td_head + = grub_cpu_to_le32 (grub_ohci_td_virt2phys (o, cdata->td_head_virt)); + cdata->ed_virt->td_tail = cdata->ed_virt->td_head; } else - td_head_virt = grub_ohci_td_phys2virt ( o, td_head_phys ); + cdata->td_head_virt = grub_ohci_td_phys2virt ( o, td_head_phys ); /* Set TDs */ - td_last_phys = td_head_phys; /* initial value to make compiler happy... */ - for (i = 0, td_current_virt = td_head_virt; + cdata->td_last_phys = td_head_phys; /* initial value to make compiler happy... */ + for (i = 0, cdata->td_current_virt = cdata->td_head_virt; i < transfer->transcnt; i++) { grub_usb_transaction_t tr = &transfer->transactions[i]; - grub_ohci_transaction (td_current_virt, tr->pid, tr->toggle, + grub_ohci_transaction (cdata->td_current_virt, tr->pid, tr->toggle, tr->size, tr->data); /* Set index of TD in transfer */ - td_current_virt->tr_index = (grub_uint32_t) i; - - /* No IRQ request in TD if bad_OHCI set */ - if (o->bad_OHCI) - td_current_virt->token |= grub_cpu_to_le32 ( 7 << 21); + cdata->td_current_virt->tr_index = (grub_uint32_t) i; /* Remember last used (processed) TD phys. addr. */ - td_last_phys = grub_ohci_td_virt2phys (o, td_current_virt); + cdata->td_last_phys = grub_ohci_td_virt2phys (o, cdata->td_current_virt); /* Allocate next TD */ td_next_virt = grub_ohci_alloc_td (o); if (!td_next_virt) /* No free TD, cancel transfer and free TDs except head TD */ { if (i) /* if i==0 we have nothing to free... */ - grub_ohci_free_tds (o, - grub_ohci_td_phys2virt(o, - grub_le_to_cpu32 (td_head_virt->next_td) ) ); + grub_ohci_free_tds (o, grub_ohci_td_phys2virt(o, + grub_le_to_cpu32 (cdata->td_head_virt->next_td))); /* Reset head TD */ - grub_memset ( (void*)td_head_virt, 0, + grub_memset ( (void*)cdata->td_head_virt, 0, sizeof(struct grub_ohci_td) ); grub_dprintf ("ohci", "Fatal: No free TD !"); + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } /* Chain TDs */ - td_current_virt->link_td = td_next_virt; - td_current_virt->next_td = grub_cpu_to_le32 ( + + cdata->td_current_virt->link_td = td_next_virt; + cdata->td_current_virt->next_td = grub_cpu_to_le32 ( grub_ohci_td_virt2phys (o, td_next_virt) ); td_next_virt->prev_td_phys = grub_ohci_td_virt2phys (o, - td_current_virt); - td_current_virt = td_next_virt; + cdata->td_current_virt); + cdata->td_current_virt = td_next_virt; } grub_dprintf ("ohci", "Tail TD (not processed) = %p\n", - td_current_virt); + cdata->td_current_virt); /* Setup the Endpoint Descriptor for transfer. */ /* First set necessary fields in TARGET but keep (or set) skip bit */ @@ -799,12 +796,12 @@ grub_ohci_transfer (grub_usb_controller_t dev, * size never change after first allocation of ED. * But unfortunately max. packet size may change during initial * setup sequence and we must handle it. */ - ed_virt->target = grub_cpu_to_le32 (target | (1 << 14)); + cdata->ed_virt->target = grub_cpu_to_le32 (target | (1 << 14)); /* Set td_tail */ - ed_virt->td_tail - = grub_cpu_to_le32 (grub_ohci_td_virt2phys (o, td_current_virt)); + cdata->ed_virt->td_tail + = grub_cpu_to_le32 (grub_ohci_td_virt2phys (o, cdata->td_current_virt)); /* Now reset skip bit */ - ed_virt->target = grub_cpu_to_le32 (target); + cdata->ed_virt->target = grub_cpu_to_le32 (target); /* ed_virt->td_head = grub_cpu_to_le32 (td_head); Must not be changed, it is maintained by OHCI */ /* ed_virt->next_ed = grub_cpu_to_le32 (0); Handled by grub_ohci_find_ed, do not change ! */ @@ -834,93 +831,21 @@ grub_ohci_transfer (grub_usb_controller_t dev, } } - /* Safety measure to avoid a hang. */ - maxtime = grub_get_time_ms () + timeout; - - /* Wait until the transfer is completed or STALLs. */ - do - { - /* Check transfer status */ - intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - if (!o->bad_OHCI && (intstatus & 0x2) != 0) - { - /* Remember last successful TD */ - tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; - /* Reset DoneHead */ - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - /* if TD is last, finish */ - if (tderr_phys == td_last_phys) - { - if (grub_le_to_cpu32 (ed_virt->td_head) & 1) - err_halt = 1; - break; - } - continue; - } + transfer->controller_data = cdata; - if ((intstatus & 0x10) != 0) - { /* Unrecoverable error - only reset can help...! */ - err_unrec = 1; - break; - } + return GRUB_USB_ERR_NONE; +} - /* Detected a HALT. */ - if (err_halt || (grub_le_to_cpu32 (ed_virt->td_head) & 1)) - { - err_halt = 1; - /* ED is halted, but donehead event can happened in the meantime */ - intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - if (!o->bad_OHCI && (intstatus & 0x2) != 0) - /* Don't break loop now, first do donehead action(s) */ - continue; - break; - } - - /* bad OHCI handling */ - if ( (grub_le_to_cpu32 (ed_virt->td_head) & ~0xf) == - (grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf) ) /* Empty ED */ - { - if (o->bad_OHCI) /* Bad OHCI detected previously */ - { - /* Try get last successful TD. */ - tderr_phys = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; - if (tderr_phys)/* Reset DoneHead if we were successful */ - { - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - } - /* Check the HALT bit */ - if (grub_le_to_cpu32 (ed_virt->td_head) & 1) - err_halt = 1; - break; - } - else /* Detection of bad OHCI */ - /* We should wait short time (~2ms) before we say that - * it is bad OHCI to prevent some hazard - - * donehead can react in the meantime. This waiting is done - * only once per OHCI driver "live cycle". */ - if (!bad_OHCI_delay) /* Set delay time */ - bad_OHCI_delay = grub_get_time_ms () + 2; - else if (grub_get_time_ms () >= bad_OHCI_delay) - o->bad_OHCI = 1; - continue; - } - - /* Timeout ? */ - if (grub_get_time_ms () > maxtime) - { - err_timeout = 1; - break; - } - - grub_cpu_idle (); - } - while (1); +static void +pre_finish_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_uint32_t target; + grub_uint32_t status; + grub_uint32_t control; + grub_uint32_t intstatus; /* There are many ways how the loop above can finish: * - normally without any error via INTSTATUS WDH bit @@ -952,8 +877,8 @@ grub_ohci_transfer (grub_usb_controller_t dev, /* Remember target for debug and set skip flag in ED */ /* It should be normaly not necessary but we need it at least * in case of timeout */ - target = grub_le_to_cpu32 ( ed_virt->target ); - ed_virt->target = grub_cpu_to_le32 (target | (1 << 14)); + target = grub_le_to_cpu32 ( cdata->ed_virt->target ); + cdata->ed_virt->target = grub_cpu_to_le32 (target | (1 << 14)); /* Read registers for debug - they should be read now because * debug prints case unwanted delays, so something can happen * in the meantime... */ @@ -963,253 +888,321 @@ grub_ohci_transfer (grub_usb_controller_t dev, /* Now print debug values - to have full info what happened */ grub_dprintf ("ohci", "loop finished: control=0x%02x status=0x%02x\n", control, status); - grub_dprintf ("ohci", "intstatus=0x%02x \n\t\t tderr_phys=0x%02x, td_last_phys=0x%02x\n", - intstatus, tderr_phys, td_last_phys); - grub_dprintf ("ohci", "err_unrec=%d, err_timeout=%d \n\t\t err_halt=%d, bad_OHCI=%d\n", - err_unrec, err_timeout, err_halt, o->bad_OHCI); + grub_dprintf ("ohci", "intstatus=0x%02x, td_last_phys=0x%02x\n", + intstatus, cdata->td_last_phys); grub_dprintf ("ohci", "TARGET=0x%02x, HEAD=0x%02x, TAIL=0x%02x\n", target, - grub_le_to_cpu32 (ed_virt->td_head), - grub_le_to_cpu32 (ed_virt->td_tail) ); + grub_le_to_cpu32 (cdata->ed_virt->td_head), + grub_le_to_cpu32 (cdata->ed_virt->td_tail) ); - if (!err_halt && !err_unrec && !err_timeout) /* normal finish */ - { - /* Simple workaround if donehead is not working */ - if (o->bad_OHCI && - ( !tderr_phys || (tderr_phys != td_last_phys) ) ) - { - grub_dprintf ("ohci", "normal finish, but tderr_phys corrected\n"); - tderr_phys = td_last_phys; - /* I hope we can do it as transfer (most probably) finished OK */ - } - /* Prepare pointer to last processed TD */ - tderr_virt = grub_ohci_td_phys2virt (o, tderr_phys); - /* Set index of last processed TD */ - if (tderr_virt) - transfer->last_trans = tderr_virt->tr_index; - else - transfer->last_trans = -1; - *actual = transfer->size + 1; - } +} - else if (err_halt) /* error, ED is halted by OHCI, i.e. can be modified */ - { - /* First we must get proper tderr_phys value */ - if (o->bad_OHCI) /* In case of bad_OHCI tderr_phys can be wrong */ - { - if ( tderr_phys ) /* check if tderr_phys points to TD with error */ - errcode = grub_le_to_cpu32 ( grub_ohci_td_phys2virt (o, - tderr_phys)->token ) - >> 28; - if ( !tderr_phys || !errcode ) /* tderr_phys not valid or points to wrong TD */ - { /* Retired TD with error should be previous TD to ED->td_head */ - tderr_phys = grub_ohci_td_phys2virt (o, - grub_le_to_cpu32 ( ed_virt->td_head) & ~0xf ) - ->prev_td_phys; - } - } - - /* Even if we have "good" OHCI, in some cases - * tderr_phys can be zero, check it */ - else if ( !tderr_phys ) - { /* Retired TD with error should be previous TD to ED->td_head */ - tderr_phys = grub_ohci_td_phys2virt (o, - grub_le_to_cpu32 ( ed_virt->td_head) & ~0xf ) - ->prev_td_phys; - } - - /* Prepare pointer to last processed TD and get error code */ - tderr_virt = grub_ohci_td_phys2virt (o, tderr_phys); - /* Set index of last processed TD */ - if (tderr_virt) - { - errcode = grub_le_to_cpu32 ( tderr_virt->token ) >> 28; - transfer->last_trans = tderr_virt->tr_index; - } - else - transfer->last_trans = -1; - - /* Evaluation of error code */ - grub_dprintf ("ohci", "OHCI tderr_phys=0x%02x, errcode=0x%02x\n", - tderr_phys, errcode); - switch (errcode) - { - case 0: - /* XXX: Should not happen! */ - grub_error (GRUB_ERR_IO, "OHCI failed without reporting the reason"); - err = GRUB_USB_ERR_INTERNAL; - break; - - case 1: - /* XXX: CRC error. */ - err = GRUB_USB_ERR_TIMEOUT; - break; - - case 2: - err = GRUB_USB_ERR_BITSTUFF; - break; - - case 3: - /* XXX: Data Toggle error. */ - err = GRUB_USB_ERR_DATA; - break; - - case 4: - err = GRUB_USB_ERR_STALL; - break; - - case 5: - /* XXX: Not responding. */ - err = GRUB_USB_ERR_TIMEOUT; - break; - - case 6: - /* XXX: PID Check bits failed. */ - err = GRUB_USB_ERR_BABBLE; - break; - - case 7: - /* XXX: PID unexpected failed. */ - err = GRUB_USB_ERR_BABBLE; - break; - - case 8: - /* XXX: Data overrun error. */ - err = GRUB_USB_ERR_DATA; - grub_dprintf ("ohci", "Overrun, failed TD address: %p, index: %d\n", - tderr_virt, tderr_virt->tr_index); - break; - - case 9: - /* XXX: Data underrun error. */ - grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n", - tderr_virt, tderr_virt->tr_index); - if (transfer->last_trans == -1) - break; - *actual = transfer->transactions[transfer->last_trans].size - - (grub_le_to_cpu32 (tderr_virt->buffer_end) - - grub_le_to_cpu32 (tderr_virt->buffer)) - + transfer->transactions[transfer->last_trans].preceding; - break; - - case 10: - /* XXX: Reserved. */ - err = GRUB_USB_ERR_NAK; - break; - - case 11: - /* XXX: Reserved. */ - err = GRUB_USB_ERR_NAK; - break; - - case 12: - /* XXX: Buffer overrun. */ - err = GRUB_USB_ERR_DATA; - break; - - case 13: - /* XXX: Buffer underrun. */ - err = GRUB_USB_ERR_DATA; - break; - - default: - err = GRUB_USB_ERR_NAK; - break; - } - - } - - else if (err_unrec) - { - /* Don't try to get error code and last processed TD for proper - * toggle bit value - anything can be invalid */ - err = GRUB_USB_ERR_UNRECOVERABLE; - grub_dprintf("ohci", "Unrecoverable error!"); - - /* Do OHCI reset in case of unrecoverable error - maybe we will need - * do more - re-enumerate bus etc. (?) */ - - /* Suspend the OHCI by issuing a reset. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); /* XXX: Magic. */ - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - grub_millisleep (1); - grub_dprintf ("ohci", "Unrecoverable error - OHCI reset\n"); - - /* Misc. resets. */ - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, 0x7f); /* Clears everything */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, o->ed_ctrl_addr); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, o->ed_bulk_addr); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); - /* Read back of register should ensure it is really written */ - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - - /* Enable the OHCI. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, - (2 << 6) - | GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE - | GRUB_OHCI_REG_CONTROL_BULK_ENABLE ); - } - - else if (err_timeout) - { - /* In case of timeout do not detect error from TD */ - err = GRUB_ERR_TIMEOUT; - grub_dprintf("ohci", "Timeout !\n"); - - /* We should wait for next SOF to be sure that ED is unaccessed - * by OHCI */ - /* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2)); - /* Wait for new SOF */ - while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) == 0); - - /* Now we must find last processed TD if bad_OHCI == TRUE */ - if (o->bad_OHCI) - { /* Retired TD with error should be previous TD to ED->td_head */ - tderr_phys = grub_ohci_td_phys2virt (o, - grub_le_to_cpu32 ( ed_virt->td_head) & ~0xf) - ->prev_td_phys; - } - tderr_virt = grub_ohci_td_phys2virt (o, tderr_phys); - if (tderr_virt) - transfer->last_trans = tderr_virt->tr_index; - else - transfer->last_trans = -1; - } +static void +finish_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; /* Set empty ED - set HEAD = TAIL = last (not processed) TD */ - ed_virt->td_head = grub_cpu_to_le32 (grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf); + cdata->ed_virt->td_head = grub_cpu_to_le32 (grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xf); /* At this point always should be: * ED has skip bit set and halted or empty or after next SOF, * i.e. it is safe to free all TDs except last not processed * ED HEAD == TAIL == phys. addr. of td_current_virt */ - /* Reset DoneHead - sanity cleanup */ + /* Un-chainig of last TD */ + if (cdata->td_current_virt->prev_td_phys) + { + grub_ohci_td_t td_prev_virt + = grub_ohci_td_phys2virt (o, cdata->td_current_virt->prev_td_phys); + + if (cdata->td_current_virt == (grub_ohci_td_t) td_prev_virt->link_td) + td_prev_virt->link_td = 0; + + cdata->td_current_virt->prev_td_phys = 0; + } + + grub_dprintf ("ohci", "OHCI finished, freeing\n"); + grub_ohci_free_tds (o, cdata->td_head_virt); + grub_free (cdata); +} + +static grub_usb_err_t +parse_halt (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_uint8_t errcode = 0; + grub_usb_err_t err = GRUB_USB_ERR_NAK; + grub_ohci_td_t tderr_virt = NULL; + + *actual = 0; + + pre_finish_transfer (dev, transfer); + + /* First we must get proper tderr_phys value */ + /* Retired TD with error should be previous TD to ED->td_head */ + cdata->tderr_phys = grub_ohci_td_phys2virt (o, + grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf ) + ->prev_td_phys; + + /* Prepare pointer to last processed TD and get error code */ + tderr_virt = grub_ohci_td_phys2virt (o, cdata->tderr_phys); + /* Set index of last processed TD */ + if (tderr_virt) + { + errcode = grub_le_to_cpu32 (tderr_virt->token) >> 28; + transfer->last_trans = tderr_virt->tr_index; + } + else + transfer->last_trans = -1; + + /* Evaluation of error code */ + grub_dprintf ("ohci", "OHCI tderr_phys=0x%02x, errcode=0x%02x\n", + cdata->tderr_phys, errcode); + switch (errcode) + { + case 0: + /* XXX: Should not happen! */ + grub_error (GRUB_ERR_IO, "OHCI failed without reporting the reason"); + err = GRUB_USB_ERR_INTERNAL; + break; + + case 1: + /* XXX: CRC error. */ + err = GRUB_USB_ERR_TIMEOUT; + break; + + case 2: + err = GRUB_USB_ERR_BITSTUFF; + break; + + case 3: + /* XXX: Data Toggle error. */ + err = GRUB_USB_ERR_DATA; + break; + + case 4: + err = GRUB_USB_ERR_STALL; + break; + + case 5: + /* XXX: Not responding. */ + err = GRUB_USB_ERR_TIMEOUT; + break; + + case 6: + /* XXX: PID Check bits failed. */ + err = GRUB_USB_ERR_BABBLE; + break; + + case 7: + /* XXX: PID unexpected failed. */ + err = GRUB_USB_ERR_BABBLE; + break; + + case 8: + /* XXX: Data overrun error. */ + err = GRUB_USB_ERR_DATA; + grub_dprintf ("ohci", "Overrun, failed TD address: %p, index: %d\n", + tderr_virt, tderr_virt->tr_index); + break; + + case 9: + /* XXX: Data underrun error. */ + grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n", + tderr_virt, tderr_virt->tr_index); + if (transfer->last_trans == -1) + break; + *actual = transfer->transactions[transfer->last_trans].size + - (grub_le_to_cpu32 (tderr_virt->buffer_end) + - grub_le_to_cpu32 (tderr_virt->buffer)) + + transfer->transactions[transfer->last_trans].preceding; + err = GRUB_USB_ERR_NONE; + break; + + case 10: + /* XXX: Reserved. */ + err = GRUB_USB_ERR_NAK; + break; + + case 11: + /* XXX: Reserved. */ + err = GRUB_USB_ERR_NAK; + break; + + case 12: + /* XXX: Buffer overrun. */ + err = GRUB_USB_ERR_DATA; + break; + + case 13: + /* XXX: Buffer underrun. */ + err = GRUB_USB_ERR_DATA; + break; + + default: + err = GRUB_USB_ERR_NAK; + break; + } + + finish_transfer (dev, transfer); + + return err; +} + +static grub_usb_err_t +parse_success (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_ohci_td_t tderr_virt = NULL; + + pre_finish_transfer (dev, transfer); + + /* I hope we can do it as transfer (most probably) finished OK */ + cdata->tderr_phys = cdata->td_last_phys; + + /* Prepare pointer to last processed TD */ + tderr_virt = grub_ohci_td_phys2virt (o, cdata->tderr_phys); + + /* Set index of last processed TD */ + if (tderr_virt) + transfer->last_trans = tderr_virt->tr_index; + else + transfer->last_trans = -1; + *actual = transfer->size + 1; + + finish_transfer (dev, transfer); + + return GRUB_USB_ERR_NONE; +} + +static grub_usb_err_t +parse_unrec (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_ohci *o = dev->data; + + *actual = 0; + + pre_finish_transfer (dev, transfer); + + /* Don't try to get error code and last processed TD for proper + * toggle bit value - anything can be invalid */ + grub_dprintf("ohci", "Unrecoverable error!"); + + /* Do OHCI reset in case of unrecoverable error - maybe we will need + * do more - re-enumerate bus etc. (?) */ + + /* Suspend the OHCI by issuing a reset. */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); /* XXX: Magic. */ + /* Read back of register should ensure it is really written */ + grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); + grub_millisleep (1); + grub_dprintf ("ohci", "Unrecoverable error - OHCI reset\n"); + + /* Misc. resets. */ o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, 0x7f); /* Clears everything */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, o->ed_ctrl_addr); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, o->ed_bulk_addr); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); /* Read back of register should ensure it is really written */ grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - /* Un-chainig of last TD */ - if (td_current_virt->prev_td_phys) - { - grub_ohci_td_t td_prev_virt - = grub_ohci_td_phys2virt (o, td_current_virt->prev_td_phys); + /* Enable the OHCI. */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, + (2 << 6) + | GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE + | GRUB_OHCI_REG_CONTROL_BULK_ENABLE ); + finish_transfer (dev, transfer); - td_next_virt = (grub_ohci_td_t) td_prev_virt->link_td; - if (td_current_virt == td_next_virt) - td_prev_virt->link_td = 0; + return GRUB_USB_ERR_UNRECOVERABLE; +} + +static grub_usb_err_t +grub_ohci_check_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_uint32_t intstatus; + + /* Check transfer status */ + intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); + + if ((intstatus & 0x10) != 0) + /* Unrecoverable error - only reset can help...! */ + return parse_unrec (dev, transfer, actual); + + /* Detected a HALT. */ + if ((grub_le_to_cpu32 (cdata->ed_virt->td_head) & 1)) + return parse_halt (dev, transfer, actual); + + /* Finished ED detection */ + if ( (grub_le_to_cpu32 (cdata->ed_virt->td_head) & ~0xf) == + (grub_le_to_cpu32 (cdata->ed_virt->td_tail) & ~0xf) ) /* Empty ED */ + { + /* Check the HALT bit */ + /* It looks like nonsense - it was tested previously... + * but it can change because OHCI is working + * simultaneously via DMA... */ + if (grub_le_to_cpu32 (cdata->ed_virt->td_head) & 1) + return parse_halt (dev, transfer, actual); + else + return parse_success (dev, transfer, actual); } - grub_dprintf ("ohci", "OHCI finished, freeing, err=0x%02x, errcode=0x%02x\n", - err, errcode); - grub_ohci_free_tds (o, td_head_virt); + return GRUB_USB_ERR_WAIT; +} - return err; +static grub_usb_err_t +grub_ohci_cancel_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_ohci *o = dev->data; + struct grub_ohci_transfer_controller_data *cdata = transfer->controller_data; + grub_ohci_td_t tderr_virt = NULL; + + pre_finish_transfer (dev, transfer); + + grub_dprintf("ohci", "Timeout !\n"); + + /* We should wait for next SOF to be sure that ED is unaccessed + * by OHCI */ + /* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2)); + /* Wait for new SOF */ + while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) == 0); + + /* Possible retired TD with error should be previous TD to ED->td_head */ + cdata->tderr_phys + = grub_ohci_td_phys2virt (o, grub_le_to_cpu32 (cdata->ed_virt->td_head) + & ~0xf)->prev_td_phys; + + tderr_virt = grub_ohci_td_phys2virt (o,cdata-> tderr_phys); + + grub_dprintf ("ohci", "Cancel: tderr_phys=0x%x, tderr_virt=%p\n", + cdata->tderr_phys, tderr_virt); + + if (tderr_virt) + transfer->last_trans = tderr_virt->tr_index; + else + transfer->last_trans = -1; + + finish_transfer (dev, transfer); + + return GRUB_USB_ERR_NONE; } static grub_err_t @@ -1218,6 +1211,7 @@ grub_ohci_portstatus (grub_usb_controller_t dev, { struct grub_ohci *o = (struct grub_ohci *) dev->data; grub_uint64_t endtime; + int i; grub_dprintf ("ohci", "begin of portstatus=0x%02x\n", grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)); @@ -1238,31 +1232,47 @@ grub_ohci_portstatus (grub_usb_controller_t dev, return GRUB_ERR_NONE; } - /* Reset the port */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, - GRUB_OHCI_SET_PORT_RESET); - grub_millisleep (50); /* For root hub should be nominaly 50ms */ - - /* End the reset signaling. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, - GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE); - grub_millisleep (10); + /* OHCI does one reset signal 10ms long but USB spec. + * requests 50ms for root hub (no need to be continuous). + * So, we do reset 5 times... */ + for (i = 0; i < 5; i++) + { + /* Reset the port - timing of reset is done by OHCI */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_SET_PORT_RESET); - /* Enable the port and wait for it. */ + /* Wait for reset completion */ + endtime = grub_get_time_ms () + 1000; + while (! (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port) + & GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE)) + if (grub_get_time_ms () > endtime) + return grub_error (GRUB_ERR_IO, "OHCI Timed out - reset"); + + /* End the reset signaling - reset the reset status change */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE); + grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port); + } + + /* Enable port */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, GRUB_OHCI_SET_PORT_ENABLE); + grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port); + + /* Wait for signal enabled */ endtime = grub_get_time_ms () + 1000; while (! (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port) & (1 << 1))) if (grub_get_time_ms () > endtime) return grub_error (GRUB_ERR_IO, "OHCI Timed out - enable"); - grub_millisleep (10); - /* Reset bit Connect Status Change */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, GRUB_OHCI_RESET_CONNECT_CHANGE); + /* "Reset recovery time" (USB spec.) */ + grub_millisleep (10); + grub_dprintf ("ohci", "end of portstatus=0x%02x\n", grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)); @@ -1279,8 +1289,16 @@ grub_ohci_detect_dev (grub_usb_controller_t dev, int port, int *changed) grub_dprintf ("ohci", "detect_dev status=0x%02x\n", status); - /* Connect Status Change bit - it detects change of connection */ - *changed = ((status & GRUB_OHCI_RESET_CONNECT_CHANGE) != 0); + /* Connect Status Change bit - it detects change of connection */ + if (status & GRUB_OHCI_RESET_CONNECT_CHANGE) + { + *changed = 1; + /* Reset bit Connect Status Change */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_RESET_CONNECT_CHANGE); + } + else + *changed = 0; if (! (status & 1)) return GRUB_USB_SPEED_NONE; @@ -1398,7 +1416,9 @@ static struct grub_usb_controller_dev usb_controller = { .name = "ohci", .iterate = grub_ohci_iterate, - .transfer = grub_ohci_transfer, + .setup_transfer = grub_ohci_setup_transfer, + .check_transfer = grub_ohci_check_transfer, + .cancel_transfer = grub_ohci_cancel_transfer, .hubports = grub_ohci_hubports, .portstatus = grub_ohci_portstatus, .detect_dev = grub_ohci_detect_dev diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c index 1fe86f5d4..711d87d86 100644 --- a/grub-core/bus/usb/uhci.c +++ b/grub-core/bus/usb/uhci.c @@ -28,6 +28,8 @@ #define GRUB_UHCI_IOMASK (0x7FF << 5) +#define N_QH 256 + typedef enum { GRUB_UHCI_REG_USBCMD = 0x00, @@ -39,6 +41,19 @@ typedef enum #define GRUB_UHCI_LINK_TERMINATE 1 #define GRUB_UHCI_LINK_QUEUE_HEAD 2 +enum + { + GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED = 0x0002, + GRUB_UHCI_REG_PORTSC_PORT_ENABLED = 0x0004, + GRUB_UHCI_REG_PORTSC_RESUME = 0x0040, + GRUB_UHCI_REG_PORTSC_RESET = 0x0200, + GRUB_UHCI_REG_PORTSC_SUSPEND = 0x1000, + GRUB_UHCI_REG_PORTSC_RW = GRUB_UHCI_REG_PORTSC_PORT_ENABLED + | GRUB_UHCI_REG_PORTSC_RESUME | GRUB_UHCI_REG_PORTSC_RESET + | GRUB_UHCI_REG_PORTSC_SUSPEND, + /* These bits should not be written as 1 unless we really need it */ + GRUB_UHCI_PORTSC_RWC = ((1 << 1) | (1 << 3) | (1 << 11) | (3 << 13)) + }; /* UHCI Queue Head. */ struct grub_uhci_qh @@ -87,7 +102,7 @@ struct grub_uhci int iobase; grub_uint32_t *framelist; - /* 256 Queue Heads. */ + /* N_QH Queue Heads. */ grub_uhci_qh_t qh; /* 256 Transfer Descriptors. */ @@ -96,6 +111,8 @@ struct grub_uhci /* Free Transfer Descriptors. */ grub_uhci_td_t tdfree; + int qh_busy[N_QH]; + struct grub_uhci *next; }; @@ -248,7 +265,7 @@ grub_uhci_pci_iter (grub_pci_device_t dev, (grub_uint32_t) (grub_addr_t) u->framelist); /* Make the Queue Heads point to each other. */ - for (i = 0; i < 256; i++) + for (i = 0; i < N_QH; i++) { /* Point to the next QH. */ u->qh[i].linkptr = (grub_uint32_t) (grub_addr_t) (&u->qh[i + 1]) & (~15); @@ -261,9 +278,8 @@ grub_uhci_pci_iter (grub_pci_device_t dev, u->qh[i].elinkptr = 1; } - /* The last Queue Head should terminate. 256 are too many QHs so - just use 50. */ - u->qh[50 - 1].linkptr = 1; + /* The last Queue Head should terminate. */ + u->qh[N_QH - 1].linkptr = 1; /* Enable UHCI again. */ grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 1 | (1 << 7)); @@ -332,11 +348,13 @@ grub_free_td (struct grub_uhci *u, grub_uhci_td_t td) } static void -grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td, +grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td, grub_usb_transfer_t transfer, grub_size_t *actual) { int i; /* Index of TD in transfer */ + u->qh_busy[qh - u->qh] = 0; + *actual = 0; /* Free the TDs in this queue and set last_trans. */ @@ -375,19 +393,21 @@ grub_alloc_qh (struct grub_uhci *u, #endif i = 1; - for (; i < 255; i++) + for (; i < N_QH; i++) { - if (u->qh[i].elinkptr & 1) + if (!u->qh_busy[i]) break; } qh = &u->qh[i]; - if (! (qh->elinkptr & 1)) + if (i == N_QH) { grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free queue heads available"); return NULL; } + u->qh_busy[qh - u->qh] = 1; + return qh; } @@ -395,7 +415,7 @@ static grub_uhci_td_t grub_uhci_transaction (struct grub_uhci *u, unsigned int endp, grub_transfer_type_t type, unsigned int addr, unsigned int toggle, grub_size_t size, - grub_uint32_t data) + grub_uint32_t data, grub_usb_speed_t speed) { grub_uhci_td_t td; static const unsigned int tf[] = { 0x69, 0xE1, 0x2D }; @@ -420,7 +440,8 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp, td->linkptr = 1; /* Active! Only retry a transfer 3 times. */ - td->ctrl_status = (1 << 23) | (3 << 27); + td->ctrl_status = (1 << 23) | (3 << 27) | + ((speed == GRUB_USB_SPEED_LOW) ? (1 << 26) : 0); /* If zero bytes are transmitted, size is 0x7FF. Otherwise size is size-1. */ @@ -438,26 +459,35 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp, return td; } +struct grub_uhci_transfer_controller_data +{ + grub_uhci_qh_t qh; + grub_uhci_td_t td_first; +}; + static grub_usb_err_t -grub_uhci_transfer (grub_usb_controller_t dev, - grub_usb_transfer_t transfer, - int timeout, grub_size_t *actual) +grub_uhci_setup_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) { struct grub_uhci *u = (struct grub_uhci *) dev->data; - grub_uhci_qh_t qh; grub_uhci_td_t td; - grub_uhci_td_t td_first = NULL; grub_uhci_td_t td_prev = NULL; - grub_usb_err_t err = GRUB_USB_ERR_NONE; int i; - grub_uint64_t endtime; + struct grub_uhci_transfer_controller_data *cdata; - *actual = 0; + cdata = grub_malloc (sizeof (*cdata)); + if (!cdata) + return GRUB_USB_ERR_INTERNAL; + + cdata->td_first = NULL; /* Allocate a queue head for the transfer queue. */ - qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL); - if (! qh) - return GRUB_USB_ERR_INTERNAL; + cdata->qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL); + if (! cdata->qh) + { + grub_free (cdata); + return GRUB_USB_ERR_INTERNAL; + } grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase); @@ -465,23 +495,26 @@ grub_uhci_transfer (grub_usb_controller_t dev, { grub_usb_transaction_t tr = &transfer->transactions[i]; - td = grub_uhci_transaction (u, transfer->endpoint, tr->pid, + td = grub_uhci_transaction (u, transfer->endpoint & 15, tr->pid, transfer->devaddr, tr->toggle, - tr->size, tr->data); + tr->size, tr->data, + transfer->dev->speed); if (! td) { + grub_size_t actual = 0; /* Terminate and free. */ td_prev->linkptr2 = 0; td_prev->linkptr = 1; - if (td_first) - grub_free_queue (u, td_first, NULL, actual); + if (cdata->td_first) + grub_free_queue (u, cdata->qh, cdata->td_first, NULL, &actual); + grub_free (cdata); return GRUB_USB_ERR_INTERNAL; } - if (! td_first) - td_first = td; + if (! cdata->td_first) + cdata->td_first = td; else { td_prev->linkptr2 = (grub_uint32_t) (grub_addr_t) td; @@ -497,81 +530,112 @@ grub_uhci_transfer (grub_usb_controller_t dev, /* Link it into the queue and terminate. Now the transaction can take place. */ - qh->elinkptr = (grub_uint32_t) (grub_addr_t) td_first; + cdata->qh->elinkptr = (grub_uint32_t) (grub_addr_t) cdata->td_first; grub_dprintf ("uhci", "initiate transaction\n"); - /* Wait until either the transaction completed or an error - occurred. */ - endtime = grub_get_time_ms () + timeout; - for (;;) + transfer->controller_data = cdata; + + return GRUB_USB_ERR_NONE; +} + +static grub_usb_err_t +grub_uhci_check_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual) +{ + struct grub_uhci *u = (struct grub_uhci *) dev->data; + grub_uhci_td_t errtd; + struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data; + + *actual = 0; + + errtd = (grub_uhci_td_t) (grub_addr_t) (cdata->qh->elinkptr & ~0x0f); + + grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n", + errtd->ctrl_status, errtd->buffer & (~15), errtd); + + /* Check if the transaction completed. */ + if (cdata->qh->elinkptr & 1) { - grub_uhci_td_t errtd; + grub_dprintf ("uhci", "transaction complete\n"); - errtd = (grub_uhci_td_t) (grub_addr_t) (qh->elinkptr & ~0x0f); + /* Place the QH back in the free list and deallocate the associated + TDs. */ + cdata->qh->elinkptr = 1; + grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual); + grub_free (cdata); + return GRUB_USB_ERR_NONE; + } - grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n", - errtd->ctrl_status, errtd->buffer & (~15), errtd); + grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status); - /* Check if the transaction completed. */ - if (qh->elinkptr & 1) - break; - - grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status); + if (!(errtd->ctrl_status & (1 << 23))) + { + grub_usb_err_t err = GRUB_USB_ERR_NONE; /* Check if the endpoint is stalled. */ if (errtd->ctrl_status & (1 << 22)) err = GRUB_USB_ERR_STALL; - + /* Check if an error related to the data buffer occurred. */ - if (errtd->ctrl_status & (1 << 21)) + else if (errtd->ctrl_status & (1 << 21)) err = GRUB_USB_ERR_DATA; - + /* Check if a babble error occurred. */ - if (errtd->ctrl_status & (1 << 20)) + else if (errtd->ctrl_status & (1 << 20)) err = GRUB_USB_ERR_BABBLE; - + /* Check if a NAK occurred. */ - if (errtd->ctrl_status & (1 << 19)) + else if (errtd->ctrl_status & (1 << 19)) err = GRUB_USB_ERR_NAK; - + /* Check if a timeout occurred. */ - if (errtd->ctrl_status & (1 << 18)) + else if (errtd->ctrl_status & (1 << 18)) err = GRUB_USB_ERR_TIMEOUT; - + /* Check if a bitstuff error occurred. */ - if (errtd->ctrl_status & (1 << 17)) + else if (errtd->ctrl_status & (1 << 17)) err = GRUB_USB_ERR_BITSTUFF; - + if (err) - goto fail; - - /* Fall through, no errors occurred, so the QH might be - updated. */ - grub_dprintf ("uhci", "transaction fallthrough\n"); - - if (grub_get_time_ms () > endtime) { - err = GRUB_USB_ERR_STALL; - grub_dprintf ("uhci", "transaction timed out\n"); - goto fail; + grub_dprintf ("uhci", "transaction failed\n"); + + /* Place the QH back in the free list and deallocate the associated + TDs. */ + cdata->qh->elinkptr = 1; + grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual); + grub_free (cdata); + + return err; } - grub_cpu_idle (); } - grub_dprintf ("uhci", "transaction complete\n"); + /* Fall through, no errors occurred, so the QH might be + updated. */ + grub_dprintf ("uhci", "transaction fallthrough\n"); - fail: + return GRUB_USB_ERR_WAIT; +} - if (err != GRUB_USB_ERR_NONE) - grub_dprintf ("uhci", "transaction failed\n"); +static grub_usb_err_t +grub_uhci_cancel_transfer (grub_usb_controller_t dev, + grub_usb_transfer_t transfer) +{ + struct grub_uhci *u = (struct grub_uhci *) dev->data; + grub_size_t actual; + struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data; + + grub_dprintf ("uhci", "transaction cancel\n"); /* Place the QH back in the free list and deallocate the associated TDs. */ - qh->elinkptr = 1; - grub_free_queue (u, td_first, transfer, actual); + cdata->qh->elinkptr = 1; + grub_free_queue (u, cdata->qh, cdata->td_first, transfer, &actual); + grub_free (cdata); - return err; + return GRUB_USB_ERR_NONE; } static int @@ -622,7 +686,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev, endtime = grub_get_time_ms () + 1000; while ((grub_uhci_readreg16 (u, reg) & (1 << 2))) if (grub_get_time_ms () > endtime) - return grub_error (GRUB_ERR_IO, "UHCI Timed out"); + return grub_error (GRUB_ERR_IO, "UHCI Timed out - disable"); status = grub_uhci_readreg16 (u, reg); grub_dprintf ("uhci", ">3detect=0x%02x\n", status); @@ -630,28 +694,37 @@ grub_uhci_portstatus (grub_usb_controller_t dev, } /* Reset the port. */ - grub_uhci_writereg16 (u, reg, 1 << 9); + status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC; + grub_uhci_writereg16 (u, reg, status | (1 << 9)); + grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */ /* Wait for the reset to complete. XXX: How long exactly? */ grub_millisleep (50); /* For root hub should be nominaly 50ms */ - status = grub_uhci_readreg16 (u, reg); + status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC; grub_uhci_writereg16 (u, reg, status & ~(1 << 9)); - grub_dprintf ("uhci", "reset completed\n"); - grub_millisleep (10); + grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */ + + /* Note: some debug prints were removed because they affected reset/enable timing. */ + + grub_millisleep (1); /* Probably not needed at all or only few microsecs. */ + + /* Reset bits Connect & Enable Status Change */ + status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC; + grub_uhci_writereg16 (u, reg, status | (1 << 3) | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED); + grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */ /* Enable the port. */ - grub_uhci_writereg16 (u, reg, 1 << 2); - grub_millisleep (10); - - grub_dprintf ("uhci", "waiting for the port to be enabled\n"); + status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC; + grub_uhci_writereg16 (u, reg, status | (1 << 2)); + grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */ endtime = grub_get_time_ms () + 1000; while (! ((status = grub_uhci_readreg16 (u, reg)) & (1 << 2))) if (grub_get_time_ms () > endtime) - return grub_error (GRUB_ERR_IO, "UHCI Timed out"); + return grub_error (GRUB_ERR_IO, "UHCI Timed out - enable"); - /* Reset bit Connect Status Change */ - grub_uhci_writereg16 (u, reg, status | (1 << 1)); + /* Reset recovery time */ + grub_millisleep (10); /* Read final port status */ status = grub_uhci_readreg16 (u, reg); @@ -683,7 +756,15 @@ grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port); /* Connect Status Change bit - it detects change of connection */ - *changed = ((status & (1 << 1)) != 0); + if (status & (1 << 1)) + { + *changed = 1; + /* Reset bit Connect Status Change */ + grub_uhci_writereg16 (u, reg, (status & GRUB_UHCI_REG_PORTSC_RW) + | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED); + } + else + *changed = 0; if (! (status & 1)) return GRUB_USB_SPEED_NONE; @@ -705,7 +786,9 @@ static struct grub_usb_controller_dev usb_controller = { .name = "uhci", .iterate = grub_uhci_iterate, - .transfer = grub_uhci_transfer, + .setup_transfer = grub_uhci_setup_transfer, + .check_transfer = grub_uhci_check_transfer, + .cancel_transfer = grub_uhci_cancel_transfer, .hubports = grub_uhci_hubports, .portstatus = grub_uhci_portstatus, .detect_dev = grub_uhci_detect_dev diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c index 7f2c8d24b..2a5cc3be9 100644 --- a/grub-core/bus/usb/usbhub.c +++ b/grub-core/bus/usb/usbhub.c @@ -28,6 +28,8 @@ /* USB Supports 127 devices, with device 0 as special case. */ static struct grub_usb_device *grub_usb_devs[GRUB_USBHUB_MAX_DEVICES]; +static int rescan = 0; + struct grub_usb_hub { struct grub_usb_hub *next; @@ -110,9 +112,6 @@ grub_usb_add_hub (grub_usb_device_t dev) struct grub_usb_usb_hubdesc hubdesc; grub_err_t err; int i; - grub_uint64_t timeout; - grub_usb_device_t next_dev; - grub_usb_device_t *attached_devices; err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | GRUB_USB_REQTYPE_CLASS @@ -131,11 +130,9 @@ grub_usb_add_hub (grub_usb_device_t dev) grub_dprintf ("usb", "Hub set configuration\n"); grub_usb_set_configuration (dev, 1); - attached_devices = grub_zalloc (hubdesc.portcnt - * sizeof (attached_devices[0])); - if (!attached_devices) + dev->children = grub_zalloc (hubdesc.portcnt * sizeof (dev->children[0])); + if (!dev->children) return GRUB_USB_ERR_INTERNAL; - dev->children = attached_devices; dev->nports = hubdesc.portcnt; /* Power on all Hub ports. */ @@ -143,115 +140,36 @@ grub_usb_add_hub (grub_usb_device_t dev) { grub_dprintf ("usb", "Power on - port %d\n", i); /* Power on the port and wait for possible device connect */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_SET_FEATURE, - GRUB_USB_HUB_FEATURE_PORT_POWER, - i, 0, NULL); - /* Just ignore the device if some error happened */ - if (err) - continue; + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_SET_FEATURE, + GRUB_USB_HUB_FEATURE_PORT_POWER, + i, 0, NULL); } - /* Wait for port power-on */ - if (hubdesc.pwdgood >= 50) - grub_millisleep (hubdesc.pwdgood * 2); - else - grub_millisleep (100); - - /* Iterate over the Hub ports. */ - for (i = 1; i <= hubdesc.portcnt; i++) + + /* Rest will be done on next usb poll. */ + for (i = 0; i < dev->config[0].interf[0].descif->endpointcnt; + i++) { - grub_uint32_t status; + struct grub_usb_desc_endp *endp = NULL; + endp = &dev->config[0].interf[0].descendp[i]; - /* Get the port status. */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_GET_STATUS, - 0, i, sizeof (status), (char *) &status); - /* Just ignore the device if the Hub does not report the - status. */ - if (err) - continue; - grub_dprintf ("usb", "Hub port %d status: 0x%02x\n", i, status); - - /* If connected, reset and enable the port. */ - if (status & GRUB_USB_HUB_STATUS_CONNECTED) + if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp) + == GRUB_USB_EP_INTERRUPT) { - grub_usb_speed_t speed; - - /* Determine the device speed. */ - if (status & GRUB_USB_HUB_STATUS_LOWSPEED) - speed = GRUB_USB_SPEED_LOW; - else - { - if (status & GRUB_USB_HUB_STATUS_HIGHSPEED) - speed = GRUB_USB_SPEED_HIGH; - else - speed = GRUB_USB_SPEED_FULL; - } - - /* A device is actually connected to this port. - * Now do reset of port. */ - grub_dprintf ("usb", "Reset hub port - port %d\n", i); - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_SET_FEATURE, - GRUB_USB_HUB_FEATURE_PORT_RESET, - i, 0, 0); - /* If the Hub does not cooperate for this port, just skip - the port. */ - if (err) - continue; - - /* Wait for reset procedure done */ - timeout = grub_get_time_ms () + 1000; - do - { - /* Get the port status. */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_GET_STATUS, - 0, i, sizeof (status), (char *) &status); - } - while (!err && - !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) && - (grub_get_time_ms() < timeout) ); - if (err || !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) ) - continue; - - /* Wait a recovery time after reset, spec. says 10ms */ - grub_millisleep (10); - - /* Do reset of connection change bit */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_CLEAR_FEATURE, - GRUB_USB_HUB_FEATURE_C_CONNECTED, - i, 0, 0); - /* Just ignore the device if the Hub reports some error */ - if (err) - continue; - grub_dprintf ("usb", "Hub port - cleared connection change\n"); - - /* Add the device and assign a device address to it. */ - grub_dprintf ("usb", "Call hub_add_dev - port %d\n", i); - next_dev = grub_usb_hub_add_dev (&dev->controller, speed); - if (! next_dev) - continue; - - attached_devices[i - 1] = next_dev; - - /* If the device is a Hub, scan it for more devices. */ - if (next_dev->descdev.class == 0x09) - grub_usb_add_hub (next_dev); + dev->hub_endpoint = endp; + dev->hub_transfer + = grub_usb_bulk_read_background (dev, endp->endp_addr, + grub_min (endp->maxpacket, + sizeof (dev->statuschange)), + (char *) &dev->statuschange); + break; } } + rescan = 1; + return GRUB_ERR_NONE; } @@ -261,19 +179,45 @@ attach_root_port (struct grub_usb_hub *hub, int portno, { grub_usb_device_t dev; grub_err_t err; + int total, i; + grub_usb_speed_t current_speed = GRUB_USB_SPEED_NONE; + int changed=0; +#if 0 +/* Specification does not say about disabling of port when device + * connected. If disabling is really necessary for some devices, + * delete this #if 0 and related #endif */ /* Disable the port. XXX: Why? */ err = hub->controller->dev->portstatus (hub->controller, portno, 0); if (err) return; +#endif + /* Wait for completion of insertion and stable power (USB spec.) + * Should be at least 100ms, some devices requires more... + * There is also another thing - some devices have worse contacts + * and connected signal is unstable for some time - we should handle + * it - but prevent deadlock in case when device is too faulty... */ + for (total = i = 0; (i < 250) && (total < 2000); i++, total++) + { + grub_millisleep (1); + current_speed = hub->controller->dev->detect_dev + (hub->controller, portno, &changed); + if (current_speed == GRUB_USB_SPEED_NONE) + i = 0; + } + grub_dprintf ("usb", "total=%d\n", total); + if (total >= 2000) + return; /* Enable the port. */ err = hub->controller->dev->portstatus (hub->controller, portno, 1); if (err) return; + hub->controller->dev->pending_reset = grub_get_time_ms () + 5000; /* Enable the port and create a device. */ dev = grub_usb_hub_add_dev (hub->controller, speed); + hub->controller->dev->pending_reset = 0; if (! dev) return; @@ -320,11 +264,14 @@ grub_usb_root_hub (grub_usb_controller_t controller) for (i = 0; i < hub->nports; i++) { grub_usb_speed_t speed; - speed = controller->dev->detect_dev (hub->controller, i, - &changed); + if (!controller->dev->pending_reset) + { + speed = controller->dev->detect_dev (hub->controller, i, + &changed); - if (speed != GRUB_USB_SPEED_NONE) - attach_root_port (hub, i, speed); + if (speed != GRUB_USB_SPEED_NONE) + attach_root_port (hub, i, speed); + } } return GRUB_USB_ERR_NONE; @@ -341,6 +288,9 @@ detach_device (grub_usb_device_t dev) return; if (dev->descdev.class == GRUB_USB_CLASS_HUB) { + if (dev->hub_transfer) + grub_usb_cancel_transfer (dev->hub_transfer); + for (i = 0; i < dev->nports; i++) detach_device (dev->children[i]); grub_free (dev->children); @@ -361,14 +311,37 @@ poll_nonroot_hub (grub_usb_device_t dev) { grub_err_t err; unsigned i; - grub_uint64_t timeout; - grub_usb_device_t next_dev; - grub_usb_device_t *attached_devices = dev->children; - + grub_uint8_t changed; + grub_size_t actual; + int j, total; + + if (!dev->hub_transfer) + return; + + err = grub_usb_check_transfer (dev->hub_transfer, &actual); + + if (err == GRUB_USB_ERR_WAIT) + return; + + changed = dev->statuschange; + + dev->hub_transfer + = grub_usb_bulk_read_background (dev, dev->hub_endpoint->endp_addr, + grub_min (dev->hub_endpoint->maxpacket, + sizeof (dev->statuschange)), + (char *) &dev->statuschange); + + if (err || actual == 0 || changed == 0) + return; + /* Iterate over the Hub ports. */ for (i = 1; i <= dev->nports; i++) { grub_uint32_t status; + grub_uint32_t current_status = 0; + + if (!(changed & (1 << i))) + continue; /* Get the port status. */ err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN @@ -376,92 +349,140 @@ poll_nonroot_hub (grub_usb_device_t dev) | GRUB_USB_REQTYPE_TARGET_OTHER), GRUB_USB_REQ_GET_STATUS, 0, i, sizeof (status), (char *) &status); - /* Just ignore the device if the Hub does not report the - status. */ + + grub_printf ("dev = %p, i = %d, status = %08x\n", + dev, i, status); + if (err) continue; - if (status & GRUB_USB_HUB_STATUS_C_CONNECTED) + /* FIXME: properly handle these conditions. */ + if (status & GRUB_USB_HUB_STATUS_C_PORT_ENABLED) + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_ENABLED, i, 0, 0); + + if (status & GRUB_USB_HUB_STATUS_C_PORT_SUSPEND) + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_SUSPEND, i, 0, 0); + + if (status & GRUB_USB_HUB_STATUS_C_PORT_OVERCURRENT) + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_OVERCURRENT, i, 0, 0); + + if (!dev->controller.dev->pending_reset && + (status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED)) { - detach_device (attached_devices[i-1]); - attached_devices[i - 1] = NULL; - } + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED, i, 0, 0); + + detach_device (dev->children[i - 1]); + dev->children[i - 1] = NULL; - /* Connected and status of connection changed ? */ - if ((status & GRUB_USB_HUB_STATUS_CONNECTED) - && (status & GRUB_USB_HUB_STATUS_C_CONNECTED)) - { - grub_usb_speed_t speed; - - /* Determine the device speed. */ - if (status & GRUB_USB_HUB_STATUS_LOWSPEED) - speed = GRUB_USB_SPEED_LOW; - else + /* Connected and status of connection changed ? */ + if (status & GRUB_USB_HUB_STATUS_PORT_CONNECTED) { - if (status & GRUB_USB_HUB_STATUS_HIGHSPEED) - speed = GRUB_USB_SPEED_HIGH; - else - speed = GRUB_USB_SPEED_FULL; + /* A device is actually connected to this port. */ + /* Wait for completion of insertion and stable power (USB spec.) + * Should be at least 100ms, some devices requires more... + * There is also another thing - some devices have worse contacts + * and connected signal is unstable for some time - we should handle + * it - but prevent deadlock in case when device is too faulty... */ + for (total = j = 0; (j < 250) && (total < 2000); j++, total++) + { + grub_millisleep (1); + /* Get the port status. */ + err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_GET_STATUS, + 0, i, + sizeof (current_status), + (char *) ¤t_status); + if (err) + { + total = 2000; + break; + } + if (!(current_status & GRUB_USB_HUB_STATUS_PORT_CONNECTED)) + j = 0; + } + grub_dprintf ("usb", "(non-root) total=%d\n", total); + if (total >= 2000) + continue; + + /* Now do reset of port. */ + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_SET_FEATURE, + GRUB_USB_HUB_FEATURE_PORT_RESET, + i, 0, 0); + rescan = 1; + /* We cannot reset more than one device at the same time ! + * Resetting more devices together results in very bad + * situation: more than one device has default address 0 + * at the same time !!! + * Additionaly, we cannot perform another reset + * anywhere on the same OHCI controller until + * we will finish addressing of reseted device ! */ + dev->controller.dev->pending_reset = grub_get_time_ms () + 5000; + return; } + } - /* A device is actually connected to this port. - * Now do reset of port. */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_SET_FEATURE, - GRUB_USB_HUB_FEATURE_PORT_RESET, - i, 0, 0); - /* If the Hub does not cooperate for this port, just skip - the port. */ - if (err) - continue; + if (status & GRUB_USB_HUB_STATUS_C_PORT_RESET) + { + grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_OTHER), + GRUB_USB_REQ_CLEAR_FEATURE, + GRUB_USB_HUB_FEATURE_C_PORT_RESET, i, 0, 0); - /* Wait for reset procedure done */ - timeout = grub_get_time_ms () + 1000; - do - { - /* Get the port status. */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_GET_STATUS, - 0, i, sizeof (status), (char *) &status); - } - while (!err && - !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) && - (grub_get_time_ms() < timeout) ); - if (err || !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) ) - continue; + if (status & GRUB_USB_HUB_STATUS_PORT_CONNECTED) + { + grub_usb_speed_t speed; + grub_usb_device_t next_dev; - /* Wait a recovery time after reset, spec. says 10ms */ - grub_millisleep (10); + /* Determine the device speed. */ + if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED) + speed = GRUB_USB_SPEED_LOW; + else + { + if (status & GRUB_USB_HUB_STATUS_PORT_HIGHSPEED) + speed = GRUB_USB_SPEED_HIGH; + else + speed = GRUB_USB_SPEED_FULL; + } - /* Do reset of connection change bit */ - err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_CLASS - | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_CLEAR_FEATURE, - GRUB_USB_HUB_FEATURE_C_CONNECTED, - i, 0, 0); - /* Just ignore the device if the Hub reports some error */ - if (err) - continue; + /* Wait a recovery time after reset, spec. says 10ms */ + grub_millisleep (10); - /* Add the device and assign a device address to it. */ - next_dev = grub_usb_hub_add_dev (&dev->controller, speed); - if (! next_dev) - continue; + /* Add the device and assign a device address to it. */ + next_dev = grub_usb_hub_add_dev (&dev->controller, speed); + dev->controller.dev->pending_reset = 0; + if (! next_dev) + continue; - attached_devices[i - 1] = next_dev; + dev->children[i - 1] = next_dev; - /* If the device is a Hub, scan it for more devices. */ - if (next_dev->descdev.class == 0x09) - grub_usb_add_hub (next_dev); + /* If the device is a Hub, scan it for more devices. */ + if (next_dev->descdev.class == 0x09) + grub_usb_add_hub (next_dev); + } } } - - return; } void @@ -476,12 +497,21 @@ grub_usb_poll_devices (void) /* No, it should be never changed, it should be constant. */ for (i = 0; i < hub->nports; i++) { - grub_usb_speed_t speed; + grub_usb_speed_t speed = GRUB_USB_SPEED_NONE; int changed = 0; - speed = hub->controller->dev->detect_dev (hub->controller, i, - &changed); - + if (!hub->controller->dev->pending_reset) + { + /* Check for possible timeout */ + if (grub_get_time_ms () > hub->controller->dev->pending_reset) + { + /* Something went wrong, reset device was not + * addressed properly, timeout happened */ + hub->controller->dev->pending_reset = 0; + speed = hub->controller->dev->detect_dev (hub->controller, + i, &changed); + } + } if (changed) { detach_device (hub->devices[i]); @@ -492,13 +522,21 @@ grub_usb_poll_devices (void) } } - /* We should check changes of non-root hubs too. */ - for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++) + while (1) { - grub_usb_device_t dev = grub_usb_devs[i]; - - if (dev && dev->descdev.class == 0x09) - poll_nonroot_hub (dev); + rescan = 0; + + /* We should check changes of non-root hubs too. */ + for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++) + { + grub_usb_device_t dev = grub_usb_devs[i]; + + if (dev && dev->descdev.class == 0x09) + poll_nonroot_hub (dev); + } + if (!rescan) + break; + grub_millisleep (50); } } diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c index 13f5c28ed..afd2eb0a5 100644 --- a/grub-core/bus/usb/usbtrans.c +++ b/grub-core/bus/usb/usbtrans.c @@ -23,6 +23,41 @@ #include #include #include +#include + +static grub_usb_err_t +grub_usb_execute_and_wait_transfer (grub_usb_device_t dev, + grub_usb_transfer_t transfer, + int timeout, grub_size_t *actual) +{ + grub_usb_err_t err; + grub_uint64_t endtime; + + err = dev->controller.dev->setup_transfer (&dev->controller, transfer); + if (err) + return err; + /* endtime moved behind setup transfer to prevent false timeouts + * while debugging... */ + endtime = grub_get_time_ms () + timeout; + while (1) + { + err = dev->controller.dev->check_transfer (&dev->controller, transfer, + actual); + if (!err) + return GRUB_USB_ERR_NONE; + if (err != GRUB_USB_ERR_WAIT) + return err; + if (grub_get_time_ms () > endtime) + { + err = dev->controller.dev->cancel_transfer (&dev->controller, + transfer); + if (err) + return err; + return GRUB_USB_ERR_TIMEOUT; + } + grub_cpu_idle (); + } +} grub_usb_err_t grub_usb_control_msg (grub_usb_device_t dev, @@ -147,8 +182,8 @@ grub_usb_control_msg (grub_usb_device_t dev, transfer->transactions[datablocks + 1].toggle = 1; - err = dev->controller.dev->transfer (&dev->controller, transfer, - 1000, &actual); + err = grub_usb_execute_and_wait_transfer (dev, transfer, 1000, &actual); + grub_dprintf ("usb", "control: err=%d\n", err); grub_free (transfer->transactions); @@ -162,22 +197,20 @@ grub_usb_control_msg (grub_usb_device_t dev, return err; } -static grub_usb_err_t -grub_usb_bulk_readwrite (grub_usb_device_t dev, - int endpoint, grub_size_t size0, char *data_in, - grub_transfer_type_t type, int timeout, - grub_size_t *actual) +static grub_usb_transfer_t +grub_usb_bulk_setup_readwrite (grub_usb_device_t dev, + int endpoint, grub_size_t size0, char *data_in, + grub_transfer_type_t type) { int i; grub_usb_transfer_t transfer; int datablocks; unsigned int max; - grub_usb_err_t err; - int toggle = dev->toggle[endpoint]; volatile char *data; grub_uint32_t data_addr; struct grub_pci_dma_chunk *data_chunk; grub_size_t size = size0; + int toggle = dev->toggle[endpoint]; grub_dprintf ("usb", "bulk: size=0x%02lx type=%d\n", (unsigned long) size, type); @@ -185,7 +218,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, /* FIXME: avoid allocation any kind of buffer in a first place. */ data_chunk = grub_memalign_dma32 (128, size); if (!data_chunk) - return GRUB_USB_ERR_INTERNAL; + return NULL; data = grub_dma_get_virt (data_chunk); data_addr = grub_dma_get_phys (data_chunk); if (type == GRUB_USB_TRANSFER_TYPE_OUT) @@ -210,18 +243,21 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, if (! transfer) { grub_dma_free (data_chunk); - return grub_errno; + return NULL; } datablocks = ((size + max - 1) / max); transfer->transcnt = datablocks; transfer->size = size - 1; - transfer->endpoint = endpoint & 15; + transfer->endpoint = endpoint; transfer->devaddr = dev->addr; transfer->type = GRUB_USB_TRANSACTION_TYPE_BULK; + transfer->dir = type; transfer->max = max; transfer->dev = dev; transfer->last_trans = -1; /* Reset index of last processed transaction (TD) */ + transfer->data_chunk = data_chunk; + transfer->data = data_in; /* Allocate an array of transfer data structures. */ transfer->transactions = grub_malloc (transfer->transcnt @@ -230,7 +266,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, { grub_free (transfer); grub_dma_free (data_chunk); - return grub_errno; + return NULL; } /* Set up all transfers. */ @@ -248,25 +284,51 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, tr->preceding = i * max; size -= tr->size; } + return transfer; +} + +static void +grub_usb_bulk_finish_readwrite (grub_usb_transfer_t transfer) +{ + grub_usb_device_t dev = transfer->dev; + int toggle = dev->toggle[transfer->endpoint]; - err = dev->controller.dev->transfer (&dev->controller, transfer, timeout, - actual); /* We must remember proper toggle value even if some transactions * were not processed - correct value should be inversion of last * processed transaction (TD). */ if (transfer->last_trans >= 0) toggle = transfer->transactions[transfer->last_trans].toggle ? 0 : 1; else - toggle = dev->toggle[endpoint]; /* Nothing done, take original */ - grub_dprintf ("usb", "bulk: err=%d, toggle=%d\n", err, toggle); - dev->toggle[endpoint] = toggle; + toggle = dev->toggle[transfer->endpoint]; /* Nothing done, take original */ + grub_dprintf ("usb", "bulk: toggle=%d\n", toggle); + dev->toggle[transfer->endpoint] = toggle; + + if (transfer->dir == GRUB_USB_TRANSFER_TYPE_IN) + grub_memcpy (transfer->data, (void *) + grub_dma_get_virt (transfer->data_chunk), + transfer->size + 1); grub_free (transfer->transactions); grub_free (transfer); - grub_dma_free (data_chunk); + grub_dma_free (transfer->data_chunk); +} - if (type == GRUB_USB_TRANSFER_TYPE_IN) - grub_memcpy (data_in, (char *) data, size0); +static grub_usb_err_t +grub_usb_bulk_readwrite (grub_usb_device_t dev, + int endpoint, grub_size_t size0, char *data_in, + grub_transfer_type_t type, int timeout, + grub_size_t *actual) +{ + grub_usb_err_t err; + grub_usb_transfer_t transfer; + + transfer = grub_usb_bulk_setup_readwrite (dev, endpoint, size0, + data_in, type); + if (!transfer) + return GRUB_USB_ERR_INTERNAL; + err = grub_usb_execute_and_wait_transfer (dev, transfer, timeout, actual); + + grub_usb_bulk_finish_readwrite (transfer); return err; } @@ -298,6 +360,49 @@ grub_usb_bulk_read (grub_usb_device_t dev, return err; } +grub_usb_err_t +grub_usb_check_transfer (grub_usb_transfer_t transfer, grub_size_t *actual) +{ + grub_usb_err_t err; + grub_usb_device_t dev = transfer->dev; + + err = dev->controller.dev->check_transfer (&dev->controller, transfer, + actual); + if (err == GRUB_USB_ERR_WAIT) + return err; + + grub_usb_bulk_finish_readwrite (transfer); + + return err; +} + +grub_usb_transfer_t +grub_usb_bulk_read_background (grub_usb_device_t dev, + int endpoint, grub_size_t size, void *data) +{ + grub_usb_err_t err; + grub_usb_transfer_t transfer; + + transfer = grub_usb_bulk_setup_readwrite (dev, endpoint, size, + data, GRUB_USB_TRANSFER_TYPE_IN); + if (!transfer) + return NULL; + + err = dev->controller.dev->setup_transfer (&dev->controller, transfer); + if (err) + return NULL; + + return transfer; +} + +void +grub_usb_cancel_transfer (grub_usb_transfer_t transfer) +{ + grub_usb_device_t dev = transfer->dev; + dev->controller.dev->cancel_transfer (&dev->controller, transfer); + grub_errno = GRUB_ERR_NONE; +} + grub_usb_err_t grub_usb_bulk_read_extended (grub_usb_device_t dev, int endpoint, grub_size_t size, char *data, diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c index 016e6fd9c..4f03997e0 100644 --- a/grub-core/commands/acpi.c +++ b/grub-core/commands/acpi.c @@ -23,10 +23,8 @@ #include #include #include -#include #include #include -#include #include #include @@ -152,10 +150,10 @@ grub_acpi_create_ebda (void) auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { grub_uint64_t end = start + size; - if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + if (type != GRUB_MEMORY_AVAILABLE) return 0; if (end > 0x100000) end = 0x100000; @@ -181,7 +179,7 @@ grub_acpi_create_ebda (void) "couldn't find space for the new EBDA"); mmapregion = grub_mmap_register (PTR_TO_UINT64 (targetebda), ebda_len, - GRUB_MACHINE_MEMORY_RESERVED); + GRUB_MEMORY_RESERVED); if (! mmapregion) return grub_errno; @@ -458,10 +456,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 +626,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 (); @@ -706,7 +703,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, playground = playground_ptr = grub_mmap_malign_and_register (1, playground_size, &mmapregion, - GRUB_MACHINE_MEMORY_ACPI, 0); + GRUB_MEMORY_ACPI, 0); if (! playground) { @@ -760,8 +757,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(acpi) { - cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, - GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("acpi", grub_cmd_acpi, 0, N_("[-1|-2] [--exclude=TABLE1,TABLE2|" "--load-only=table1,table2] FILE1" " [FILE2] [...]"), diff --git a/grub-core/commands/acpihalt.c b/grub-core/commands/acpihalt.c new file mode 100644 index 000000000..0cd32f389 --- /dev/null +++ b/grub-core/commands/acpihalt.c @@ -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 . + */ + +#include +#include +#include + +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 0x%x\n", *ptr); + grub_dprintf ("acpi", "Tell %x\n", (unsigned) (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 *) (grub_addr_t) 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 *) (grub_addr_t) *entry_ptr, "FACP", 4) == 0) + { + grub_uint32_t port; + struct grub_acpi_fadt *fadt + = ((struct grub_acpi_fadt *) (grub_addr_t) *entry_ptr); + struct grub_acpi_table_header *dsdt + = (struct grub_acpi_table_header *) (grub_addr_t) 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"); +} diff --git a/grub-core/commands/blocklist.c b/grub-core/commands/blocklist.c index cace31113..4651fb32a 100644 --- a/grub-core/commands/blocklist.c +++ b/grub-core/commands/blocklist.c @@ -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; diff --git a/grub-core/commands/cat.c b/grub-core/commands/cat.c index 77a4cc793..79ecf75c7 100644 --- a/grub-core/commands/cat.c +++ b/grub-core/commands/cat.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -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; @@ -77,7 +76,7 @@ grub_cmd_cat (grub_extcmd_t cmd, int argc, char **args) } while (grub_checkkey () >= 0 && - (key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != GRUB_TERM_ESC) + (key = grub_getkey ()) != GRUB_TERM_ESC) ; } @@ -92,7 +91,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(cat) { - cmd = grub_register_extcmd ("cat", grub_cmd_cat, GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("cat", grub_cmd_cat, 0, N_("FILE"), N_("Show the contents of a file."), options); } diff --git a/grub-core/commands/cmp.c b/grub-core/commands/cmp.c index 626e1d022..d9e76a4d7 100644 --- a/grub-core/commands/cmp.c +++ b/grub-core/commands/cmp.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -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; diff --git a/grub-core/commands/crc.c b/grub-core/commands/crc.c deleted file mode 100644 index 1c1a690aa..000000000 --- a/grub-core/commands/crc.c +++ /dev/null @@ -1,71 +0,0 @@ -/* crc.c - command to calculate the crc32 checksum of a file */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008,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 . - */ - -#include -#include -#include -#include -#include -#include -#include - -static grub_err_t -grub_cmd_crc (grub_command_t cmd __attribute__ ((unused)), - int argc, char **args) - -{ - grub_file_t file; - char buf[GRUB_DISK_SECTOR_SIZE]; - grub_ssize_t size; - grub_uint32_t crc; - - if (argc != 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); - - file = grub_file_open (args[0]); - if (! file) - return 0; - - crc = 0; - while ((size = grub_file_read (file, buf, sizeof (buf))) > 0) - crc = grub_getcrc32 (crc, buf, size); - - if (grub_errno) - goto fail; - - grub_printf ("%08x\n", crc); - - fail: - grub_file_close (file); - return 0; -} - -static grub_command_t cmd; - -GRUB_MOD_INIT(crc) -{ - cmd = grub_register_command ("crc", grub_cmd_crc, - N_("FILE"), - N_("Calculate the crc32 checksum of a file.")); -} - -GRUB_MOD_FINI(crc) -{ - grub_unregister_command (cmd); -} diff --git a/grub-core/commands/echo.c b/grub-core/commands/echo.c index 4fea091cb..13bc1c3fd 100644 --- a/grub-core/commands/echo.c +++ b/grub-core/commands/echo.c @@ -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; @@ -113,7 +113,9 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(echo) { - cmd = grub_register_extcmd ("echo", grub_cmd_echo, GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("echo", grub_cmd_echo, + GRUB_COMMAND_ACCEPT_DASH + | GRUB_COMMAND_OPTIONS_AT_START, N_("[-e|-n] STRING"), N_("Display a line of text."), options); } diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c index 16796febf..e9274fbab 100644 --- a/grub-core/commands/extcmd.c +++ b/grub-core/commands/extcmd.c @@ -21,46 +21,55 @@ #include #include #include +#include -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, + grub_command_flags_t 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, + grub_command_flags_t 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) { diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c index d5f551dbb..df297b585 100644 --- a/grub-core/commands/hashsum.c +++ b/grub-core/commands/hashsum.c @@ -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} }; @@ -40,6 +41,7 @@ struct { const char *name; const char *hashname; } aliases[] = {"sha256sum", "sha256"}, {"sha512sum", "sha512"}, {"md5sum", "md5"}, + {"crc", "crc32"}, }; static inline int @@ -80,7 +82,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 +117,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 +173,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 +206,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 +215,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) { @@ -238,30 +249,32 @@ grub_cmd_hashsum (struct grub_extcmd *cmd, return GRUB_ERR_NONE; } -static grub_extcmd_t cmd, cmd_md5, cmd_sha256, cmd_sha512; +static grub_extcmd_t cmd, cmd_md5, cmd_sha256, cmd_sha512 , cmd_crc; GRUB_MOD_INIT(hashsum) { - cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, - GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, 0, "hashsum -h HASH [-c FILE [-p PREFIX]] " "[FILE1 [FILE2 ...]]", "Compute or check hash checksum.", options); - cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, - GRUB_COMMAND_FLAG_BOTH, + cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, 0, N_("[-c FILE [-p PREFIX]] " "[FILE1 [FILE2 ...]]"), N_("Compute or check hash checksum."), options); - cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, - GRUB_COMMAND_FLAG_BOTH, + cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, 0, N_("[-c FILE [-p PREFIX]] " "[FILE1 [FILE2 ...]]"), "Compute or check hash checksum.", options); - cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, - GRUB_COMMAND_FLAG_BOTH, + cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, 0, + N_("[-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]"), + N_("Compute or check hash checksum."), + options); + + cmd_crc = grub_register_extcmd ("crc", grub_cmd_hashsum, 0, N_("[-c FILE [-p PREFIX]] " "[FILE1 [FILE2 ...]]"), N_("Compute or check hash checksum."), @@ -274,4 +287,5 @@ GRUB_MOD_FINI(hashsum) grub_unregister_extcmd (cmd_md5); grub_unregister_extcmd (cmd_sha256); grub_unregister_extcmd (cmd_sha512); + grub_unregister_extcmd (cmd_crc); } diff --git a/grub-core/commands/hdparm.c b/grub-core/commands/hdparm.c index a3f8bbff0..b6ab78755 100644 --- a/grub-core/commands/hdparm.c +++ b/grub-core/commands/hdparm.c @@ -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) @@ -409,8 +409,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(hdparm) { - cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, - GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("hdparm", grub_cmd_hdparm, 0, N_("[OPTIONS] DISK"), N_("Get/set ATA disk parameters."), options); } diff --git a/grub-core/commands/help.c b/grub-core/commands/help.c index e7d108c33..ff6d7ed2e 100644 --- a/grub-core/commands/help.c +++ b/grub-core/commands/help.c @@ -27,7 +27,7 @@ #include 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; @@ -38,8 +38,7 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, grub_command_t cmd; FOR_COMMANDS(cmd) { - if ((cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) && - (cmd->flags & GRUB_COMMAND_FLAG_CMDLINE)) + if ((cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE)) { struct grub_term_output *term; const char *summary_translated = _(cmd->summary); @@ -112,7 +111,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), @@ -130,8 +130,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(help) { - cmd = grub_register_extcmd ("help", grub_cmd_help, - GRUB_COMMAND_FLAG_CMDLINE, + cmd = grub_register_extcmd ("help", grub_cmd_help, 0, N_("[PATTERN ...]"), N_("Show a help message."), 0); } diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c index c1d4ecba9..629f2a069 100644 --- a/grub-core/commands/hexdump.c +++ b/grub-core/commands/hexdump.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -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; @@ -120,8 +119,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT (hexdump) { - cmd = grub_register_extcmd ("hexdump", grub_cmd_hexdump, - GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("hexdump", grub_cmd_hexdump, 0, N_("[OPTIONS] FILE_OR_DEVICE"), N_("Dump the contents of a file or memory."), options); diff --git a/grub-core/commands/i386/cmostest.c b/grub-core/commands/i386/cmostest.c index 36c35e6c4..994da11b0 100644 --- a/grub-core/commands/i386/cmostest.c +++ b/grub-core/commands/i386/cmostest.c @@ -22,20 +22,32 @@ #include static grub_err_t -grub_cmd_cmostest (struct grub_command *cmd __attribute__ ((unused)), - int argc, char *argv[]) +parse_args (int argc, char *argv[], int *byte, int *bit) { - int byte, bit; char *rest; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "Address required."); - byte = grub_strtoul (argv[0], &rest, 0); + *byte = grub_strtoul (argv[0], &rest, 0); if (*rest != ':') return grub_error (GRUB_ERR_BAD_ARGUMENT, "Address required."); - bit = grub_strtoul (rest + 1, 0, 0); + *bit = grub_strtoul (rest + 1, 0, 0); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_cmostest (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int byte, bit; + grub_err_t err; + + err = parse_args (argc, argv, &byte, &bit); + if (err) + return err; if (grub_cmos_read (byte) & (1 << bit)) return GRUB_ERR_NONE; @@ -43,7 +55,22 @@ grub_cmd_cmostest (struct grub_command *cmd __attribute__ ((unused)), return grub_error (GRUB_ERR_TEST_FAILURE, "false"); } -static grub_command_t cmd; +static grub_err_t +grub_cmd_cmosclean (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + int byte, bit; + grub_err_t err; + + err = parse_args (argc, argv, &byte, &bit); + if (err) + return err; + + grub_cmos_write (byte, grub_cmos_read (byte) & (~(1 << bit))); + return GRUB_ERR_NONE; +} + +static grub_command_t cmd, cmd_clean; GRUB_MOD_INIT(cmostest) @@ -51,9 +78,13 @@ GRUB_MOD_INIT(cmostest) cmd = grub_register_command ("cmostest", grub_cmd_cmostest, "cmostest BYTE:BIT", "Test bit at BYTE:BIT in CMOS."); + cmd_clean = grub_register_command ("cmosclean", grub_cmd_cmosclean, + "cmosclean BYTE:BIT", + "Clean bit at BYTE:BIT in CMOS."); } GRUB_MOD_FINI(cmostest) { grub_unregister_command (cmd); + grub_unregister_command (cmd_clean); } diff --git a/grub-core/commands/i386/cpuid.c b/grub-core/commands/i386/cpuid.c index 6eebf91a1..f5f0f15a8 100644 --- a/grub-core/commands/i386/cpuid.c +++ b/grub-core/commands/i386/cpuid.c @@ -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))) { @@ -88,7 +88,7 @@ GRUB_MOD_INIT(cpuid) done: #endif - cmd = grub_register_extcmd ("cpuid", grub_cmd_cpuid, GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("cpuid", grub_cmd_cpuid, 0, "[-l]", N_("Check for CPU features."), options); } diff --git a/grub-core/commands/i386/pc/drivemap.c b/grub-core/commands/i386/pc/drivemap.c index 4afc43358..ed4211cca 100644 --- a/grub-core/commands/i386/pc/drivemap.c +++ b/grub-core/commands/i386/pc/drivemap.c @@ -24,9 +24,10 @@ #include #include #include -#include #include #include +#include +#include /* Real mode IVT slot (seg:off far pointer) for interrupt 0x13. */ @@ -196,13 +197,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 +217,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 +249,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; } @@ -306,7 +307,7 @@ install_int13_handler (int noret __attribute__ ((unused))) grub_dprintf ("drivemap", "Payload is %u bytes long\n", total_size); handler_base = grub_mmap_malign_and_register (16, total_size, &drivemap_mmap, - GRUB_MACHINE_MEMORY_RESERVED, + GRUB_MEMORY_RESERVED, GRUB_MMAP_MALLOC_LOW); if (! handler_base) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't reserve " @@ -401,8 +402,7 @@ GRUB_MOD_INIT (drivemap) { grub_get_root_biosnumber_saved = grub_get_root_biosnumber; grub_get_root_biosnumber = grub_get_root_biosnumber_drivemap; - cmd = grub_register_extcmd ("drivemap", grub_cmd_drivemap, - GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("drivemap", grub_cmd_drivemap, 0, N_("-l | -r | [-s] grubdev osdisk."), N_("Manage the BIOS drive mappings."), options); diff --git a/grub-core/commands/i386/pc/halt.c b/grub-core/commands/i386/pc/halt.c index c237fe361..81eb6a1bb 100644 --- a/grub-core/commands/i386/pc/halt.c +++ b/grub-core/commands/i386/pc/halt.c @@ -22,6 +22,7 @@ #include #include #include +#include static const struct grub_arg_option options[] = { @@ -46,6 +47,8 @@ grub_halt (int no_apm) { struct grub_bios_int_registers regs; + grub_acpi_halt (); + if (no_apm) stop (); @@ -93,13 +96,14 @@ 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; + if (state[0].set) no_apm = 1; grub_halt (no_apm); @@ -110,8 +114,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(halt) { - cmd = grub_register_extcmd ("halt", grub_cmd_halt, GRUB_COMMAND_FLAG_BOTH, - "[-n]", + cmd = grub_register_extcmd ("halt", grub_cmd_halt, 0, "[-n]", N_("Halt the system, if possible using APM."), options); } diff --git a/grub-core/commands/i386/pc/lsapm.c b/grub-core/commands/i386/pc/lsapm.c new file mode 100644 index 000000000..30475d2ec --- /dev/null +++ b/grub-core/commands/i386/pc/lsapm.c @@ -0,0 +1,113 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include + +int +grub_apm_get_info (struct grub_apm_info *info) +{ + struct grub_bios_int_registers regs; + + /* detect APM */ + regs.eax = 0x5300; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + return 0; + info->version = regs.eax & 0xffff; + info->flags = regs.ecx & 0xffff; + + /* disconnect APM first */ + regs.eax = 0x5304; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + + /* connect APM */ + regs.eax = 0x5303; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + return 0; + + info->cseg = regs.eax & 0xffff; + info->offset = regs.ebx; + info->cseg_16 = regs.ecx & 0xffff; + info->dseg = regs.edx & 0xffff; + info->cseg_len = regs.esi >> 16; + info->cseg_16_len = regs.esi & 0xffff; + info->dseg_len = regs.edi; + + return 1; +} + +static grub_err_t +grub_cmd_lsapm (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) +{ + struct grub_apm_info info; + if (!grub_apm_get_info (&info)) + return grub_error (GRUB_ERR_IO, "no APM found"); + + grub_printf ("Vesion %u.%u\n" + "32-bit CS = 0x%x, len = 0x%x, offset = 0x%x\n" + "16-bit CS = 0x%x, len = 0x%x\n" + "DS = 0x%x, len = 0x%x\n", + info.version >> 8, info.version & 0xff, + info.cseg, info.cseg_len, info.offset, + info.cseg_16, info.cseg_16_len, + info.dseg, info.dseg_len); + grub_xputs (info.flags & GRUB_APM_FLAGS_16BITPROTECTED_SUPPORTED + ? "16-bit protected interface supported\n" + : "16-bit protected interface unsupported\n"); + grub_xputs (info.flags & GRUB_APM_FLAGS_32BITPROTECTED_SUPPORTED + ? "32-bit protected interface supported\n" + : "32-bit protected interface unsupported\n"); + grub_xputs (info.flags & GRUB_APM_FLAGS_CPUIDLE_SLOWS_DOWN + ? "CPU Idle slows down processor\n" + : "CPU Idle doesn't slow down processor\n"); + grub_xputs (info.flags & GRUB_APM_FLAGS_DISABLED + ? "APM disabled\n" : "APM enabled\n"); + grub_xputs (info.flags & GRUB_APM_FLAGS_DISENGAGED + ? "APM disengaged\n" : "APM engaged\n"); + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(lsapm) +{ + cmd = grub_register_command ("lsapm", grub_cmd_lsapm, 0, + N_("Show APM information.")); +} + +GRUB_MOD_FINI(lsapm) +{ + grub_unregister_command (cmd); +} + + diff --git a/grub-core/commands/i386/pc/sendkey.c b/grub-core/commands/i386/pc/sendkey.c index 6c5602dec..c777ea60a 100644 --- a/grub-core/commands/i386/pc/sendkey.c +++ b/grub-core/commands/i386/pc/sendkey.c @@ -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); @@ -366,8 +366,7 @@ static void *preboot_hook; GRUB_MOD_INIT (sendkey) { - cmd = grub_register_extcmd ("sendkey", grub_cmd_sendkey, - GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("sendkey", grub_cmd_sendkey, 0, "sendkey [KEYSTROKE1] [KEYSTROKE2] ...", "Emulate a keystroke", options); diff --git a/grub-core/commands/i386/pc/vbeinfo.c b/grub-core/commands/i386/pc/vbeinfo.c deleted file mode 100644 index c266bbfcb..000000000 --- a/grub-core/commands/i386/pc/vbeinfo.c +++ /dev/null @@ -1,185 +0,0 @@ -/* vbeinfo.c - command to list compatible VBE video modes. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007,2008,2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static void * -real2pm (grub_vbe_farptr_t ptr) -{ - return (void *) ((((unsigned long) ptr & 0xFFFF0000) >> 12UL) - + ((unsigned long) ptr & 0x0000FFFF)); -} - -static grub_err_t -grub_cmd_vbeinfo (grub_command_t cmd __attribute__ ((unused)), - int argc __attribute__ ((unused)), - char **args __attribute__ ((unused))) -{ - struct grub_vbe_info_block controller_info; - struct grub_vbe_mode_info_block mode_info_tmp; - grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE; - grub_uint16_t *video_mode_list; - grub_uint16_t *p; - grub_uint16_t *saved_video_mode_list; - grub_size_t video_mode_list_size; - grub_err_t err; - char *modevar; - - err = grub_vbe_probe (&controller_info); - if (err != GRUB_ERR_NONE) - return err; - - grub_printf ("VBE info: version: %d.%d OEM software rev: %d.%d\n", - controller_info.version >> 8, - controller_info.version & 0xFF, - controller_info.oem_software_rev >> 8, - controller_info.oem_software_rev & 0xFF); - - /* The total_memory field is in 64 KiB units. */ - grub_printf (" total memory: %d KiB\n", - (controller_info.total_memory << 16) / 1024); - - /* Because the information on video modes is stored in a temporary place, - it is better to copy it to somewhere safe. */ - p = video_mode_list = real2pm (controller_info.video_mode_ptr); - while (*p++ != 0xFFFF) - ; - - video_mode_list_size = (grub_addr_t) p - (grub_addr_t) video_mode_list; - saved_video_mode_list = grub_malloc (video_mode_list_size); - if (! saved_video_mode_list) - return grub_errno; - - grub_memcpy (saved_video_mode_list, video_mode_list, video_mode_list_size); - - grub_printf ("List of compatible video modes:\n"); - grub_printf ("Legend: P=Packed pixel, D=Direct color, " - "mask/pos=R/G/B/reserved\n"); - - /* Walk through all video modes listed. */ - for (p = saved_video_mode_list; *p != 0xFFFF; p++) - { - const char *memory_model = 0; - grub_uint32_t mode = (grub_uint32_t) *p; - - err = grub_vbe_get_video_mode_info (mode, &mode_info_tmp); - if (err != GRUB_ERR_NONE) - { - grub_errno = GRUB_ERR_NONE; - continue; - } - - if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_SUPPORTED) == 0) - /* If not available, skip it. */ - continue; - - if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_RESERVED_1) == 0) - /* Not enough information. */ - continue; - - if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_COLOR) == 0) - /* Monochrome is unusable. */ - continue; - - if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_LFB_AVAIL) == 0) - /* We support only linear frame buffer modes. */ - continue; - - if ((mode_info_tmp.mode_attributes & GRUB_VBE_MODEATTR_GRAPHICS) == 0) - /* We allow only graphical modes. */ - continue; - - switch (mode_info_tmp.memory_model) - { - case GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL: - memory_model = "Packed"; - break; - case GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR: - memory_model = "Direct"; - break; - - default: - break; - } - - if (! memory_model) - continue; - - grub_printf ("0x%03x: %4d x %4d x %2d %s", - mode, - mode_info_tmp.x_resolution, - mode_info_tmp.y_resolution, - mode_info_tmp.bits_per_pixel, - memory_model); - - /* Show mask and position details for direct color modes. */ - if (mode_info_tmp.memory_model == GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR) - grub_printf (", mask: %d/%d/%d/%d pos: %d/%d/%d/%d", - mode_info_tmp.red_mask_size, - mode_info_tmp.green_mask_size, - mode_info_tmp.blue_mask_size, - mode_info_tmp.rsvd_mask_size, - mode_info_tmp.red_field_position, - mode_info_tmp.green_field_position, - mode_info_tmp.blue_field_position, - mode_info_tmp.rsvd_field_position); - grub_printf ("\n"); - } - - grub_free (saved_video_mode_list); - - /* Check existence of vbe_mode environment variable. */ - modevar = grub_env_get ("vbe_mode"); - - if (modevar != 0) - { - unsigned long value; - - value = grub_strtoul (modevar, 0, 0); - if (grub_errno == GRUB_ERR_NONE) - use_mode = value; - else - grub_errno = GRUB_ERR_NONE; - } - - grub_printf ("Configured VBE mode (vbe_mode) = 0x%03x\n", use_mode); - - return 0; -} - -static grub_command_t cmd; - -GRUB_MOD_INIT(vbeinfo) -{ - cmd = - grub_register_command ("vbeinfo", grub_cmd_vbeinfo, 0, - N_("List compatible VESA BIOS extension video modes.")); -} - -GRUB_MOD_FINI(vbeinfo) -{ - grub_unregister_command (cmd); -} diff --git a/grub-core/commands/i386/pc/vbetest.c b/grub-core/commands/i386/pc/vbetest.c deleted file mode 100644 index d2921c09d..000000000 --- a/grub-core/commands/i386/pc/vbetest.c +++ /dev/null @@ -1,179 +0,0 @@ -/* vbetest.c - command to test VESA BIOS Extension 2.0+ support. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static grub_err_t -grub_cmd_vbetest (grub_command_t cmd __attribute__ ((unused)), - int argc __attribute__ ((unused)), - char **args __attribute__ ((unused))) -{ - grub_err_t err; - char *modevar; - struct grub_vbe_mode_info_block mode_info; - struct grub_vbe_info_block controller_info; - grub_uint32_t use_mode = GRUB_VBE_DEFAULT_VIDEO_MODE; - grub_uint32_t old_mode; - grub_uint8_t *framebuffer = 0; - grub_uint32_t bytes_per_scan_line = 0; - unsigned char *ptr; - int i; - - grub_printf ("Probing for VESA BIOS Extension ... "); - - /* Check if VESA BIOS exists. */ - err = grub_vbe_probe (&controller_info); - if (err != GRUB_ERR_NONE) - return err; - - grub_printf ("found!\n"); - - /* Dump out controller information. */ - grub_printf ("VBE signature = %c%c%c%c\n", - controller_info.signature[0], - controller_info.signature[1], - controller_info.signature[2], - controller_info.signature[3]); - - grub_printf ("VBE version = %d.%d\n", - controller_info.version >> 8, - controller_info.version & 0xFF); - grub_printf ("OEM string ptr = %08x\n", - controller_info.oem_string_ptr); - grub_printf ("Total memory = %d\n", - controller_info.total_memory); - - err = grub_vbe_get_video_mode (&old_mode); - grub_printf ("Get video mode err = %04x\n", err); - - if (err == GRUB_ERR_NONE) - grub_printf ("Old video mode = %04x\n", old_mode); - else - grub_errno = GRUB_ERR_NONE; - - /* Check existence of vbe_mode environment variable. */ - modevar = grub_env_get ("vbe_mode"); - if (modevar != 0) - { - unsigned long value; - - value = grub_strtoul (modevar, 0, 0); - if (grub_errno == GRUB_ERR_NONE) - use_mode = value; - else - grub_errno = GRUB_ERR_NONE; - } - - err = grub_vbe_get_video_mode_info (use_mode, &mode_info); - if (err != GRUB_ERR_NONE) - return err; - - /* Dump out details about the mode being tested. */ - grub_printf ("mode: 0x%03x\n", - use_mode); - grub_printf ("width : %d\n", - mode_info.x_resolution); - grub_printf ("height: %d\n", - mode_info.y_resolution); - grub_printf ("memory model: %02x\n", - mode_info.memory_model); - grub_printf ("bytes/scanline: %d\n", - mode_info.bytes_per_scan_line); - grub_printf ("bytes/scanline (lin): %d\n", - mode_info.lin_bytes_per_scan_line); - grub_printf ("base address: %08x\n", - mode_info.phys_base_addr); - grub_printf ("red mask/pos: %d/%d\n", - mode_info.red_mask_size, - mode_info.red_field_position); - grub_printf ("green mask/pos: %d/%d\n", - mode_info.green_mask_size, - mode_info.green_field_position); - grub_printf ("blue mask/pos: %d/%d\n", - mode_info.blue_mask_size, - mode_info.blue_field_position); - - grub_printf ("Press any key to continue.\n"); - - grub_getkey (); - - /* Setup GFX mode. */ - err = grub_vbe_set_video_mode (use_mode, &mode_info); - if (err != GRUB_ERR_NONE) - return err; - - /* Determine framebuffer address and how many bytes are in scan line. */ - framebuffer = (grub_uint8_t *) mode_info.phys_base_addr; - ptr = framebuffer; - - if (controller_info.version >= 0x300) - { - bytes_per_scan_line = mode_info.lin_bytes_per_scan_line; - } - else - { - bytes_per_scan_line = mode_info.bytes_per_scan_line; - } - - /* Draw some random data to screen. */ - for (i = 0; i < 256 * 256; i++) - { - ptr[i] = i & 0x0F; - } - - /* Draw white line to screen. */ - for (i = 0; i < 100; i++) - { - ptr[mode_info.bytes_per_scan_line * 50 + i] = 0x0F; - } - - /* Draw another white line to screen. */ - grub_memset (ptr + bytes_per_scan_line * 51, 0x0f, bytes_per_scan_line); - - grub_getkey (); - - grub_video_restore (); - - /* Restore old video mode. */ - grub_vbe_set_video_mode (old_mode, 0); - - return grub_errno; -} - -static grub_command_t cmd; - -GRUB_MOD_INIT(vbetest) -{ - cmd = grub_register_command ("vbetest", grub_cmd_vbetest, - 0, N_("Test VESA BIOS Extension 2.0+ support.")); -} - -GRUB_MOD_FINI(vbetest) -{ - grub_unregister_command (cmd); -} diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c index 474c8712e..20d203e92 100644 --- a/grub-core/commands/iorw.c +++ b/grub-core/commands/iorw.c @@ -36,17 +36,16 @@ 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; - char buf[sizeof ("XXXXXXXX")]; if (argc != 1) 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 +60,11 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) break; } - if (cmd->state[0].set) + if (ctxt->state[0].set) { + char buf[sizeof ("XXXXXXXX")]; 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); @@ -117,13 +117,13 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) GRUB_MOD_INIT(memrw) { cmd_read_byte = - grub_register_extcmd ("inb", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + grub_register_extcmd ("inb", grub_cmd_read, 0, N_("PORT"), N_("Read byte from PORT."), options); cmd_read_word = - grub_register_extcmd ("inw", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + grub_register_extcmd ("inw", grub_cmd_read, 0, N_("PORT"), N_("Read word from PORT."), options); cmd_read_dword = - grub_register_extcmd ("inl", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + grub_register_extcmd ("inl", grub_cmd_read, 0, N_("PORT"), N_("Read dword from PORT."), options); cmd_write_byte = grub_register_command ("outb", grub_cmd_write, diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c new file mode 100644 index 000000000..deb482a85 --- /dev/null +++ b/grub-core/commands/keylayouts.c @@ -0,0 +1,297 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct grub_keyboard_layout layout_us = { + .keyboard_map = { + /* Keyboard errors. Handled by driver. */ + /* 0x00 */ 0, 0, 0, 0, + + /* 0x04 */ 'a', 'b', 'c', 'd', + /* 0x08 */ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + /* 0x10 */ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + /* 0x18 */ 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', + /* 0x20 */ '3', '4', '5', '6', '7', '8', '9', '0', + /* 0x28 */ '\n', '\e', '\b', '\t', ' ', '-', '=', '[', + /* According to usage table 0x31 should be mapped to '/' + but testing with real keyboard shows that 0x32 is remapped to '/'. + Map 0x31 to 0. + */ + /* 0x30 */ ']', 0, '\\', ';', '\'', '`', ',', '.', + /* 0x39 is CapsLock. Handled by driver. */ + /* 0x38 */ '/', 0, GRUB_TERM_KEY_F1, GRUB_TERM_KEY_F2, + /* 0x3c */ GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, + /* 0x3e */ GRUB_TERM_KEY_F5, GRUB_TERM_KEY_F6, + /* 0x40 */ GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, + /* 0x42 */ GRUB_TERM_KEY_F9, GRUB_TERM_KEY_F10, + /* 0x44 */ GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12, + /* PrtScr and ScrollLock. Not handled yet. */ + /* 0x46 */ 0, 0, + /* 0x48 is Pause. Not handled yet. */ + /* 0x48 */ 0, GRUB_TERM_KEY_INSERT, + /* 0x4a */ GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_PPAGE, + /* 0x4c */ GRUB_TERM_KEY_DC, GRUB_TERM_KEY_END, + /* 0x4e */ GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_RIGHT, + /* 0x50 */ GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_DOWN, + /* 0x53 is NumLock. Handled by driver. */ + /* 0x52 */ GRUB_TERM_KEY_UP, 0, + /* 0x54 */ '/', '*', + /* 0x56 */ '-', '+', + /* 0x58 */ '\n', GRUB_TERM_KEY_END, + /* 0x5a */ GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_NPAGE, + /* 0x5c */ GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_CENTER, + /* 0x5e */ GRUB_TERM_KEY_RIGHT, GRUB_TERM_KEY_HOME, + /* 0x60 */ GRUB_TERM_KEY_UP, GRUB_TERM_KEY_PPAGE, + /* 0x62 */ GRUB_TERM_KEY_INSERT, GRUB_TERM_KEY_DC, + /* 0x64 */ '\\' + }, + .keyboard_map_shift = { + /* Keyboard errors. Handled by driver. */ + /* 0x00 */ 0, 0, 0, 0, + + /* 0x04 */ 'A', 'B', 'C', 'D', + /* 0x08 */ 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + /* 0x10 */ 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + /* 0x18 */ 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', + /* 0x20 */ '#', '$', '%', '^', '&', '*', '(', ')', + /* 0x28 */ '\n' | GRUB_TERM_SHIFT, '\e' | GRUB_TERM_SHIFT, + /* 0x2a */ '\b' | GRUB_TERM_SHIFT, '\t' | GRUB_TERM_SHIFT, + /* 0x2c */ ' ' | GRUB_TERM_SHIFT, '_', '+', '{', + /* According to usage table 0x31 should be mapped to '/' + but testing with real keyboard shows that 0x32 is remapped to '/'. + Map 0x31 to 0. + */ + /* 0x30 */ '}', 0, '|', ':', '"', '~', '<', '>', + /* 0x39 is CapsLock. Handled by driver. */ + /* 0x38 */ '?', 0, + /* 0x3a */ GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT, + /* 0x3b */ GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT, + /* 0x3c */ GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT, + /* 0x3d */ GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT, + /* 0x3e */ GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT, + /* 0x3f */ GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT, + /* 0x40 */ GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT, + /* 0x41 */ GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT, + /* 0x42 */ GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT, + /* 0x43 */ GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT, + /* 0x44 */ GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT, + /* 0x45 */ GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT, + /* PrtScr and ScrollLock. Not handled yet. */ + /* 0x46 */ 0, 0, + /* 0x48 is Pause. Not handled yet. */ + /* 0x48 */ 0, GRUB_TERM_KEY_INSERT | GRUB_TERM_SHIFT, + /* 0x4a */ GRUB_TERM_KEY_HOME | GRUB_TERM_SHIFT, + /* 0x4b */ GRUB_TERM_KEY_PPAGE | GRUB_TERM_SHIFT, + /* 0x4c */ GRUB_TERM_KEY_DC | GRUB_TERM_SHIFT, + /* 0x4d */ GRUB_TERM_KEY_END | GRUB_TERM_SHIFT, + /* 0x4e */ GRUB_TERM_KEY_NPAGE | GRUB_TERM_SHIFT, + /* 0x4f */ GRUB_TERM_KEY_RIGHT | GRUB_TERM_SHIFT, + /* 0x50 */ GRUB_TERM_KEY_LEFT | GRUB_TERM_SHIFT, + /* 0x51 */ GRUB_TERM_KEY_DOWN | GRUB_TERM_SHIFT, + /* 0x53 is NumLock. Handled by driver. */ + /* 0x52 */ GRUB_TERM_KEY_UP | GRUB_TERM_SHIFT, 0, + /* 0x54 */ '/', '*', + /* 0x56 */ '-', '+', + /* 0x58 */ '\n' | GRUB_TERM_SHIFT, '1', '2', '3', '4', '5','6', '7', + /* 0x60 */ '8', '9', '0', '.', '|' + } +}; + +static struct grub_keyboard_layout *grub_current_layout = &layout_us; + +static int +map_key_core (int code, int status, int *alt_gr_consumed) +{ + *alt_gr_consumed = 0; + + if (status & GRUB_TERM_STATUS_RALT) + { + if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) + { + if (grub_current_layout->keyboard_map_shift_l3[code]) + { + *alt_gr_consumed = 1; + return grub_current_layout->keyboard_map_shift_l3[code]; + } + } + else if (grub_current_layout->keyboard_map_l3[code]) + { + *alt_gr_consumed = 1; + return grub_current_layout->keyboard_map_l3[code]; + } + } + if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) + return grub_current_layout->keyboard_map_shift[code]; + else + return grub_current_layout->keyboard_map[code]; +} + +unsigned +grub_term_map_key (grub_keyboard_key_t code, int status) +{ + int alt_gr_consumed = 0; + int key; + + if (code >= 0x59 && code <= 0x63 && (status & GRUB_TERM_STATUS_NUM)) + { + if (status & (GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT)) + status &= ~(GRUB_TERM_STATUS_RSHIFT | GRUB_TERM_STATUS_LSHIFT); + else + status |= GRUB_TERM_STATUS_RSHIFT; + } + + key = map_key_core (code, status, &alt_gr_consumed); + + if (key == 0 || key == GRUB_TERM_SHIFT) + grub_printf ("Unknown key 0x%x detected\n", code); + + if (status & GRUB_TERM_STATUS_CAPS) + { + if ((key >= 'a') && (key <= 'z')) + key += 'A' - 'a'; + else if ((key >= 'A') && (key <= 'Z')) + key += 'a' - 'A'; + } + + if ((status & GRUB_TERM_STATUS_LALT) || + ((status & GRUB_TERM_STATUS_RALT) && !alt_gr_consumed)) + key |= GRUB_TERM_ALT; + if (status & (GRUB_TERM_STATUS_LCTRL | GRUB_TERM_STATUS_RCTRL)) + key |= GRUB_TERM_CTRL; + + return key; +} + +static grub_err_t +grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + char *filename; + grub_file_t file; + grub_uint32_t version; + grub_uint8_t magic[GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE]; + struct grub_keyboard_layout *newmap = NULL; + unsigned i; + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file or layout name required"); + if (argv[0][0] != '(' && argv[0][0] != '/' && argv[0][0] != '+') + { + const char *prefix = grub_env_get ("prefix"); + if (!prefix) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "No prefix set"); + filename = grub_xasprintf ("%s/layouts/%s.gkb", prefix, argv[0]); + if (!filename) + return grub_errno; + } + else + filename = argv[0]; + + file = grub_file_open (filename); + if (! file) + goto fail; + + if (grub_file_read (file, magic, sizeof (magic)) != sizeof (magic)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); + goto fail; + } + + if (grub_memcmp (magic, GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, + GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE) != 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid magic"); + goto fail; + } + + if (grub_file_read (file, &version, sizeof (version)) != sizeof (version)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); + goto fail; + } + + if (grub_le_to_cpu32 (version) != GRUB_KEYBOARD_LAYOUTS_VERSION) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid version"); + goto fail; + } + + newmap = grub_malloc (sizeof (*newmap)); + if (!newmap) + goto fail; + + if (grub_file_read (file, newmap, sizeof (*newmap)) != sizeof (*newmap)) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_ARGUMENT, "file is too short"); + goto fail; + } + + for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map); i++) + newmap->keyboard_map[i] = grub_le_to_cpu32(newmap->keyboard_map[i]); + + for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_shift); i++) + newmap->keyboard_map_shift[i] + = grub_le_to_cpu32(newmap->keyboard_map_shift[i]); + + for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_l3); i++) + newmap->keyboard_map_l3[i] + = grub_le_to_cpu32(newmap->keyboard_map_l3[i]); + + for (i = 0; i < ARRAY_SIZE (newmap->keyboard_map_shift_l3); i++) + newmap->keyboard_map_shift_l3[i] + = grub_le_to_cpu32(newmap->keyboard_map_shift_l3[i]); + + grub_current_layout = newmap; + + return GRUB_ERR_NONE; + + fail: + if (filename != argv[0]) + grub_free (filename); + grub_free (newmap); + if (file) + grub_file_close (file); + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(keylayouts) +{ + cmd = grub_register_command ("keymap", grub_cmd_keymap, + 0, N_("Load a keyboard layout.")); +} + +GRUB_MOD_FINI(keylayouts) +{ + grub_unregister_command (cmd); +} diff --git a/grub-core/commands/keystatus.c b/grub-core/commands/keystatus.c index 838792889..9e1486c9d 100644 --- a/grub-core/commands/keystatus.c +++ b/grub-core/commands/keystatus.c @@ -31,23 +31,39 @@ static const struct grub_arg_option options[] = {0, 0, 0, 0, 0, 0} }; -#define grub_cur_term_input grub_term_get_current_input () +static int +grub_getkeystatus (void) +{ + int status = 0; + grub_term_input_t term; + + if (grub_term_poll_usb) + grub_term_poll_usb (); + + FOR_ACTIVE_TERM_INPUTS(term) + { + if (term->getkeystatus) + status |= term->getkeystatus (term); + } + + return status; +} 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; if (state[0].set) - expect_mods |= GRUB_TERM_STATUS_SHIFT; + expect_mods |= (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT); if (state[1].set) - expect_mods |= GRUB_TERM_STATUS_CTRL; + expect_mods |= (GRUB_TERM_STATUS_LCTRL | GRUB_TERM_STATUS_RCTRL); if (state[2].set) - expect_mods |= GRUB_TERM_STATUS_ALT; + expect_mods |= (GRUB_TERM_STATUS_LALT | GRUB_TERM_STATUS_RALT); grub_dprintf ("keystatus", "expect_mods: %d\n", expect_mods); @@ -80,8 +96,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(keystatus) { - cmd = grub_register_extcmd ("keystatus", grub_cmd_keystatus, - GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("keystatus", grub_cmd_keystatus, 0, N_("[--shift] [--ctrl] [--alt]"), N_("Check key modifier status."), options); diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c new file mode 100644 index 000000000..463297810 --- /dev/null +++ b/grub-core/commands/legacycfg.c @@ -0,0 +1,781 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000, 2001, 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_err_t +legacy_file (const char *filename) +{ + grub_file_t file; + char *entryname = NULL, *entrysrc = NULL; + grub_menu_t menu; + char *suffix = grub_strdup (""); + + auto grub_err_t getline (char **line, int cont); + grub_err_t getline (char **line, + int cont __attribute__ ((unused))) + { + *line = 0; + return GRUB_ERR_NONE; + } + + if (!suffix) + return grub_errno; + + file = grub_file_open (filename); + if (! file) + return grub_errno; + + menu = grub_env_get_menu (); + if (! menu) + { + menu = grub_zalloc (sizeof (*menu)); + if (! menu) + return grub_errno; + + grub_env_set_menu (menu); + } + + while (1) + { + char *buf = grub_file_getline (file); + char *parsed = NULL; + + if (!buf && grub_errno) + { + grub_file_close (file); + return grub_errno; + } + + if (!buf) + break; + + { + char *oldname = NULL; + char *newsuffix; + + oldname = entryname; + parsed = grub_legacy_parse (buf, &entryname, &newsuffix); + buf = NULL; + if (newsuffix) + { + char *t; + + t = suffix; + suffix = grub_realloc (suffix, grub_strlen (suffix) + + grub_strlen (newsuffix) + 1); + if (!suffix) + { + grub_free (t); + grub_free (entrysrc); + grub_free (parsed); + grub_free (newsuffix); + grub_free (suffix); + return grub_errno; + } + grub_memcpy (suffix + grub_strlen (suffix), newsuffix, + grub_strlen (newsuffix) + 1); + grub_free (newsuffix); + newsuffix = NULL; + } + if (oldname != entryname && oldname) + { + const char **args = grub_malloc (sizeof (args[0])); + if (!args) + { + grub_file_close (file); + return grub_errno; + } + args[0] = oldname; + grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL, + entrysrc); + grub_free (args); + entrysrc[0] = 0; + grub_free (oldname); + } + } + + if (parsed && !entryname) + { + grub_normal_parse_line (parsed, getline); + grub_print_error (); + grub_free (parsed); + parsed = NULL; + } + else if (parsed) + { + if (!entrysrc) + entrysrc = parsed; + else + { + char *t; + + t = entrysrc; + entrysrc = grub_realloc (entrysrc, grub_strlen (entrysrc) + + grub_strlen (parsed) + 1); + if (!entrysrc) + { + grub_free (t); + grub_free (parsed); + grub_free (suffix); + return grub_errno; + } + grub_memcpy (entrysrc + grub_strlen (entrysrc), parsed, + grub_strlen (parsed) + 1); + grub_free (parsed); + parsed = NULL; + } + } + } + grub_file_close (file); + + if (entryname) + { + const char **args = grub_malloc (sizeof (args[0])); + if (!args) + { + grub_file_close (file); + return grub_errno; + } + args[0] = entryname; + grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL, entrysrc); + grub_free (args); + } + + grub_normal_parse_line (suffix, getline); + grub_print_error (); + grub_free (suffix); + grub_free (entrysrc); + + if (menu && menu->size) + grub_show_menu (menu, 1); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_legacy_source (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + return legacy_file (args[0]); +} + +static grub_err_t +grub_cmd_legacy_configfile (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_err_t ret; + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + grub_cls (); + grub_env_context_open (1); + + ret = legacy_file (args[0]); + grub_env_context_close (); + + return ret; +} + +static enum + { + GUESS_IT, LINUX, MULTIBOOT, KFREEBSD, KNETBSD, KOPENBSD + } kernel_type; + +static grub_err_t +grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + int i; + int no_mem_option = 0; + struct grub_command *cmd; + char **cutargs; + int cutargc; + + for (i = 0; i < 2; i++) + { + /* FIXME: really support this. */ + if (argc >= 1 && grub_strcmp (args[0], "--no-mem-option") == 0) + { + no_mem_option = 1; + argc--; + args++; + continue; + } + + /* linux16 handles both zImages and bzImages. */ + if (argc >= 1 && (grub_strcmp (args[0], "--type=linux") == 0 + || grub_strcmp (args[0], "--type=biglinux") == 0)) + { + kernel_type = LINUX; + argc--; + args++; + continue; + } + + if (argc >= 1 && grub_strcmp (args[0], "--type=multiboot") == 0) + { + kernel_type = MULTIBOOT; + argc--; + args++; + continue; + } + + if (argc >= 1 && grub_strcmp (args[0], "--type=freebsd") == 0) + { + kernel_type = KFREEBSD; + argc--; + args++; + continue; + } + + if (argc >= 1 && grub_strcmp (args[0], "--type=openbsd") == 0) + { + kernel_type = KOPENBSD; + argc--; + args++; + continue; + } + + if (argc >= 1 && grub_strcmp (args[0], "--type=netbsd") == 0) + { + kernel_type = KNETBSD; + argc--; + args++; + continue; + } + } + + if (argc < 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "filename required"); + + cutargs = grub_malloc (sizeof (cutargs[0]) * (argc - 1)); + cutargc = argc - 1; + grub_memcpy (cutargs + 1, args + 2, sizeof (cutargs[0]) * (argc - 2)); + cutargs[0] = args[0]; + + do + { + /* First try Linux. */ + if (kernel_type == GUESS_IT || kernel_type == LINUX) + { + cmd = grub_command_find ("linux16"); + if (cmd) + { + if (!(cmd->func) (cmd, cutargc, cutargs)) + { + kernel_type = LINUX; + return GRUB_ERR_NONE; + } + } + grub_errno = GRUB_ERR_NONE; + } + + /* Then multiboot. */ + if (kernel_type == GUESS_IT || kernel_type == MULTIBOOT) + { + cmd = grub_command_find ("multiboot"); + if (cmd) + { + if (!(cmd->func) (cmd, argc, args)) + { + kernel_type = MULTIBOOT; + return GRUB_ERR_NONE; + } + } + grub_errno = GRUB_ERR_NONE; + } + + { + int bsd_device = -1; + int bsd_slice = -1; + int bsd_part = -1; + { + grub_device_t dev; + char *hdbiasstr; + int hdbias = 0; + hdbiasstr = grub_env_get ("legacy_hdbias"); + if (hdbiasstr) + { + hdbias = grub_strtoul (hdbiasstr, 0, 0); + grub_errno = GRUB_ERR_NONE; + } + dev = grub_device_open (0); + if (dev && dev->disk + && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID + && dev->disk->dev->id >= 0x80 && dev->disk->dev->id <= 0x90) + { + struct grub_partition *part = dev->disk->partition; + bsd_device = dev->disk->id - 0x80 - hdbias; + if (part && (grub_strcmp (part->partmap->name, "netbsd") == 0 + || grub_strcmp (part->partmap->name, "openbsd") == 0 + || grub_strcmp (part->partmap->name, "bsd") == 0)) + { + bsd_part = part->number; + part = part->parent; + } + if (part && grub_strcmp (part->partmap->name, "msdos") == 0) + bsd_slice = part->number; + } + } + + /* k*BSD didn't really work well with grub-legacy. */ + if (kernel_type == GUESS_IT || kernel_type == KFREEBSD) + { + char buf[sizeof("adXXXXXXXXXXXXsXXXXXXXXXXXXYYY")]; + if (bsd_device != -1) + { + if (bsd_slice != -1 && bsd_part != -1) + grub_snprintf(buf, sizeof(buf), "ad%ds%d%c", bsd_device, + bsd_slice, 'a' + bsd_part); + else if (bsd_slice != -1) + grub_snprintf(buf, sizeof(buf), "ad%ds%d", bsd_device, + bsd_slice); + else + grub_snprintf(buf, sizeof(buf), "ad%d", bsd_device); + grub_env_set ("kFreeBSD.vfs.root.mountfrom", buf); + } + else + grub_env_unset ("kFreeBSD.vfs.root.mountfrom"); + cmd = grub_command_find ("kfreebsd"); + if (cmd) + { + if (!(cmd->func) (cmd, cutargc, cutargs)) + { + kernel_type = KFREEBSD; + return GRUB_ERR_NONE; + } + } + grub_errno = GRUB_ERR_NONE; + } + { + char **bsdargs; + int bsdargc; + char bsddevname[sizeof ("wdXXXXXXXXXXXXY")]; + if (bsd_device == -1) + { + bsdargs = cutargs; + bsdargc = cutargc; + } + else + { + bsdargc = cutargc + 2; + bsdargs = grub_malloc (sizeof (bsdargs[0]) * bsdargc); + grub_memcpy (bsdargs, args, argc * sizeof (bsdargs[0])); + bsdargs[argc] = "-r"; + bsdargs[argc + 1] = bsddevname; + grub_snprintf (bsddevname, sizeof (bsddevname), + "wd%d%c", bsd_device, + bsd_part != -1 ? bsd_part + 'a' : 'c'); + } + if (kernel_type == GUESS_IT || kernel_type == KNETBSD) + { + cmd = grub_command_find ("knetbsd"); + if (cmd) + { + if (!(cmd->func) (cmd, bsdargc, bsdargs)) + { + kernel_type = KNETBSD; + return GRUB_ERR_NONE; + } + } + grub_errno = GRUB_ERR_NONE; + } + if (kernel_type == GUESS_IT || kernel_type == KOPENBSD) + { + cmd = grub_command_find ("kopenbsd"); + if (cmd) + { + if (!(cmd->func) (cmd, bsdargc, bsdargs)) + { + kernel_type = KOPENBSD; + return GRUB_ERR_NONE; + } + } + grub_errno = GRUB_ERR_NONE; + } + if (bsdargs != cutargs) + grub_free (bsdargs); + } + } + } + while (0); + + return grub_error (GRUB_ERR_BAD_OS, "couldn't load file %s\n", + args[0]); +} + +static grub_err_t +grub_cmd_legacy_initrd (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_command *cmd; + + if (kernel_type == LINUX) + { + cmd = grub_command_find ("initrd16"); + if (!cmd) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "command initrd16 not found"); + + return cmd->func (cmd, argc, args); + } + if (kernel_type == MULTIBOOT) + { + cmd = grub_command_find ("module"); + if (!cmd) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "command module not found"); + + return cmd->func (cmd, argc, args); + } + + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "no kernel with module support is loaded in legacy way"); +} + +static grub_err_t +grub_cmd_legacy_initrdnounzip (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_command *cmd; + + if (kernel_type == LINUX) + { + cmd = grub_command_find ("initrd16"); + if (!cmd) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "command initrd16 not found"); + + return cmd->func (cmd, argc, args); + } + if (kernel_type == MULTIBOOT) + { + char **newargs; + grub_err_t err; + newargs = grub_malloc ((argc + 1) * sizeof (newargs[0])); + if (!newargs) + return grub_errno; + grub_memcpy (newargs + 1, args, argc * sizeof (newargs[0])); + newargs[0] = "--nounzip"; + cmd = grub_command_find ("module"); + if (!cmd) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "command module not found"); + + err = cmd->func (cmd, argc + 1, newargs); + grub_free (newargs); + return err; + } + + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "no kernel with module support is loaded in legacy way"); +} + +static grub_err_t +check_password_deny (const char *user __attribute__ ((unused)), + const char *entered __attribute__ ((unused)), + void *password __attribute__ ((unused))) +{ + return GRUB_ACCESS_DENIED; +} + +#define MD5_HASHLEN 16 + +struct legacy_md5_password +{ + grub_uint8_t *salt; + int saltlen; + grub_uint8_t hash[MD5_HASHLEN]; +}; + +static int +check_password_md5_real (const char *entered, + struct legacy_md5_password *pw) +{ + int enteredlen = grub_strlen (entered); + unsigned char alt_result[MD5_HASHLEN]; + unsigned char *digest; + grub_uint8_t ctx[GRUB_MD_MD5->contextsize]; + int i; + + GRUB_MD_MD5->init (ctx); + GRUB_MD_MD5->write (ctx, entered, enteredlen); + GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3); + GRUB_MD_MD5->write (ctx, entered, enteredlen); + digest = GRUB_MD_MD5->read (ctx); + GRUB_MD_MD5->final (ctx); + memcpy (alt_result, digest, MD5_HASHLEN); + + GRUB_MD_MD5->init (ctx); + GRUB_MD_MD5->write (ctx, entered, enteredlen); + GRUB_MD_MD5->write (ctx, pw->salt, pw->saltlen); /* include the $1$ header */ + for (i = enteredlen; i > 16; i -= 16) + GRUB_MD_MD5->write (ctx, alt_result, 16); + GRUB_MD_MD5->write (ctx, alt_result, i); + + for (i = enteredlen; i > 0; i >>= 1) + GRUB_MD_MD5->write (ctx, entered + ((i & 1) ? enteredlen : 0), 1); + digest = GRUB_MD_MD5->read (ctx); + GRUB_MD_MD5->final (ctx); + + for (i = 0; i < 1000; i++) + { + memcpy (alt_result, digest, 16); + + GRUB_MD_MD5->init (ctx); + if ((i & 1) != 0) + GRUB_MD_MD5->write (ctx, entered, enteredlen); + else + GRUB_MD_MD5->write (ctx, alt_result, 16); + + if (i % 3 != 0) + GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3); + + if (i % 7 != 0) + GRUB_MD_MD5->write (ctx, entered, enteredlen); + + if ((i & 1) != 0) + GRUB_MD_MD5->write (ctx, alt_result, 16); + else + GRUB_MD_MD5->write (ctx, entered, enteredlen); + digest = GRUB_MD_MD5->read (ctx); + GRUB_MD_MD5->final (ctx); + } + + return (grub_crypto_memcmp (digest, pw->hash, MD5_HASHLEN) == 0); +} + +static grub_err_t +check_password_md5 (const char *user, + const char *entered, + void *password) +{ + if (!check_password_md5_real (entered, password)) + return GRUB_ACCESS_DENIED; + + grub_auth_authenticate (user); + + return GRUB_ERR_NONE; +} + +static inline int +ib64t (char c) +{ + if (c == '.') + return 0; + if (c == '/') + return 1; + if (c >= '0' && c <= '9') + return c - '0' + 2; + if (c >= 'A' && c <= 'Z') + return c - 'A' + 12; + if (c >= 'a' && c <= 'z') + return c - 'a' + 38; + return -1; +} + +static struct legacy_md5_password * +parse_legacy_md5 (int argc, char **args) +{ + const char *salt, *saltend; + struct legacy_md5_password *pw = NULL; + int i; + const char *p; + + if (grub_memcmp (args[0], "--md5", sizeof ("--md5")) != 0) + goto fail; + if (argc == 1) + goto fail; + if (grub_strlen(args[1]) <= 3) + goto fail; + salt = args[1]; + saltend = grub_strchr (salt + 3, '$'); + if (!saltend) + goto fail; + pw = grub_malloc (sizeof (*pw)); + if (!pw) + goto fail; + + p = saltend + 1; + for (i = 0; i < 5; i++) + { + int n; + grub_uint32_t w = 0; + + for (n = 0; n < 4; n++) + { + int ww = ib64t(*p++); + if (ww == -1) + goto fail; + w |= ww << (n * 6); + } + pw->hash[i == 4 ? 5 : 12+i] = w & 0xff; + pw->hash[6+i] = (w >> 8) & 0xff; + pw->hash[i] = (w >> 16) & 0xff; + } + { + int n; + grub_uint32_t w = 0; + for (n = 0; n < 2; n++) + { + int ww = ib64t(*p++); + if (ww == -1) + goto fail; + w |= ww << (6 * n); + } + if (w >= 0x100) + goto fail; + pw->hash[11] = w; + } + + pw->saltlen = saltend - salt; + pw->salt = (grub_uint8_t *) grub_strndup (salt, pw->saltlen); + if (!pw->salt) + goto fail; + + return pw; + + fail: + grub_free (pw); + return NULL; +} + +static grub_err_t +grub_cmd_legacy_password (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + struct legacy_md5_password *pw = NULL; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments expected"); + if (args[0][0] != '-' || args[0][1] != '-') + return grub_normal_set_password ("legacy", args[0]); + + pw = parse_legacy_md5 (argc, args); + + if (pw) + return grub_auth_register_authentication ("legacy", check_password_md5, pw); + else + /* This is to imitate minor difference between grub-legacy in GRUB2. + If 2 password commands are executed in a row and second one fails + on GRUB2 the password of first one is used, whereas in grub-legacy + authenthication is denied. In case of no password command was executed + early both versions deny any access. */ + return grub_auth_register_authentication ("legacy", check_password_deny, + NULL); +} + +static grub_err_t +grub_cmd_legacy_check_password (struct grub_command *mycmd __attribute__ ((unused)), + int argc, char **args) +{ + struct legacy_md5_password *pw = NULL; + char entered[GRUB_AUTH_MAX_PASSLEN]; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments expected"); + grub_printf ("Enter password:"); + if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN)) + return GRUB_ACCESS_DENIED; + + if (args[0][0] != '-' || args[0][1] != '-') + { + char correct[GRUB_AUTH_MAX_PASSLEN]; + + grub_memset (correct, 0, sizeof (correct)); + grub_strncpy (correct, args[0], sizeof (correct)); + + if (grub_crypto_memcmp (entered, correct, GRUB_AUTH_MAX_PASSLEN) != 0) + return GRUB_ACCESS_DENIED; + return GRUB_ERR_NONE; + } + + pw = parse_legacy_md5 (argc, args); + + if (!pw) + return GRUB_ACCESS_DENIED; + + if (!check_password_md5_real (entered, pw)) + return GRUB_ACCESS_DENIED; + + return GRUB_ERR_NONE; +} + +static grub_command_t cmd_source, cmd_configfile, cmd_kernel, cmd_initrd; +static grub_command_t cmd_password, cmd_check_password, cmd_initrdnounzip; + +GRUB_MOD_INIT(legacycfg) +{ + cmd_source = grub_register_command ("legacy_source", + grub_cmd_legacy_source, + N_("FILE"), N_("Parse legacy config")); + cmd_configfile = grub_register_command ("legacy_configfile", + grub_cmd_legacy_configfile, + N_("FILE"), + N_("Parse legacy config")); + + cmd_kernel = grub_register_command ("legacy_kernel", + grub_cmd_legacy_kernel, + N_("[--no-mem-option] [--type=TYPE] FILE [ARG ...]"), + N_("Simulate grub-legacy kernel command")); + + cmd_initrd = grub_register_command ("legacy_initrd", + grub_cmd_legacy_initrd, + N_("FILE [ARG ...]"), + N_("Simulate grub-legacy initrd command")); + cmd_initrdnounzip = grub_register_command ("legacy_initrd_nounzip", + grub_cmd_legacy_initrdnounzip, + N_("FILE [ARG ...]"), + N_("Simulate grub-legacy modulenounzip command")); + + cmd_password = grub_register_command ("legacy_password", + grub_cmd_legacy_password, + N_("[--md5] PASSWD [FILE]"), + N_("Simulate grub-legacy password command")); + + cmd_check_password = grub_register_command ("legacy_check_password", + grub_cmd_legacy_check_password, + N_("[--md5] PASSWD [FILE]"), + N_("Simulate grub-legacy password command in menuentry mode")); + +} + +GRUB_MOD_FINI(legacycfg) +{ + grub_unregister_command (cmd_source); + grub_unregister_command (cmd_configfile); + grub_unregister_command (cmd_kernel); + grub_unregister_command (cmd_initrd); + grub_unregister_command (cmd_initrdnounzip); + grub_unregister_command (cmd_password); + grub_unregister_command (cmd_check_password); +} diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c index d763b2d5e..38b3a84c6 100644 --- a/grub-core/commands/loadenv.c +++ b/grub-core/commands/loadenv.c @@ -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; @@ -373,20 +375,15 @@ static grub_extcmd_t cmd_load, cmd_list, cmd_save; GRUB_MOD_INIT(loadenv) { cmd_load = - grub_register_extcmd ("load_env", grub_cmd_load_env, - GRUB_COMMAND_FLAG_BOTH, - N_("[-f FILE]"), + grub_register_extcmd ("load_env", grub_cmd_load_env, 0, N_("[-f FILE]"), N_("Load variables from environment block file."), options); cmd_list = - grub_register_extcmd ("list_env", grub_cmd_list_env, - GRUB_COMMAND_FLAG_BOTH, - N_("[-f FILE]"), + grub_register_extcmd ("list_env", grub_cmd_list_env, 0, N_("[-f FILE]"), N_("List variables from environment block file."), options); cmd_save = - grub_register_extcmd ("save_env", grub_cmd_save_env, - GRUB_COMMAND_FLAG_BOTH, + grub_register_extcmd ("save_env", grub_cmd_save_env, 0, N_("[-f FILE] variable_name [...]"), N_("Save variables to environment block file."), options); diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c index 9ee0a7a31..481d17db0 100644 --- a/grub-core/commands/ls.c +++ b/grub-core/commands/ls.c @@ -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,15 +250,17 @@ 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; + int i; if (argc == 0) grub_ls_list_devices (state[0].set); else - grub_ls_list_files (args[0], state[0].set, state[2].set, - state[1].set); + for (i = 0; i < argc; i++) + grub_ls_list_files (args[i], state[0].set, state[2].set, + state[1].set); return 0; } @@ -265,8 +269,8 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(ls) { - cmd = grub_register_extcmd ("ls", grub_cmd_ls, GRUB_COMMAND_FLAG_BOTH, - N_("[-l|-h|-a] [FILE]"), + cmd = grub_register_extcmd ("ls", grub_cmd_ls, 0, + N_("[-l|-h|-a] [FILE ...]"), N_("List devices and files."), options); } diff --git a/grub-core/commands/lsacpi.c b/grub-core/commands/lsacpi.c index d20b80fed..64b559665 100644 --- a/grub-core/commands/lsacpi.c +++ b/grub-core/commands/lsacpi.c @@ -196,10 +196,11 @@ static const struct grub_arg_option options[] = { }; static grub_err_t -grub_cmd_lsacpi (struct grub_extcmd *cmd, int argc __attribute__ ((unused)), +grub_cmd_lsacpi (struct grub_extcmd_context *ctxt, + int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - if (!cmd->state[1].set) + if (!ctxt->state[1].set) { struct grub_acpi_rsdp_v10 *rsdp1 = grub_acpi_get_rsdpv1 (); if (!rsdp1) @@ -212,7 +213,7 @@ grub_cmd_lsacpi (struct grub_extcmd *cmd, int argc __attribute__ ((unused)), } } - if (!cmd->state[0].set) + if (!ctxt->state[0].set) { struct grub_acpi_rsdp_v20 *rsdp2 = grub_acpi_get_rsdpv2 (); if (!rsdp2) @@ -237,8 +238,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(lsapi) { - cmd = grub_register_extcmd ("lsacpi", grub_cmd_lsacpi, GRUB_COMMAND_FLAG_BOTH, - N_("[-1|-2]"), + cmd = grub_register_extcmd ("lsacpi", grub_cmd_lsacpi, 0, N_("[-1|-2]"), N_("Show ACPI information."), options); } diff --git a/grub-core/commands/lsmmap.c b/grub-core/commands/lsmmap.c index 2755df9c4..657f81387 100644 --- a/grub-core/commands/lsmmap.c +++ b/grub-core/commands/lsmmap.c @@ -16,24 +16,39 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_MACHINE_EMU -#include -#endif #include #include #include #include +#include + +static const char *names[] = + { + [GRUB_MEMORY_AVAILABLE] = "available", + [GRUB_MEMORY_RESERVED] = "reserved", + [GRUB_MEMORY_ACPI] = "ACPI reclamaible", + [GRUB_MEMORY_NVS] = "NVS", + [GRUB_MEMORY_BADRAM] = "BadRAM", + [GRUB_MEMORY_CODE] = "firmware code", + [GRUB_MEMORY_HOLE] = "hole" + }; static grub_err_t grub_cmd_lsmmap (grub_command_t cmd __attribute__ ((unused)), - int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) { - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) { - grub_printf ("base_addr = 0x%llx, length = 0x%llx, type = 0x%x\n", - (long long) addr, (long long) size, type); + if (type < ARRAY_SIZE (names) && names[type]) + grub_printf ("base_addr = 0x%llx, length = 0x%llx, %s\n", + (long long) addr, (long long) size, names[type]); + else + grub_printf ("base_addr = 0x%llx, length = 0x%llx, type = 0x%x\n", + (long long) addr, (long long) size, type); return 0; } #ifndef GRUB_MACHINE_EMU diff --git a/grub-core/commands/lspci.c b/grub-core/commands/lspci.c index a69bb35ad..fd2d4eaf2 100644 --- a/grub-core/commands/lspci.c +++ b/grub-core/commands/lspci.c @@ -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; } @@ -224,8 +224,8 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(lspci) { - cmd = grub_register_extcmd ("lspci", grub_cmd_lspci, GRUB_COMMAND_FLAG_BOTH, - "[-i]", N_("List PCI devices."), options); + cmd = grub_register_extcmd ("lspci", grub_cmd_lspci, 0, "[-i]", + N_("List PCI devices."), options); } GRUB_MOD_FINI(lspci) diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c index 6a4d43be2..28aac7d81 100644 --- a/grub-core/commands/memrw.c +++ b/grub-core/commands/memrw.c @@ -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); @@ -119,13 +119,13 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) GRUB_MOD_INIT(memrw) { cmd_read_byte = - grub_register_extcmd ("read_byte", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + grub_register_extcmd ("read_byte", grub_cmd_read, 0, N_("ADDR"), N_("Read byte from ADDR."), options); cmd_read_word = - grub_register_extcmd ("read_word", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + grub_register_extcmd ("read_word", grub_cmd_read, 0, N_("ADDR"), N_("Read word from ADDR."), options); cmd_read_dword = - grub_register_extcmd ("read_dword", grub_cmd_read, GRUB_COMMAND_FLAG_BOTH, + grub_register_extcmd ("read_dword", grub_cmd_read, 0, N_("ADDR"), N_("Read dword from ADDR."), options); cmd_write_byte = grub_register_command ("write_byte", grub_cmd_write, diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c new file mode 100644 index 000000000..b19257c8e --- /dev/null +++ b/grub-core/commands/menuentry.c @@ -0,0 +1,299 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +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_KEY_DC}, + {"insert", GRUB_TERM_KEY_INSERT}, + {"f1", GRUB_TERM_KEY_F1}, + {"f2", GRUB_TERM_KEY_F2}, + {"f3", GRUB_TERM_KEY_F3}, + {"f4", GRUB_TERM_KEY_F4}, + {"f5", GRUB_TERM_KEY_F5}, + {"f6", GRUB_TERM_KEY_F6}, + {"f7", GRUB_TERM_KEY_F7}, + {"f8", GRUB_TERM_KEY_F8}, + {"f9", GRUB_TERM_KEY_F9}, + {"f10", GRUB_TERM_KEY_F10}, + {"f11", GRUB_TERM_KEY_F11}, + {"f12", GRUB_TERM_KEY_F12}, + }; + +/* Add a menu entry to the current menu context (as given by the environment + variable data slot `menu'). As the configuration file is read, the script + parser calls this when a menu entry is to be created. */ +grub_err_t +grub_normal_add_menu_entry (int argc, const char **args, char **classes, + const char *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; i < argc; i++) + { + menu_args[i] = grub_strdup (args[i]); + if (! menu_args[i]) + goto fail; + } + menu_args[argc] = NULL; + + /* Add the menu entry at the end of the list. */ + 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 grub_normal_add_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 = grub_normal_add_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_BLOCKS, + N_("BLOCK"), N_("Define a menuentry."), options); +} + +void +grub_menu_fini (void) +{ + grub_unregister_extcmd (cmd); +} diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c index d71174598..5cf109fde 100644 --- a/grub-core/commands/minicmd.c +++ b/grub-core/commands/minicmd.c @@ -108,146 +108,6 @@ grub_rescue_cmd_info (void) } #endif -/* root [DEVICE] */ -static grub_err_t -grub_mini_cmd_root (struct grub_command *cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_device_t dev; - grub_fs_t fs; - - if (argc > 0) - { - char *device_name = grub_file_get_device_name (argv[0]); - if (! device_name) - return grub_errno; - - grub_env_set ("root", device_name); - grub_free (device_name); - } - - dev = grub_device_open (0); - if (! dev) - return grub_errno; - - fs = grub_fs_probe (dev); - if (grub_errno == GRUB_ERR_UNKNOWN_FS) - grub_errno = GRUB_ERR_NONE; - - grub_printf ("(%s): Filesystem is %s.\n", - grub_env_get ("root"), fs ? fs->name : "unknown"); - - grub_device_close (dev); - - 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)), @@ -332,7 +192,7 @@ grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)), return 0; } -static grub_command_t cmd_cat, cmd_help, cmd_root; +static grub_command_t cmd_cat, cmd_help; static grub_command_t cmd_dump, cmd_rmmod, cmd_lsmod, cmd_exit; GRUB_MOD_INIT(minicmd) @@ -343,9 +203,6 @@ GRUB_MOD_INIT(minicmd) cmd_help = grub_register_command ("help", grub_mini_cmd_help, 0, N_("Show this message.")); - cmd_root = - grub_register_command ("root", grub_mini_cmd_root, - N_("[DEVICE]"), N_("Set the root device.")); cmd_dump = grub_register_command ("dump", grub_mini_cmd_dump, N_("ADDR"), N_("Dump memory.")); @@ -364,7 +221,6 @@ GRUB_MOD_FINI(minicmd) { grub_unregister_command (cmd_cat); grub_unregister_command (cmd_help); - grub_unregister_command (cmd_root); grub_unregister_command (cmd_dump); grub_unregister_command (cmd_rmmod); grub_unregister_command (cmd_lsmod); diff --git a/grub-core/commands/parttool.c b/grub-core/commands/parttool.c index f2a62e581..31e768553 100644 --- a/grub-core/commands/parttool.c +++ b/grub-core/commands/parttool.c @@ -275,7 +275,7 @@ grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), if (! parsed[j]) { for (curarg = ptool->args; curarg->name; curarg++) - if (grub_strncmp (curarg->name, args[i], + if (grub_strncmp (curarg->name, args[j], grub_strlen (curarg->name)) == 0 && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL && (args[j][grub_strlen (curarg->name)] == '+' diff --git a/grub-core/commands/password.c b/grub-core/commands/password.c index 04285254e..db5951cbb 100644 --- a/grub-core/commands/password.c +++ b/grub-core/commands/password.c @@ -40,26 +40,22 @@ check_password (const char *user, const char *entered, return GRUB_ERR_NONE; } -static grub_err_t -grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), - int argc, char **args) +grub_err_t +grub_normal_set_password (const char *user, const char *password) { grub_err_t err; char *pass; int copylen; - if (argc != 2) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments expected"); - pass = grub_zalloc (GRUB_AUTH_MAX_PASSLEN); if (!pass) return grub_errno; - copylen = grub_strlen (args[1]); + copylen = grub_strlen (password); if (copylen >= GRUB_AUTH_MAX_PASSLEN) copylen = GRUB_AUTH_MAX_PASSLEN - 1; - grub_memcpy (pass, args[1], copylen); + grub_memcpy (pass, password, copylen); - err = grub_auth_register_authentication (args[0], check_password, pass); + err = grub_auth_register_authentication (user, check_password, pass); if (err) { grub_free (pass); @@ -69,6 +65,15 @@ grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), return GRUB_ERR_NONE; } +static grub_err_t +grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "two arguments expected"); + return grub_normal_set_password (args[0], args[1]); +} + static grub_command_t cmd; GRUB_MOD_INIT(password) diff --git a/grub-core/commands/probe.c b/grub-core/commands/probe.c index c2cc599e9..abe84895d 100644 --- a/grub-core/commands/probe.c +++ b/grub-core/commands/probe.c @@ -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; @@ -150,8 +150,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT (probe) { - cmd = grub_register_extcmd ("probe", grub_cmd_probe, GRUB_COMMAND_FLAG_BOTH, - N_("[DEVICE]"), + cmd = grub_register_extcmd ("probe", grub_cmd_probe, 0, N_("[DEVICE]"), N_("Retrieve device info."), options); } diff --git a/grub-core/commands/regexp.c b/grub-core/commands/regexp.c index e8e8243b5..f27a147af 100644 --- a/grub-core/commands/regexp.c +++ b/grub-core/commands/regexp.c @@ -20,37 +20,104 @@ #include #include #include -#include +#include +#include +#include #include +#include #include +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 (®ex, args[0], RE_SYNTAX_GNU_AWK); + ret = regcomp (®ex, args[0], REG_EXTENDED); if (ret) goto fail; - ret = regexec (®ex, args[1], 0, 0, 0); + matches = grub_zalloc (sizeof (*matches) * (regex.re_nsub + 1)); + if (! matches) + goto fail; + + ret = regexec (®ex, 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 (®ex); - return GRUB_ERR_NONE; + grub_free (matches); + return err; } fail: + grub_free (matches); s = regerror (ret, ®ex, 0, 0); comperr = grub_malloc (s); if (!comperr) @@ -65,16 +132,19 @@ 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, 0, 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; } diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index 71267b117..f265f86d6 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -28,9 +28,12 @@ #include #include #include +#include +#include void -FUNC_NAME (const char *key, const char *var, int no_floppy) +FUNC_NAME (const char *key, const char *var, int no_floppy, + char **hints, unsigned nhints) { int count = 0; grub_fs_autoload_hook_t saved_autoload; @@ -54,6 +57,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) { @@ -113,22 +117,86 @@ FUNC_NAME (const char *key, const char *var, int no_floppy) return (found && var); } + auto int part_hook (grub_disk_t disk, const grub_partition_t partition); + int part_hook (grub_disk_t disk, const grub_partition_t partition) + { + char *partition_name, *devname; + int ret; + + partition_name = grub_partition_get_name (partition); + if (! partition_name) + return 1; + + devname = grub_xasprintf ("%s,%s", disk->name, partition_name); + grub_free (partition_name); + if (!devname) + return 1; + ret = iterate_device (devname); + grub_free (devname); + + return ret; + } + + auto void try (void); + void try (void) + { + unsigned i; + for (i = 0; i < nhints; i++) + { + char *end; + if (!hints[i][0]) + continue; + end = hints[i] + grub_strlen (hints[i]) - 1; + if (*end == ',') + *end = 0; + if (iterate_device (hints[i])) + { + if (!*end) + *end = ','; + return; + } + if (!*end) + { + grub_device_t dev; + int ret; + dev = grub_device_open (hints[i]); + if (!dev) + { + *end = ','; + continue; + } + if (!dev->disk) + { + grub_device_close (dev); + *end = ','; + continue; + } + ret = grub_partition_iterate (dev->disk, part_hook); + *end = ','; + grub_device_close (dev); + if (ret) + return; + } + } + grub_device_iterate (iterate_device); + } + /* First try without autoloading if we're setting variable. */ if (var) { saved_autoload = grub_fs_autoload_hook; grub_fs_autoload_hook = 0; - grub_device_iterate (iterate_device); + try (); /* Restore autoload hook. */ grub_fs_autoload_hook = saved_autoload; /* Retry with autoload if nothing found. */ if (grub_errno == GRUB_ERR_NONE && count == 0) - grub_device_iterate (iterate_device); + try (); } else - grub_device_iterate (iterate_device); + try (); if (grub_errno == GRUB_ERR_NONE && count == 0) grub_error (GRUB_ERR_FILE_NOT_FOUND, "no such device: %s", key); @@ -141,7 +209,8 @@ grub_cmd_do_search (grub_command_t cmd __attribute__ ((unused)), int argc, if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified"); - FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0); + FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0, (args + 2), + argc > 2 ? argc - 2 : 0); return grub_errno; } @@ -158,7 +227,7 @@ GRUB_MOD_INIT(search_label) { cmd = grub_register_command (COMMAND_NAME, grub_cmd_do_search, - N_("NAME [VARIABLE]"), + N_("NAME [VARIABLE] [HINTS]"), HELP_MESSAGE); } diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c index 2891d85d7..402421f65 100644 --- a/grub-core/commands/search_wrap.c +++ b/grub-core/commands/search_wrap.c @@ -37,6 +37,9 @@ static const struct grub_arg_option options[] = {"set", 's', GRUB_ARG_OPTION_OPTIONAL, N_("Set a variable to the first device found."), "VAR", ARG_TYPE_STRING}, {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0}, + {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -47,13 +50,19 @@ enum options SEARCH_FS_UUID, SEARCH_SET, SEARCH_NO_FLOPPY, + SEARCH_HINT }; 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; + int nhints = 0; + + if (state[SEARCH_HINT].set) + while (state[SEARCH_HINT].args[nhints]) + nhints++; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no argument specified"); @@ -62,11 +71,14 @@ grub_cmd_search (grub_extcmd_t cmd, int argc, char **args) var = state[SEARCH_SET].arg ? state[SEARCH_SET].arg : "root"; if (state[SEARCH_LABEL].set) - grub_search_label (args[0], var, state[SEARCH_NO_FLOPPY].set); + grub_search_label (args[0], var, state[SEARCH_NO_FLOPPY].set, + state[SEARCH_HINT].args, nhints); else if (state[SEARCH_FS_UUID].set) - grub_search_fs_uuid (args[0], var, state[SEARCH_NO_FLOPPY].set); + grub_search_fs_uuid (args[0], var, state[SEARCH_NO_FLOPPY].set, + state[SEARCH_HINT].args, nhints); else if (state[SEARCH_FILE].set) - grub_search_fs_file (args[0], var, state[SEARCH_NO_FLOPPY].set); + grub_search_fs_file (args[0], var, state[SEARCH_NO_FLOPPY].set, + state[SEARCH_HINT].args, nhints); else return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type"); @@ -78,9 +90,9 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(search) { cmd = - grub_register_extcmd ("search", grub_cmd_search, - GRUB_COMMAND_FLAG_BOTH, - N_("search [-f|-l|-u|-s|-n] NAME"), + grub_register_extcmd ("search", grub_cmd_search, 0, + N_("[-f|-l|-u|-s|-n] [--hint HINT [--hint HINT] ...]" + " NAME"), N_("Search devices by file, filesystem label" " or filesystem UUID." " If --set is specified, the first device found is" diff --git a/grub-core/commands/setpci.c b/grub-core/commands/setpci.c index aa09f5bbb..7b194ed17 100644 --- a/grub-core/commands/setpci.c +++ b/grub-core/commands/setpci.c @@ -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; @@ -329,7 +329,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(setpci) { - cmd = grub_register_extcmd ("setpci", grub_cmd_setpci, GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("setpci", grub_cmd_setpci, 0, N_("[-s POSITION] [-d DEVICE] [-v VAR] " "[REGISTER][=VALUE[:MASK]]"), N_("Manipulate PCI devices."), options); diff --git a/grub-core/commands/sleep.c b/grub-core/commands/sleep.c index ead279506..da642fcd9 100644 --- a/grub-core/commands/sleep.c +++ b/grub-core/commands/sleep.c @@ -52,17 +52,16 @@ grub_interruptible_millisleep (grub_uint32_t ms) start = grub_get_time_ms (); while (grub_get_time_ms () - start < ms) - if (grub_checkkey () >= 0 && - GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC) + if (grub_checkkey () >= 0 && grub_getkey () == GRUB_TERM_ESC) return 1; return 0; } 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) @@ -101,7 +100,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(sleep) { - cmd = grub_register_extcmd ("sleep", grub_cmd_sleep, GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("sleep", grub_cmd_sleep, 0, N_("NUMBER_OF_SECONDS"), N_("Wait for a specified number of seconds."), options); diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c index 6995165cf..97b7fe6e4 100644 --- a/grub-core/commands/test.c +++ b/grub-core/commands/test.c @@ -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) diff --git a/grub-core/commands/testload.c b/grub-core/commands/testload.c new file mode 100644 index 000000000..3b6ddfae3 --- /dev/null +++ b/grub-core/commands/testload.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/grub-core/commands/videoinfo.c b/grub-core/commands/videoinfo.c new file mode 100644 index 000000000..10f77915b --- /dev/null +++ b/grub-core/commands/videoinfo.c @@ -0,0 +1,184 @@ +/* videoinfo.c - command to list video modes. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2005,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +static unsigned height, width, depth; + +static int +hook (const struct grub_video_mode_info *info) +{ + if (height && width && (info->width != width || info->height != height)) + return 0; + + if (depth && info->bpp != depth) + return 0; + + if (info->mode_number == GRUB_VIDEO_MODE_NUMBER_INVALID) + grub_printf (" "); + else + grub_printf (" 0x%03x ", info->mode_number); + grub_printf ("%4d x %4d x %2d ", info->width, info->height, info->bpp); + + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT) + grub_printf ("Text-only "); + /* Show mask and position details for direct color modes. */ + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_RGB) + grub_printf ("Direct, mask: %d/%d/%d/%d pos: %d/%d/%d/%d", + info->red_mask_size, + info->green_mask_size, + info->blue_mask_size, + info->reserved_mask_size, + info->red_field_pos, + info->green_field_pos, + info->blue_field_pos, + info->reserved_field_pos); + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) + grub_printf ("Packed "); + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_YUV) + grub_printf ("YUV "); + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PLANAR) + grub_printf ("Planar "); + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_HERCULES) + grub_printf ("Hercules "); + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_CGA) + grub_printf ("CGA "); + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_NONCHAIN4) + grub_printf ("Non-chain 4 "); + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP) + grub_printf ("Monochrome "); + if (info->mode_type & GRUB_VIDEO_MODE_TYPE_UNKNOWN) + grub_printf ("Unknown "); + + grub_printf ("\n"); + + return 0; +} + +static grub_err_t +grub_cmd_videoinfo (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_video_adapter_t adapter; + grub_video_driver_id_t id; + + height = width = depth = 0; + if (argc) + { + char *ptr; + ptr = args[0]; + width = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + if (*ptr != 'x') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid mode specification"); + ptr++; + height = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + if (*ptr == 'x') + { + ptr++; + depth = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + } + } + +#ifdef GRUB_MACHINE_PCBIOS + if (grub_strcmp (cmd->name, "vbeinfo") == 0) + grub_dl_load ("vbe"); +#endif + + id = grub_video_get_driver_id (); + + grub_printf ("List of supported video modes:\n"); + grub_printf ("Legend: P=Packed pixel, D=Direct color, " + "mask/pos=R/G/B/reserved\n"); + + FOR_VIDEO_ADAPTERS (adapter) + { + grub_printf ("Adapter '%s':\n", adapter->name); + + if (!adapter->iterate) + { + grub_printf (" No info available\n"); + continue; + } + + if (adapter->id != id) + { + if (adapter->init ()) + { + grub_printf (" Failed\n"); + grub_errno = GRUB_ERR_NONE; + continue; + } + } + + if (adapter->print_adapter_specific_info) + adapter->print_adapter_specific_info (); + + adapter->iterate (hook); + + if (adapter->id != id) + { + if (adapter->fini ()) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + } + } + return GRUB_ERR_NONE; +} + +static grub_command_t cmd; +#ifdef GRUB_MACHINE_PCBIOS +static grub_command_t cmd_vbe; +#endif + +GRUB_MOD_INIT(videoinfo) +{ + cmd = grub_register_command ("videoinfo", grub_cmd_videoinfo, "[WxH[xD]]", + N_("List available video modes. If " + "resolution is given show only modes" + " matching it.")); +#ifdef GRUB_MACHINE_PCBIOS + cmd_vbe = grub_register_command ("vbeinfo", grub_cmd_videoinfo, "[WxH[xD]]", + N_("List available video modes. If " + "resolution is given show only modes" + " matching it.")); +#endif +} + +GRUB_MOD_FINI(videoinfo) +{ + grub_unregister_command (cmd); +#ifdef GRUB_MACHINE_PCBIOS + grub_unregister_command (cmd_vbe); +#endif +} + diff --git a/grub-core/commands/videotest.c b/grub-core/commands/videotest.c index c544d1839..435ac2937 100644 --- a/grub-core/commands/videotest.c +++ b/grub-core/commands/videotest.c @@ -26,11 +26,11 @@ #include #include #include +#include static grub_err_t grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), - int argc __attribute__ ((unused)), - char **args __attribute__ ((unused))) + int argc, char **args) { grub_err_t err; grub_video_color_t color; @@ -41,8 +41,20 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), int i; struct grub_video_render_target *text_layer; grub_video_color_t palette[16]; + const char *mode = NULL; - err = grub_video_set_mode ("auto", GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); +#ifdef GRUB_MACHINE_PCBIOS + if (grub_strcmp (cmd->name, "vbetest") == 0) + grub_dl_load ("vbe"); +#endif + + mode = grub_env_get ("gfxmode"); + if (argc) + mode = args[0]; + if (!mode) + mode = "auto"; + + err = grub_video_set_mode (mode, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); if (err) return err; @@ -180,14 +192,25 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), } static grub_command_t cmd; +#ifdef GRUB_MACHINE_PCBIOS +static grub_command_t cmd_vbe; +#endif GRUB_MOD_INIT(videotest) { cmd = grub_register_command ("videotest", grub_cmd_videotest, + "[WxH]", + N_("Test video subsystem in mode WxH.")); +#ifdef GRUB_MACHINE_PCBIOS + cmd_vbe = grub_register_command ("vbetest", grub_cmd_videotest, 0, N_("Test video subsystem.")); +#endif } GRUB_MOD_FINI(videotest) { grub_unregister_command (cmd); +#ifdef GRUB_MACHINE_PCBIOS + grub_unregister_command (cmd_vbe); +#endif } diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c new file mode 100644 index 000000000..6eab333b3 --- /dev/null +++ b/grub-core/commands/wildcard.c @@ -0,0 +1,498 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include +#include + +#include + +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 '.': + case '(': + case ')': + buffer[i++] = '\\'; + buffer[i++] = ch; + break; + + case '*': + buffer[i++] = '.'; + buffer[i++] = '*'; + break; + + default: + buffer[i++] = ch; + } + } + buffer[i++] = '$'; + buffer[i] = '\0'; + grub_dprintf ("expand", "Regexp is %s\n", buffer); + + 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_dprintf ("expand", "not matched\n"); + 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, ®exop); + if (noregexop >= regexop) /* no more wildcards */ + break; + + if (make_regex (noregexop, regexop, ®exp)) + goto fail; + + if (paths == 0) + { + if (start == noregexop) /* device part has regexop */ + paths = match_devices (®exp, *start != '('); + + else if (*start == '(') /* device part explicit wo regexop */ + paths = match_files ("", start, noregexop, ®exp); + + 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, ®exp); + grub_free (prefix); + } + } + else + { + char **r = 0; + + for (i = 0; paths[i]; i++) + { + char **p; + + p = match_files (paths[i], start, noregexop, ®exp); + if (! p) + continue; + + r = merge (r, p); + if (! r) + goto fail; + } + paths = r; + } + + regfree (®exp); + 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 (®exp); + return grub_errno; +} diff --git a/grub-core/disk/ata.c b/grub-core/disk/ata.c index cfd58a6d5..fe677e2a0 100644 --- a/grub-core/disk/ata.c +++ b/grub-core/disk/ata.c @@ -723,7 +723,6 @@ grub_ata_open (const char *name, grub_disk_t disk) disk->id = (unsigned long) dev; - disk->has_partitions = 1; disk->data = dev; return 0; diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c index f9c6f3153..7aec1efe8 100644 --- a/grub-core/disk/efi/efidisk.c +++ b/grub-core/disk/efi/efidisk.c @@ -514,16 +514,12 @@ grub_efidisk_open (const char *name, struct grub_disk *disk) switch (name[0]) { case 'f': - disk->has_partitions = 0; d = get_device (fd_devices, num); break; case 'c': - /* FIXME: a CDROM should have partitions, but not implemented yet. */ - disk->has_partitions = 0; d = get_device (cd_devices, num); break; case 'h': - disk->has_partitions = 1; d = get_device (hd_devices, num); break; default: diff --git a/grub-core/disk/host.c b/grub-core/disk/host.c index c4f3e7150..c51966293 100644 --- a/grub-core/disk/host.c +++ b/grub-core/disk/host.c @@ -43,7 +43,6 @@ grub_host_open (const char *name, grub_disk_t disk) disk->total_sectors = 0; disk->id = (unsigned long) "host"; - disk->has_partitions = 0; disk->data = 0; return GRUB_ERR_NONE; diff --git a/grub-core/disk/i386/pc/biosdisk.c b/grub-core/disk/i386/pc/biosdisk.c index 17de0c1a1..3f9015fb9 100644 --- a/grub-core/disk/i386/pc/biosdisk.c +++ b/grub-core/disk/i386/pc/biosdisk.c @@ -17,8 +17,8 @@ */ #include -#include #include +#include #include #include #include @@ -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); @@ -321,7 +327,6 @@ grub_biosdisk_open (const char *name, grub_disk_t disk) if (drive < 0) return grub_errno; - disk->has_partitions = 1; disk->id = drive; data = (struct grub_biosdisk_data *) grub_zalloc (sizeof (*data)); diff --git a/grub-core/disk/ieee1275/nand.c b/grub-core/disk/ieee1275/nand.c index df2ee81f3..a2c717cdb 100644 --- a/grub-core/disk/ieee1275/nand.c +++ b/grub-core/disk/ieee1275/nand.c @@ -113,7 +113,6 @@ grub_nand_open (const char *name, grub_disk_t disk) disk->id = dev_ihandle; - disk->has_partitions = 0; disk->data = data; return 0; diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c index d0d9e894f..85c34609e 100644 --- a/grub-core/disk/ieee1275/ofdisk.c +++ b/grub-core/disk/ieee1275/ofdisk.c @@ -23,9 +23,15 @@ #include #include +static char *last_devpath; +static grub_ieee1275_ihandle_t last_ihandle; + struct ofdisk_hash_ent { char *devpath; + /* Pointer to shortest available name on nodes representing canonical names, + otherwise NULL. */ + const char *shortest; struct ofdisk_hash_ent *next; }; @@ -59,60 +65,125 @@ static struct ofdisk_hash_ent * ofdisk_hash_add (char *devpath) { struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)]; - struct ofdisk_hash_ent *p = grub_malloc(sizeof (*p)); + struct ofdisk_hash_ent *p, *pcan; + char *curcan; - if (p) + p = grub_malloc(sizeof (*p)); + if (!p) + return NULL; + + p->devpath = devpath; + p->next = *head; + p->shortest = 0; + *head = p; + + curcan = grub_ieee1275_canonicalise_devname (devpath); + if (!curcan) { - p->devpath = devpath; - p->next = *head; - *head = p; + grub_errno = GRUB_ERR_NONE; + return p; } + + pcan = ofdisk_hash_find (curcan); + if (!pcan) + pcan = ofdisk_hash_add (curcan); + else + grub_free (curcan); + + if (!pcan) + grub_errno = GRUB_ERR_NONE; + else + { + if (!pcan->shortest + || grub_strlen (pcan->shortest) > grub_strlen (devpath)) + pcan->shortest = devpath; + } + return p; } -static int -grub_ofdisk_iterate (int (*hook) (const char *name)) +static void +scan (void) { auto int dev_iterate (struct grub_ieee1275_devalias *alias); int dev_iterate (struct grub_ieee1275_devalias *alias) { - int ret = 0; + struct ofdisk_hash_ent *op; + + grub_dprintf ("disk", "device name = %s type = %s\n", alias->name, + alias->type); + + if (grub_strcmp (alias->type, "block") != 0) + return 0; grub_dprintf ("disk", "disk name = %s\n", alias->name); - if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY)) + op = ofdisk_hash_find (alias->path); + if (!op) { - grub_ieee1275_phandle_t dev; - char tmp[8]; - - if (grub_ieee1275_finddevice (alias->path, &dev)) + char *name = grub_strdup (alias->name); + if (!name) { - grub_dprintf ("disk", "finddevice (%s) failed\n", alias->path); - return 0; - } - - if (grub_ieee1275_get_property (dev, "iconname", tmp, - sizeof tmp, 0)) - { - grub_dprintf ("disk", "get iconname failed\n"); - return 0; - } - - if (grub_strcmp (tmp, "sdmmc")) - { - grub_dprintf ("disk", "device is not an SD card\n"); + grub_errno = GRUB_ERR_NONE; return 0; } + op = ofdisk_hash_add (name); } - - if (! grub_strcmp (alias->type, "block") && - grub_strncmp (alias->name, "cdrom", 5)) - ret = hook (alias->name); - return ret; + return 0; } - return grub_devalias_iterate (dev_iterate); + grub_devalias_iterate (dev_iterate); + grub_ieee1275_devices_iterate (dev_iterate); +} + +static int +grub_ofdisk_iterate (int (*hook) (const char *name)) +{ + unsigned i; + scan (); + + for (i = 0; i < ARRAY_SIZE (ofdisk_hash); i++) + { + static struct ofdisk_hash_ent *ent; + for (ent = ofdisk_hash[i]; ent; ent = ent->next) + { + if (!ent->shortest) + continue; + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_OFDISK_SDCARD_ONLY)) + { + grub_ieee1275_phandle_t dev; + char tmp[8]; + + if (grub_ieee1275_finddevice (ent->devpath, &dev)) + { + grub_dprintf ("disk", "finddevice (%s) failed\n", + ent->devpath); + continue; + } + + if (grub_ieee1275_get_property (dev, "iconname", tmp, + sizeof tmp, 0)) + { + grub_dprintf ("disk", "get iconname failed\n"); + continue; + } + + if (grub_strcmp (tmp, "sdmmc") != 0) + { + grub_dprintf ("disk", "device is not an SD card\n"); + continue; + } + } + + if (grub_strncmp (ent->shortest, "cdrom", 5) == 0) + continue; + + if (hook (ent->shortest)) + return 1; + } + } + return 0; } static char * @@ -137,11 +208,6 @@ compute_dev_path (const char *name) *p++ = c; } - if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0)) - { - *p++ = ':'; - *p++ = '0'; - } *p++ = '\0'; return devpath; @@ -151,8 +217,6 @@ static grub_err_t grub_ofdisk_open (const char *name, grub_disk_t disk) { grub_ieee1275_phandle_t dev; - grub_ieee1275_ihandle_t dev_ihandle = 0; - struct ofdisk_hash_ent *op; char *devpath; /* XXX: This should be large enough for any possible case. */ char prop[64]; @@ -162,69 +226,50 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) if (! devpath) return grub_errno; - op = ofdisk_hash_find (devpath); - if (!op) - op = ofdisk_hash_add (devpath); + grub_dprintf ("disk", "Opening `%s'.\n", devpath); - grub_free (devpath); - if (!op) - return grub_errno; - - grub_dprintf ("disk", "Opening `%s'.\n", op->devpath); - - if (grub_ieee1275_finddevice (op->devpath, &dev)) - { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read device properties"); - goto fail; - } + if (grub_ieee1275_finddevice (devpath, &dev)) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read device properties"); if (grub_ieee1275_get_property (dev, "device_type", prop, sizeof (prop), &actual)) - { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type"); - goto fail; - } + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't read the device type"); if (grub_strcmp (prop, "block")) - { - grub_error (GRUB_ERR_BAD_DEVICE, "not a block device"); - goto fail; - } - - grub_ieee1275_open (op->devpath, &dev_ihandle); - if (! dev_ihandle) - { - grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); - goto fail; - } - - grub_dprintf ("disk", "Opened `%s' as handle %p.\n", op->devpath, - (void *) (unsigned long) dev_ihandle); + return grub_error (GRUB_ERR_BAD_DEVICE, "not a block device"); /* XXX: There is no property to read the number of blocks. There should be a property `#blocks', but it is not there. Perhaps it is possible to use seek for this. */ disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; - disk->id = (unsigned long) op; + { + struct ofdisk_hash_ent *op; + op = ofdisk_hash_find (devpath); + if (!op) + op = ofdisk_hash_add (devpath); + else + grub_free (devpath); + if (!op) + return grub_errno; + disk->id = (unsigned long) op; + disk->data = op->devpath; + } - /* XXX: Read this, somehow. */ - disk->has_partitions = 1; - disk->data = (void *) (unsigned long) dev_ihandle; return 0; - - fail: - if (dev_ihandle) - grub_ieee1275_close (dev_ihandle); - return grub_errno; } static void grub_ofdisk_close (grub_disk_t disk) { - grub_dprintf ("disk", "Closing handle %p.\n", - (void *) disk->data); - grub_ieee1275_close ((grub_ieee1275_ihandle_t) (unsigned long) disk->data); + if (disk->data == last_devpath) + { + if (last_ihandle) + grub_ieee1275_close (last_ihandle); + last_ihandle = 0; + last_devpath = NULL; + } + disk->data = 0; } static grub_err_t @@ -234,16 +279,40 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, grub_ssize_t status, actual; unsigned long long pos; + if (disk->data != last_devpath) + { + if (last_ihandle) + grub_ieee1275_close (last_ihandle); + last_ihandle = 0; + last_devpath = NULL; + + if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0)) + { + char name2[grub_strlen (disk->data) + 3]; + char *p; + + grub_strcpy (name2, disk->data); + p = name2 + grub_strlen (name2); + *p++ = ':'; + *p++ = '0'; + *p = 0; + grub_ieee1275_open (name2, &last_ihandle); + } + else + grub_ieee1275_open (disk->data, &last_ihandle); + if (! last_ihandle) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + last_devpath = disk->data; + } + pos = sector * 512UL; - grub_ieee1275_seek ((grub_ieee1275_ihandle_t) (unsigned long) disk->data, - pos, &status); + grub_ieee1275_seek (last_ihandle, pos, &status); if (status < 0) return grub_error (GRUB_ERR_READ_ERROR, "seek error, can't seek block %llu", (long long) sector); - grub_ieee1275_read ((grub_ieee1275_ihandle_t) (unsigned long) disk->data, - buf, size * 512UL, &actual); + grub_ieee1275_read (last_ihandle, buf, size * 512UL, &actual); if (actual != (grub_ssize_t) (size * 512UL)) return grub_error (GRUB_ERR_READ_ERROR, "read error on block: %llu", (long long) sector); @@ -281,5 +350,10 @@ grub_ofdisk_init (void) void grub_ofdisk_fini (void) { + if (last_ihandle) + grub_ieee1275_close (last_ihandle); + last_ihandle = 0; + last_devpath = NULL; + grub_disk_dev_unregister (&grub_ofdisk_dev); } diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c index 509e9e33f..ae4cb9a9c 100644 --- a/grub-core/disk/loopback.c +++ b/grub-core/disk/loopback.c @@ -29,7 +29,6 @@ struct grub_loopback { char *devname; grub_file_t file; - int has_partitions; struct grub_loopback *next; }; @@ -38,7 +37,6 @@ static struct grub_loopback *loopback_list; static const struct grub_arg_option options[] = { {"delete", 'd', 0, N_("Delete the loopback device entry."), 0, 0}, - {"partitions", 'p', 0, N_("Simulate a hard drive with partitions."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -71,9 +69,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; @@ -106,9 +104,6 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) grub_file_close (newdev->file); newdev->file = file; - /* Set has_partitions when `--partitions' was used. */ - newdev->has_partitions = state[1].set; - return 0; } @@ -126,9 +121,6 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) newdev->file = file; - /* Set has_partitions when `--partitions' was used. */ - newdev->has_partitions = state[1].set; - /* Add the new entry to the list. */ newdev->next = loopback_list; loopback_list = newdev; @@ -167,11 +159,13 @@ 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; disk->data = dev->file; return 0; @@ -227,8 +221,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(loopback) { - cmd = grub_register_extcmd ("loopback", grub_cmd_loopback, - GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("loopback", grub_cmd_loopback, 0, N_("[-d|-p] DEVICENAME FILE."), N_("Make a device of a file."), options); grub_disk_dev_register (&grub_loopback_dev); diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c index 71860e853..94cf9a1aa 100644 --- a/grub-core/disk/lvm.c +++ b/grub-core/disk/lvm.c @@ -150,7 +150,6 @@ grub_lvm_open (const char *name, grub_disk_t disk) if (! lv) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown LVM device %s", name); - disk->has_partitions = 0; disk->id = lv->number; disk->data = lv; disk->total_sectors = lv->size; @@ -274,9 +273,17 @@ 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; + { + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_errno = GRUB_ERR_NONE; + return 0; + } /* Search for label. */ for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++) @@ -294,7 +301,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 +330,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 +359,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 +382,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 +399,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 +427,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 +472,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 +543,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 +558,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 +591,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 +609,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++) @@ -655,6 +728,8 @@ grub_lvm_scan_device (const char *name) grub_free (metadatabuf); fail: grub_disk_close (disk); + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + grub_errno = GRUB_ERR_NONE; return 0; } diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c index 2e8885020..e00280dd7 100644 --- a/grub-core/disk/memdisk.c +++ b/grub-core/disk/memdisk.c @@ -41,7 +41,6 @@ grub_memdisk_open (const char *name, grub_disk_t disk) disk->total_sectors = memdisk_size / GRUB_DISK_SECTOR_SIZE; disk->id = (unsigned long) "mdsk"; - disk->has_partitions = 0; return GRUB_ERR_NONE; } diff --git a/grub-core/disk/raid.c b/grub-core/disk/raid.c index 51a4b00e2..2fd6aa9de 100644 --- a/grub-core/disk/raid.c +++ b/grub-core/disk/raid.c @@ -126,7 +126,6 @@ grub_raid_open (const char *name, grub_disk_t disk) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s", name); - disk->has_partitions = 1; disk->id = array->number; disk->data = array; diff --git a/grub-core/disk/scsi.c b/grub-core/disk/scsi.c index 60192bef5..902ab12c3 100644 --- a/grub-core/disk/scsi.c +++ b/grub-core/disk/scsi.c @@ -431,12 +431,6 @@ grub_scsi_open (const char *name, grub_disk_t disk) "unknown SCSI device"); } - if (scsi->devtype == grub_scsi_devtype_cdrom) - disk->has_partitions = 0; - else - disk->has_partitions = 1; - - /* According to USB MS tests specification, issue Test Unit Ready * until OK */ maxtime = grub_get_time_ms () + 5000; /* It is safer value */ diff --git a/grub-core/efiemu/mm.c b/grub-core/efiemu/mm.c index de7d309be..3c1dc2946 100644 --- a/grub-core/efiemu/mm.c +++ b/grub-core/efiemu/mm.c @@ -29,8 +29,8 @@ #include #include #include -#include #include +#include struct grub_efiemu_memrequest { @@ -269,10 +269,11 @@ static grub_err_t grub_efiemu_mmap_init (void) { auto int NESTED_FUNC_ATTR bounds_hook (grub_uint64_t, grub_uint64_t, - grub_uint32_t); + grub_memory_type_t); int NESTED_FUNC_ATTR bounds_hook (grub_uint64_t addr __attribute__ ((unused)), grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) + grub_memory_type_t type + __attribute__ ((unused))) { mmap_reserved_size++; return 0; @@ -382,32 +383,29 @@ grub_efiemu_mm_init (void) static grub_err_t grub_efiemu_mmap_fill (void) { - auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { switch (type) { - case GRUB_MACHINE_MEMORY_AVAILABLE: + case GRUB_MEMORY_AVAILABLE: return grub_efiemu_add_to_mmap (addr, size, GRUB_EFI_CONVENTIONAL_MEMORY); -#ifdef GRUB_MACHINE_MEMORY_ACPI - case GRUB_MACHINE_MEMORY_ACPI: + case GRUB_MEMORY_ACPI: return grub_efiemu_add_to_mmap (addr, size, GRUB_EFI_ACPI_RECLAIM_MEMORY); -#endif -#ifdef GRUB_MACHINE_MEMORY_NVS - case GRUB_MACHINE_MEMORY_NVS: + case GRUB_MEMORY_NVS: return grub_efiemu_add_to_mmap (addr, size, GRUB_EFI_ACPI_MEMORY_NVS); -#endif default: - grub_printf ("Unknown memory type %d. Marking as unusable\n", type); - case GRUB_MACHINE_MEMORY_RESERVED: + grub_printf ("Unknown memory type %d. Assuming unusable\n", type); + case GRUB_MEMORY_RESERVED: return grub_efiemu_add_to_mmap (addr, size, GRUB_EFI_UNUSABLE_MEMORY); } @@ -421,9 +419,7 @@ grub_efiemu_mmap_fill (void) } grub_err_t -grub_efiemu_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, - grub_uint64_t, - grub_uint32_t)) +grub_efiemu_mmap_iterate (grub_memory_hook_t hook) { unsigned i; @@ -432,18 +428,22 @@ grub_efiemu_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, { case GRUB_EFI_RUNTIME_SERVICES_CODE: hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, - GRUB_EFIEMU_MEMORY_CODE); + GRUB_MEMORY_CODE); + break; + + case GRUB_EFI_UNUSABLE_MEMORY: + hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, + GRUB_MEMORY_BADRAM); break; case GRUB_EFI_RESERVED_MEMORY_TYPE: case GRUB_EFI_RUNTIME_SERVICES_DATA: - case GRUB_EFI_UNUSABLE_MEMORY: case GRUB_EFI_MEMORY_MAPPED_IO: case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE: case GRUB_EFI_PAL_CODE: case GRUB_EFI_MAX_MEMORY_TYPE: hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, - GRUB_EFIEMU_MEMORY_RESERVED); + GRUB_MEMORY_RESERVED); break; case GRUB_EFI_LOADER_CODE: @@ -452,17 +452,17 @@ grub_efiemu_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, case GRUB_EFI_BOOT_SERVICES_DATA: case GRUB_EFI_CONVENTIONAL_MEMORY: hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, - GRUB_EFIEMU_MEMORY_AVAILABLE); + GRUB_MEMORY_AVAILABLE); break; case GRUB_EFI_ACPI_RECLAIM_MEMORY: hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, - GRUB_EFIEMU_MEMORY_ACPI); + GRUB_MEMORY_ACPI); break; case GRUB_EFI_ACPI_MEMORY_NVS: hook (efiemu_mmap[i].physical_start, efiemu_mmap[i].num_pages * 4096, - GRUB_EFIEMU_MEMORY_NVS); + GRUB_MEMORY_NVS); break; } diff --git a/grub-core/efiemu/prepare.c b/grub-core/efiemu/prepare.c index 620260049..171e092c9 100644 --- a/grub-core/efiemu/prepare.c +++ b/grub-core/efiemu/prepare.c @@ -20,9 +20,9 @@ #include #include -#include +#include #include -#include +#include grub_err_t SUFFIX (grub_efiemu_prepare) (struct grub_efiemu_prepare_hook *prepare_hooks, @@ -123,6 +123,7 @@ SUFFIX (grub_efiemu_crc) (void) int handle; grub_off_t off; struct SUFFIX (grub_efiemu_runtime_services) *runtime_services; + grub_uint8_t crc32_context[GRUB_MD_CRC32->contextsize]; /* compute CRC32 of runtime_services */ err = grub_efiemu_resolve_symbol ("efiemu_runtime_services", @@ -132,19 +133,25 @@ SUFFIX (grub_efiemu_crc) (void) runtime_services = (struct SUFFIX (grub_efiemu_runtime_services) *) ((grub_uint8_t *) grub_efiemu_mm_obtain_request (handle) + off); - runtime_services->hdr.crc32 = 0; - runtime_services->hdr.crc32 = grub_getcrc32 - (0, runtime_services, runtime_services->hdr.header_size); + + GRUB_MD_CRC32->init(crc32_context); + GRUB_MD_CRC32->write(crc32_context, runtime_services, runtime_services->hdr.header_size); + GRUB_MD_CRC32->final(crc32_context); + + runtime_services->hdr.crc32 = + grub_be_to_cpu32(*(grub_uint32_t*)GRUB_MD_CRC32->read(crc32_context)); err = grub_efiemu_resolve_symbol ("efiemu_system_table", &handle, &off); if (err) return err; /* compute CRC32 of system table */ - SUFFIX (grub_efiemu_system_table)->hdr.crc32 = 0; - SUFFIX (grub_efiemu_system_table)->hdr.crc32 - = grub_getcrc32 (0, SUFFIX (grub_efiemu_system_table), - SUFFIX (grub_efiemu_system_table)->hdr.header_size); + GRUB_MD_CRC32->init(crc32_context); + GRUB_MD_CRC32->write(crc32_context, SUFFIX (grub_efiemu_system_table), + SUFFIX (grub_efiemu_system_table)->hdr.header_size); + GRUB_MD_CRC32->final(crc32_context); + SUFFIX (grub_efiemu_system_table)->hdr.crc32 = + grub_be_to_cpu32(*(grub_uint32_t*)GRUB_MD_CRC32->read(crc32_context)); grub_dprintf ("efiemu","system_table = %p, runtime_services = %p\n", SUFFIX (grub_efiemu_system_table), runtime_services); diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c new file mode 100644 index 000000000..a50bae000 --- /dev/null +++ b/grub-core/fs/btrfs.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c index f2fec828a..dfc75c625 100644 --- a/grub-core/fs/ext2.c +++ b/grub-core/fs/ext2.c @@ -728,22 +728,27 @@ grub_ext2_open (struct grub_file *file, const char *name) { struct grub_ext2_data *data; struct grub_fshelp_node *fdiro = 0; + grub_err_t err; grub_dl_ref (my_mod); data = grub_ext2_mount (file->device->disk); if (! data) - goto fail; + { + err = grub_errno; + goto fail; + } - grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_ext2_iterate_dir, - grub_ext2_read_symlink, GRUB_FSHELP_REG); - if (grub_errno) + err = grub_fshelp_find_file (name, &data->diropen, &fdiro, + grub_ext2_iterate_dir, + grub_ext2_read_symlink, GRUB_FSHELP_REG); + if (err) goto fail; if (! fdiro->inode_read) { - grub_ext2_read_inode (data, fdiro->ino, &fdiro->inode); - if (grub_errno) + err = grub_ext2_read_inode (data, fdiro->ino, &fdiro->inode); + if (err) goto fail; } @@ -763,7 +768,7 @@ grub_ext2_open (struct grub_file *file, const char *name) grub_dl_unref (my_mod); - return grub_errno; + return err; } static grub_err_t diff --git a/grub-core/fs/i386/pc/pxe.c b/grub-core/fs/i386/pc/pxe.c index 0dd44a30a..cbb3c7d87 100644 --- a/grub-core/fs/i386/pc/pxe.c +++ b/grub-core/fs/i386/pc/pxe.c @@ -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, ®s); 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 @@ -170,7 +176,6 @@ grub_pxe_open (const char *name, grub_disk_t disk) disk->total_sectors = 0; disk->id = (unsigned long) data; - disk->has_partitions = 0; disk->data = data; return GRUB_ERR_NONE; @@ -276,6 +281,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 +327,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 +489,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; diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c index a856e38c4..aa5b9a0c9 100644 --- a/grub-core/fs/minix.c +++ b/grub-core/fs/minix.c @@ -25,10 +25,13 @@ #include #include +#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); } diff --git a/grub-core/fs/minix2.c b/grub-core/fs/minix2.c new file mode 100644 index 000000000..0fcd4b139 --- /dev/null +++ b/grub-core/fs/minix2.c @@ -0,0 +1,2 @@ +#define MODE_MINIX2 1 +#include "minix.c" diff --git a/grub-core/gencmdlist.sh b/grub-core/gencmdlist.sh deleted file mode 100644 index ed5965f07..000000000 --- a/grub-core/gencmdlist.sh +++ /dev/null @@ -1,22 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 2005,2009 Free Software Foundation, Inc. -# -# This gensymlist.sh is free software; the author -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -# Read source code from stdin and detect command names. - -module=$1 - -grep -v "^#" | sed -n \ - -e "/grub_register_command *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $module/;p;}" \ - -e "/grub_register_extcmd *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $module/;p;}" \ - -e "/grub_register_command_p1 *( *\"/{s/.*( *\"\([^\"]*\)\".*/*\1: $module/;p;}" - diff --git a/grub-core/genfslist.sh b/grub-core/genfslist.sh deleted file mode 100644 index 6fa7e927d..000000000 --- a/grub-core/genfslist.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 2005,2008 Free Software Foundation, Inc. -# -# This gensymlist.sh is free software; the author -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -# Read source code from stdin and detect fs names. - -module=$1 - -# Ignore kernel.mod. -if test $module = kernel; then - exit -fi - -# For now, this emits only a module name, if the module registers a filesystem. -if grep -v "^#" | grep '^ *grub_fs_register' >/dev/null 2>&1; then - echo $module -fi diff --git a/grub-core/genhandlerlist.sh b/grub-core/genhandlerlist.sh deleted file mode 100644 index e4cb0d9de..000000000 --- a/grub-core/genhandlerlist.sh +++ /dev/null @@ -1,19 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 2009 Free Software Foundation, Inc. -# -# This script is free software; the author -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -# Read source code from stdin and detect command names. - -module=$1 - -grep -v "^#" | sed -n \ - -e "/grub_parser_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/parser.\1: $module/;p;}" diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in new file mode 100644 index 000000000..faac2b605 --- /dev/null +++ b/grub-core/genmod.sh.in @@ -0,0 +1,73 @@ +#! /bin/sh -e +# +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# This gensymlist.sh is free software; the author +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# +# Example: +# +# genmod.sh moddep.lst normal.module normal.mod +# + +moddep=$1 +infile=$2 +outfile=$3 + +tmpfile=${outfile}.tmp +modname=`echo $infile | sed -e 's@\.module.*$@@'` + +if ! grep ^$modname: $moddep >/dev/null; then + echo "warning: moddep.lst has no dependencies for $modname" >&2 + exit 0 +fi + +deps=`grep ^$modname: $moddep | sed s@^.*:@@` + +# remove old files if any +rm -f $tmpfile $outfile + +# stripout .modname and .moddeps sections from input module +objcopy -R .modname -R .moddeps $infile $tmpfile + +# Attach .modname and .moddeps sections +t1=`mktemp` +printf "$modname\0" >$t1 + +t2=`mktemp` +for dep in $deps; do printf "$dep\0" >> $t2; done + +if test -n "$deps"; then + objcopy --add-section .modname=$t1 --add-section .moddeps=$t2 $tmpfile +else + objcopy --add-section .modname=$t1 $tmpfile +fi +rm -f $t1 $t2 + +if test x@TARGET_APPLE_CC@ != x1; then + if ! test -z "@TARGET_OBJ2ELF@"; then + ./@TARGET_OBJ2ELF@ $tmpfile || exit 1 + fi + if test x@platform@ != xemu; then + @STRIP@ --strip-unneeded \ + -K grub_mod_init -K grub_mod_fini \ + -K _grub_mod_init -K _grub_mod_fini \ + -R .note -R .comment $tmpfile || exit 1 + fi +else +# XXX Test these Apple CC fixes + cp $tmpfile $tmpfile.bin + @OBJCONV@ -f@TARGET_MODULE_FORMAT@ \ + -nr:_grub_mod_init:grub_mod_init \ + -nr:_grub_mod_fini:grub_mod_fini \ + -wd1106 -ew2030 -ew2050 -nu -nd $tmpfile.bin $tmpfile || exit 1 + rm -f $name.bin +fi +mv $tmpfile $outfile diff --git a/grub-core/genmoddep.awk b/grub-core/genmoddep.awk index 74487eabf..e412d4370 100644 --- a/grub-core/genmoddep.awk +++ b/grub-core/genmoddep.awk @@ -11,23 +11,28 @@ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. -# Read defined symbols from stdin. +# Read symbols' info from stdin. BEGIN { + error = 0 + lineno = 0; while (getline <"/dev/stdin") { - symtab[$1] = $2 - } -} - -# The rest is undefined symbols. -{ - module = $2 - - if ($1 in symtab) { - modtab[module] = modtab[module] " " symtab[$1]; - } - else if ($1 != "__gnu_local_gp") { - printf "%s in %s is not defined\n", $1, module >"/dev/stderr"; - error++; + lineno++; + if ($1 == "defined") { + symtab[$3] = $2; + modtab[$2] = "" modtab[$2] + } else if ($1 == "undefined") { + if ($3 in symtab) + modtab[$2] = modtab[$2] " " symtab[$3]; + else if ($3 != "__gnu_local_gp") { + printf "%s in %s is not defined\n", $3, $2 >"/dev/stderr"; + error++; + } + } + else { + printf "error: %u: unrecognized input format\n", lineno; + error++; + break; + } } } diff --git a/grub-core/genmodsrc.sh b/grub-core/genmodsrc.sh deleted file mode 100644 index 2d420550a..000000000 --- a/grub-core/genmodsrc.sh +++ /dev/null @@ -1,47 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 2002,2007 Free Software Foundation, Inc. -# -# This genmodsrc.sh is free software; the author -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -set -e - -mod_name="$1" -deps="$2" - -cat <. - */ - -#include - -EOF - -echo "GRUB_MOD_NAME(${mod_name});" - -for mod in `grep "^${mod_name}:" ${deps} | sed 's/^[^:]*://'`; do - echo "GRUB_MOD_DEP(${mod});" -done diff --git a/grub-core/genpartmaplist.sh b/grub-core/genpartmaplist.sh deleted file mode 100644 index fceb0f869..000000000 --- a/grub-core/genpartmaplist.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 2005, 2008 Free Software Foundation, Inc. -# -# This script is free software; the author -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -# Read source code from stdin and detect partmap names. - -module=$1 - -# Ignore kernel.mod. -if test $module = kernel; then - exit -fi - -# For now, this emits only a module name, if the module registers a partition map. -if grep -v "^#" | grep '^ *grub_partition_map_register' >/dev/null 2>&1; then - echo $module -fi diff --git a/grub-core/genparttoollist.sh b/grub-core/genparttoollist.sh deleted file mode 100644 index 48a0efe55..000000000 --- a/grub-core/genparttoollist.sh +++ /dev/null @@ -1,19 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 2009 Free Software Foundation, Inc. -# -# This gensymlist.sh is free software; the author -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -# Read source code from stdin and detect parttool names. - -module=$1 - -grep -v "^#" | sed -n \ - -e "/grub_parttool_register *( *\"/{s/.*( *\"\([^\"]*\)\".*/\1: $module/;p;}" diff --git a/grub-core/gensyminfo.sh.in b/grub-core/gensyminfo.sh.in new file mode 100644 index 000000000..4f5184913 --- /dev/null +++ b/grub-core/gensyminfo.sh.in @@ -0,0 +1,34 @@ +#! /bin/sh -e +# +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# This gensymlist.sh is free software; the author +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# +# Example: +# +# gensyms.sh normal.module +# + +module=$1 +modname=`echo $module | sed -e 's@\.module.*$@@'` + +# Print all symbols defined by module +if test x@TARGET_APPLE_CC@ = x1; then + @NM@ -g -P -p $module | \ + grep -E '^[a-zA-Z0-9_]* [TDS]' | \ + sed "s@^\([^ ]*\).*@defined $modname \1@g" +else + @NM@ -g --defined-only -P -p $module | \ + sed "s@^\([^ ]*\).*@defined $modname \1@g" +fi + +# Print all undefined symbols used by module +@NM@ -u -P -p $module | sed "s@^\([^ ]*\).*@undefined $modname \1@g" diff --git a/grub-core/genterminallist.sh b/grub-core/genterminallist.sh deleted file mode 100644 index 60f5b9105..000000000 --- a/grub-core/genterminallist.sh +++ /dev/null @@ -1,20 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 2009,2010 Free Software Foundation, Inc. -# -# This script is free software; the author -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -# Read source code from stdin and detect command names. - -module=$1 - -grep -v "^#" | sed -n \ - -e "/grub_term_register_input *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $module/;p;}" \ - -e "/grub_term_register_output *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $module/;p;}" \ diff --git a/grub-core/genvideolist.sh b/grub-core/genvideolist.sh deleted file mode 100644 index b208fa25c..000000000 --- a/grub-core/genvideolist.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/sh -# -# Copyright (C) 2005,2008,2009 Free Software Foundation, Inc. -# -# This script is free software; the author -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -# Read source code from stdin and detect partmap names. - -module=$1 - -# Ignore video.mod. -if test $module = video; then - exit -fi - -# For now, this emits only a module name, if the module registers a partition map. -if grep -v "^#" | grep '^ *grub_video_register' >/dev/null 2>&1; then - echo $module -fi diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c index bc7d42824..2f94ac030 100644 --- a/grub-core/gettext/gettext.c +++ b/grub-core/gettext/gettext.c @@ -26,7 +26,6 @@ #include #include #include -#include #include /* @@ -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) diff --git a/grub-core/gnulib/basename-lgpl.c b/grub-core/gnulib/basename-lgpl.c new file mode 100644 index 000000000..a35ff01c2 --- /dev/null +++ b/grub-core/gnulib/basename-lgpl.c @@ -0,0 +1,75 @@ +/* basename.c -- return the last element in a file name + + Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2010 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include "dirname.h" + +#include + +/* Return the address of the last file name component of NAME. If + NAME has no relative file name components because it is a file + system root, return the empty string. */ + +char * +last_component (char const *name) +{ + char const *base = name + FILE_SYSTEM_PREFIX_LEN (name); + char const *p; + bool saw_slash = false; + + while (ISSLASH (*base)) + base++; + + for (p = base; *p; p++) + { + if (ISSLASH (*p)) + saw_slash = true; + else if (saw_slash) + { + base = p; + saw_slash = false; + } + } + + return (char *) base; +} + +/* Return the length of the basename NAME. Typically NAME is the + value returned by base_name or last_component. Act like strlen + (NAME), except omit all trailing slashes. */ + +size_t +base_len (char const *name) +{ + size_t len; + size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name); + + for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--) + continue; + + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1 + && ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2]) + return 2; + + if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len + && len == prefix_len && ISSLASH (name[prefix_len])) + return prefix_len + 1; + + return len; +} diff --git a/grub-core/gnulib/basename.c b/grub-core/gnulib/basename.c new file mode 100644 index 000000000..24da93ac4 --- /dev/null +++ b/grub-core/gnulib/basename.c @@ -0,0 +1,58 @@ +/* basename.c -- return the last element in a file name + + Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2010 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include "dirname.h" + +#include +#include "xalloc.h" +#include "xstrndup.h" + +char * +base_name (char const *name) +{ + char const *base = last_component (name); + size_t length; + + /* If there is no last component, then name is a file system root or the + empty string. */ + if (! *base) + return xstrndup (name, base_len (name)); + + /* Collapse a sequence of trailing slashes into one. */ + length = base_len (base); + if (ISSLASH (base[length])) + length++; + + /* On systems with drive letters, `a/b:c' must return `./b:c' rather + than `b:c' to avoid confusion with a drive letter. On systems + with pure POSIX semantics, this is not an issue. */ + if (FILE_SYSTEM_PREFIX_LEN (base)) + { + char *p = xmalloc (length + 3); + p[0] = '.'; + p[1] = '/'; + memcpy (p + 2, base, length); + p[length + 2] = '\0'; + return p; + } + + /* Finally, copy the basename. */ + return xstrndup (base, length); +} diff --git a/grub-core/gnulib/dirname-lgpl.c b/grub-core/gnulib/dirname-lgpl.c new file mode 100644 index 000000000..d4506e060 --- /dev/null +++ b/grub-core/gnulib/dirname-lgpl.c @@ -0,0 +1,86 @@ +/* dirname.c -- return all but the last element in a file name + + Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2010 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include "dirname.h" + +#include +#include + +/* Return the length of the prefix of FILE that will be used by + dir_name. If FILE is in the working directory, this returns zero + even though `dir_name (FILE)' will return ".". Works properly even + if there are trailing slashes (by effectively ignoring them). */ + +size_t +dir_len (char const *file) +{ + size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file); + size_t length; + + /* Advance prefix_length beyond important leading slashes. */ + prefix_length += (prefix_length != 0 + ? (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE + && ISSLASH (file[prefix_length])) + : (ISSLASH (file[0]) + ? ((DOUBLE_SLASH_IS_DISTINCT_ROOT + && ISSLASH (file[1]) && ! ISSLASH (file[2]) + ? 2 : 1)) + : 0)); + + /* Strip the basename and any redundant slashes before it. */ + for (length = last_component (file) - file; + prefix_length < length; length--) + if (! ISSLASH (file[length - 1])) + break; + return length; +} + + +/* In general, we can't use the builtin `dirname' function if available, + since it has different meanings in different environments. + In some environments the builtin `dirname' modifies its argument. + + Return the leading directories part of FILE, allocated with malloc. + Works properly even if there are trailing slashes (by effectively + ignoring them). Return NULL on failure. + + If lstat (FILE) would succeed, then { chdir (dir_name (FILE)); + lstat (base_name (FILE)); } will access the same file. Likewise, + if the sequence { chdir (dir_name (FILE)); + rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE + to "foo" in the same directory FILE was in. */ + +char * +mdir_name (char const *file) +{ + size_t length = dir_len (file); + bool append_dot = (length == 0 + || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE + && length == FILE_SYSTEM_PREFIX_LEN (file) + && file[2] != '\0' && ! ISSLASH (file[2]))); + char *dir = malloc (length + append_dot + 1); + if (!dir) + return NULL; + memcpy (dir, file, length); + if (append_dot) + dir[length++] = '.'; + dir[length] = '\0'; + return dir; +} diff --git a/grub-core/gnulib/dirname.c b/grub-core/gnulib/dirname.c new file mode 100644 index 000000000..953a9acc3 --- /dev/null +++ b/grub-core/gnulib/dirname.c @@ -0,0 +1,38 @@ +/* dirname.c -- return all but the last element in a file name + + Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2010 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include "dirname.h" + +#include +#include +#include "xalloc.h" + +/* Just like mdir_name (dirname-lgpl.c), except, rather than + returning NULL upon malloc failure, here, we report the + "memory exhausted" condition and exit. */ + +char * +dir_name (char const *file) +{ + char *result = mdir_name (file); + if (!result) + xalloc_die (); + return result; +} diff --git a/grub-core/gnulib/dirname.h b/grub-core/gnulib/dirname.h new file mode 100644 index 000000000..fb19508f7 --- /dev/null +++ b/grub-core/gnulib/dirname.h @@ -0,0 +1,74 @@ +/* Take file names apart into directory and base names. + + Copyright (C) 1998, 2001, 2003-2006, 2009-2010 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef DIRNAME_H_ +# define DIRNAME_H_ 1 + +# include +# include + +# ifndef DIRECTORY_SEPARATOR +# define DIRECTORY_SEPARATOR '/' +# endif + +# ifndef ISSLASH +# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) +# endif + +# ifndef FILE_SYSTEM_PREFIX_LEN +# if FILE_SYSTEM_ACCEPTS_DRIVE_LETTER_PREFIX + /* This internal macro assumes ASCII, but all hosts that support drive + letters use ASCII. */ +# define _IS_DRIVE_LETTER(c) (((unsigned int) (c) | ('a' - 'A')) - 'a' \ + <= 'z' - 'a') +# define FILE_SYSTEM_PREFIX_LEN(Filename) \ + (_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':' ? 2 : 0) +# else +# define FILE_SYSTEM_PREFIX_LEN(Filename) 0 +# endif +# endif + +# ifndef FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE +# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0 +# endif + +# ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT +# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 +# endif + +# if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE +# define IS_ABSOLUTE_FILE_NAME(F) ISSLASH ((F)[FILE_SYSTEM_PREFIX_LEN (F)]) +# else +# define IS_ABSOLUTE_FILE_NAME(F) \ + (ISSLASH ((F)[0]) || 0 < FILE_SYSTEM_PREFIX_LEN (F)) +# endif +# define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F)) + +# if GNULIB_DIRNAME +char *base_name (char const *file); +char *dir_name (char const *file); +# endif + +char *mdir_name (char const *file); +size_t base_len (char const *file); +size_t dir_len (char const *file); +char *last_component (char const *file); + +bool strip_trailing_slashes (char *file); + +#endif /* not DIRNAME_H_ */ diff --git a/grub-core/gnulib/error.c b/grub-core/gnulib/error.c index c79e8d42c..ed9dba0d2 100644 --- a/grub-core/gnulib/error.c +++ b/grub-core/gnulib/error.c @@ -88,6 +88,15 @@ extern void __error_at_line (int status, int errnum, const char *file_name, # include # include +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +/* Get declarations of the Win32 API functions. */ +# define WIN32_LEAN_AND_MEAN +# include +# endif + +/* The gnulib override of fcntl is not needed in this file. */ +# undef fcntl + # if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P # ifndef HAVE_DECL_STRERROR_R "this configure-time declaration test was not run" @@ -104,10 +113,29 @@ extern char *program_name; # endif /* HAVE_STRERROR_R || defined strerror_r */ #endif /* not _LIBC */ +#if !_LIBC +/* Return non-zero if FD is open. */ +static inline int +is_open (int fd) +{ +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* On Win32: The initial state of unassigned standard file descriptors is + that they are open but point to an INVALID_HANDLE_VALUE. There is no + fcntl, and the gnulib replacement fcntl does not support F_GETFL. */ + return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE; +# else +# ifndef F_GETFL +# error Please port fcntl to your platform +# endif + return 0 <= fcntl (fd, F_GETFL); +# endif +} +#endif + static inline void flush_stdout (void) { -#if !_LIBC && defined F_GETFL +#if !_LIBC int stdout_fd; # if GNULIB_FREOPEN_SAFER @@ -124,7 +152,7 @@ flush_stdout (void) /* POSIX states that fflush (stdout) after fclose is unspecified; it is safe in glibc, but not on all other platforms. fflush (NULL) is always defined, but too draconian. */ - if (0 <= stdout_fd && 0 <= fcntl (stdout_fd, F_GETFL)) + if (0 <= stdout_fd && is_open (stdout_fd)) #endif fflush (stdout); } diff --git a/grub-core/gnulib/getopt.c b/grub-core/gnulib/getopt.c index aaabc8d19..3791f1293 100644 --- a/grub-core/gnulib/getopt.c +++ b/grub-core/gnulib/getopt.c @@ -348,8 +348,6 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, int long_only, struct _getopt_data *d, int posixly_correct) { int print_errors = d->opterr; - if (optstring[0] == ':') - print_errors = 0; if (argc < 1) return -1; @@ -364,6 +362,10 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, posixly_correct); d->__initialized = 1; } + else if (optstring[0] == '-' || optstring[0] == '+') + optstring++; + if (optstring[0] == ':') + print_errors = 0; /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag @@ -633,8 +635,8 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, char *buf; if (__asprintf (&buf, _("\ -%s: option '%s' requires an argument\n"), - argv[0], argv[d->optind - 1]) >= 0) +%s: option '--%s' requires an argument\n"), + argv[0], pfound->name) >= 0) { _IO_flockfile (stderr); @@ -651,8 +653,8 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, } #else fprintf (stderr, - _("%s: option '%s' requires an argument\n"), - argv[0], argv[d->optind - 1]); + _("%s: option '--%s' requires an argument\n"), + argv[0], pfound->name); #endif } d->__nextchar += strlen (d->__nextchar); @@ -736,13 +738,13 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, { char c = *d->__nextchar++; - char *temp = strchr (optstring, c); + const char *temp = strchr (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*d->__nextchar == '\0') ++d->optind; - if (temp == NULL || c == ':') + if (temp == NULL || c == ':' || c == ';') { if (print_errors) { @@ -864,7 +866,10 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, pfound = p; indfound = option_index; } - else + else if (long_only + || pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } @@ -876,7 +881,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, char *buf; if (__asprintf (&buf, _("%s: option '-W %s' is ambiguous\n"), - argv[0], argv[d->optind]) >= 0) + argv[0], d->optarg) >= 0) { _IO_flockfile (stderr); @@ -892,7 +897,7 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, } #else fprintf (stderr, _("%s: option '-W %s' is ambiguous\n"), - argv[0], argv[d->optind]); + argv[0], d->optarg); #endif } d->__nextchar += strlen (d->__nextchar); @@ -955,8 +960,8 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, char *buf; if (__asprintf (&buf, _("\ -%s: option '%s' requires an argument\n"), - argv[0], argv[d->optind - 1]) >= 0) +%s: option '-W %s' requires an argument\n"), + argv[0], pfound->name) >= 0) { _IO_flockfile (stderr); @@ -972,15 +977,17 @@ _getopt_internal_r (int argc, char **argv, const char *optstring, free (buf); } #else - fprintf (stderr, - _("%s: option '%s' requires an argument\n"), - argv[0], argv[d->optind - 1]); + fprintf (stderr, _("\ +%s: option '-W %s' requires an argument\n"), + argv[0], pfound->name); #endif } d->__nextchar += strlen (d->__nextchar); return optstring[0] == ':' ? ':' : '?'; } } + else + d->optarg = NULL; d->__nextchar += strlen (d->__nextchar); if (longind != NULL) *longind = option_index; diff --git a/grub-core/gnulib/getopt_int.h b/grub-core/gnulib/getopt_int.h index 169def5b2..980b7507f 100644 --- a/grub-core/gnulib/getopt_int.h +++ b/grub-core/gnulib/getopt_int.h @@ -30,6 +30,40 @@ extern int _getopt_internal (int ___argc, char **___argv, /* Reentrant versions which can handle parsing multiple argument vectors at the same time. */ +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters, or by calling getopt. + + PERMUTE is the default. We permute the contents of ARGV as we + scan, so that eventually all the non-options are at the end. + This allows options to be given in any order, even with programs + that were not written to expect this. + + RETURN_IN_ORDER is an option available to programs that were + written to expect options and other ARGV-elements in any order + and that care about the ordering of the two. We describe each + non-option ARGV-element as if it were the argument of an option + with character code 1. Using `-' as the first character of the + list of option characters selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +enum __ord + { + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER + }; + /* Data type for reentrant functions. */ struct _getopt_data { @@ -54,39 +88,8 @@ struct _getopt_data by advancing to the next ARGV-element. */ char *__nextchar; - /* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters, or by calling getopt. - - PERMUTE is the default. We permute the contents of ARGV as we - scan, so that eventually all the non-options are at the end. - This allows options to be given in any order, even with programs - that were not written to expect this. - - RETURN_IN_ORDER is an option available to programs that were - written to expect options and other ARGV-elements in any order - and that care about the ordering of the two. We describe each - non-option ARGV-element as if it were the argument of an option - with character code 1. Using `-' as the first character of the - list of option characters selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return -1 with `optind' != ARGC. */ - - enum - { - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER - } __ordering; + /* See __ord above. */ + enum __ord __ordering; /* If the POSIXLY_CORRECT environment variable is set or getopt was called. */ diff --git a/grub-core/gnulib/regex.h b/grub-core/gnulib/regex.h index 594d5e6aa..89a8143d4 100644 --- a/grub-core/gnulib/regex.h +++ b/grub-core/gnulib/regex.h @@ -114,10 +114,10 @@ typedef unsigned long int reg_syntax_t; /* If this bit is set, then ^ and $ are always anchors (outside bracket expressions, of course). If this bit is not set, then it depends: - ^ is an anchor if it is at the beginning of a regular - expression or after an open-group or an alternation operator; - $ is an anchor if it is at the end of a regular expression, or - before a close-group or an alternation operator. + ^ is an anchor if it is at the beginning of a regular + expression or after an open-group or an alternation operator; + $ is an anchor if it is at the end of a regular expression, or + before a close-group or an alternation operator. This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because POSIX draft 11.2 says that * etc. in leading positions is undefined. @@ -219,8 +219,8 @@ typedef unsigned long int reg_syntax_t; whether ^ should be special. */ # define RE_CARET_ANCHORS_HERE (RE_ICASE << 1) -/* If this bit is set, then \{ cannot be first in an bre or - immediately after an alternation or begin-group operator. */ +/* If this bit is set, then \{ cannot be first in a regex or + immediately after an alternation, open-group or \} operator. */ # define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1) /* If this bit is set, then no_sub will be set to 1 during @@ -495,8 +495,8 @@ struct re_pattern_buffer #endif unsigned int _REG_RE_NAME (regs_allocated) : 2; - /* Set to zero when `regex_compile' compiles a pattern; set to one - by `re_compile_fastmap' if it updates the fastmap. */ + /* Set to zero when `re_compile_pattern' compiles a pattern; set to + one by `re_compile_fastmap' if it updates the fastmap. */ unsigned int _REG_RE_NAME (fastmap_accurate) : 1; /* If set, `re_match_2' does not return information about @@ -610,8 +610,8 @@ extern regoff_t re_match_2 (struct re_pattern_buffer *__buffer, register data. Unless this function is called, the first search or match using - PATTERN_BUFFER will allocate its own register data, without - freeing the old data. */ + BUFFER will allocate its own register data, without freeing the old + data. */ extern void re_set_registers (struct re_pattern_buffer *__buffer, struct re_registers *__regs, __re_size_t __num_regs, diff --git a/grub-core/gnulib/regex_internal.c b/grub-core/gnulib/regex_internal.c index 378b767d8..787a3a627 100644 --- a/grub-core/gnulib/regex_internal.c +++ b/grub-core/gnulib/regex_internal.c @@ -733,15 +733,17 @@ re_string_reconstruct (re_string_t *pstr, Idx idx, int eflags) mbstate_t cur_state; wchar_t wc2; Idx mlen = raw + pstr->len - p; - unsigned char buf[6]; size_t mbclen; +#if 0 /* dead code: buf is set but never used */ + unsigned char buf[6]; if (BE (pstr->trans != NULL, 0)) { int i = mlen < 6 ? mlen : 6; while (--i >= 0) buf[i] = pstr->trans[p[i]]; } +#endif /* XXX Don't use mbrtowc, we know which conversion to use (UTF-8 -> UCS4). */ memset (&cur_state, 0, sizeof (cur_state)); diff --git a/grub-core/gnulib/regex_internal.h b/grub-core/gnulib/regex_internal.h index e1b4c61b3..dc94e2cbc 100644 --- a/grub-core/gnulib/regex_internal.h +++ b/grub-core/gnulib/regex_internal.h @@ -467,6 +467,8 @@ static unsigned int re_string_context_at (const re_string_t *input, Idx idx, # else /* alloca is implemented with malloc, so just use malloc. */ # define __libc_use_alloca(n) 0 +# undef alloca +# define alloca(n) malloc (n) # endif #endif diff --git a/grub-core/gnulib/stripslash.c b/grub-core/gnulib/stripslash.c new file mode 100644 index 000000000..3a5996fd9 --- /dev/null +++ b/grub-core/gnulib/stripslash.c @@ -0,0 +1,45 @@ +/* stripslash.c -- remove redundant trailing slashes from a file name + + Copyright (C) 1990, 2001, 2003-2006, 2009-2010 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include "dirname.h" + +/* Remove trailing slashes from FILE. Return true if a trailing slash + was removed. This is useful when using file name completion from a + shell that adds a "/" after directory names (such as tcsh and + bash), because on symlinks to directories, several system calls + have different semantics according to whether a trailing slash is + present. */ + +bool +strip_trailing_slashes (char *file) +{ + char *base = last_component (file); + char *base_lim; + bool had_slash; + + /* last_component returns "" for file system roots, but we need to turn + `///' into `/'. */ + if (! *base) + base = file; + base_lim = base + base_len (base); + had_slash = (*base_lim != '\0'); + *base_lim = '\0'; + return had_slash; +} diff --git a/grub-core/hello/hello.c b/grub-core/hello/hello.c index eff07d941..77c4c96b1 100644 --- a/grub-core/hello/hello.c +++ b/grub-core/hello/hello.c @@ -27,7 +27,7 @@ #include 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))) { @@ -39,8 +39,8 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(hello) { - cmd = grub_register_extcmd ("hello", grub_cmd_hello, GRUB_COMMAND_FLAG_BOTH, - 0, N_("Say \"Hello World\"."), 0); + cmd = grub_register_extcmd ("hello", grub_cmd_hello, 0, 0, + N_("Say \"Hello World\"."), 0); } GRUB_MOD_FINI(hello) diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c index 92f29279e..8a72ecd79 100644 --- a/grub-core/io/bufio.c +++ b/grub-core/io/bufio.c @@ -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; } diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c index 9bf609105..43b67c373 100644 --- a/grub-core/io/gzio.c +++ b/grub-core/io/gzio.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include /* * 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); +} diff --git a/grub-core/io/xzio.c b/grub-core/io/xzio.c new file mode 100644 index 000000000..1a22bdc70 --- /dev/null +++ b/grub-core/io/xzio.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/grub-core/kern/command.c b/grub-core/kern/command.c index 477240d57..7f353b653 100644 --- a/grub-core/kern/command.c +++ b/grub-core/kern/command.c @@ -40,7 +40,7 @@ grub_register_command_prio (const char *name, cmd->summary = (summary) ? summary : ""; cmd->description = description; - cmd->flags = GRUB_COMMAND_FLAG_BOTH; + cmd->flags = 0; cmd->prio = prio; grub_prio_list_insert (GRUB_AS_PRIO_LIST_P (&grub_command_list), diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c index 4273fedfe..9554ca76a 100644 --- a/grub-core/kern/device.c +++ b/grub-core/kern/device.c @@ -103,7 +103,7 @@ grub_device_iterate (int (*hook) (const char *name)) return 0; } - if (dev->disk && dev->disk->has_partitions) + if (dev->disk) { struct part_ent *p; int ret = 0; diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c index ccd5f200f..7cf29ae7c 100644 --- a/grub-core/kern/disk.c +++ b/grub-core/kern/disk.c @@ -281,12 +281,6 @@ grub_disk_open (const char *name) goto fail; } - if (p && ! disk->has_partitions) - { - grub_error (GRUB_ERR_BAD_DEVICE, "no partition on this disk"); - goto fail; - } - disk->dev = dev; if (p) diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c index c124aa292..1b0a872b4 100644 --- a/grub-core/kern/efi/init.c +++ b/grub-core/kern/efi/init.c @@ -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) { diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index 875a855ea..4be408c31 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -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; diff --git a/grub-core/kern/emu/cache.S b/grub-core/kern/emu/cache.S index 90a5b5396..abd81c910 100644 --- a/grub-core/kern/emu/cache.S +++ b/grub-core/kern/emu/cache.S @@ -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 + +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 diff --git a/grub-core/kern/emu/console.c b/grub-core/kern/emu/console.c index f6b13b19b..7fd1fc0c9 100644 --- a/grub-core/kern/emu/console.c +++ b/grub-core/kern/emu/console.c @@ -18,6 +18,7 @@ */ #include +#include /* For compatibility. */ #ifndef A_NORMAL @@ -37,6 +38,8 @@ # include #elif defined(HAVE_CURSES_H) # include +#else +#error What the hell? #endif static int grub_console_attr = A_NORMAL; @@ -102,63 +105,32 @@ grub_ncurses_setcolorstate (struct grub_term_output *term, } } -static int saved_char = ERR; - -static int -grub_ncurses_checkkey (struct grub_term_input *term __attribute__ ((unused))) -{ - int c; - - /* Check for SAVED_CHAR. This should not be true, because this - means checkkey is called twice continuously. */ - if (saved_char != ERR) - return saved_char; - - wtimeout (stdscr, 100); - c = getch (); - /* If C is not ERR, then put it back in the input queue. */ - if (c != ERR) - { - saved_char = c; - return c; - } - - return -1; -} - static int grub_ncurses_getkey (struct grub_term_input *term __attribute__ ((unused))) { int c; - /* If checkkey has already got a character, then return it. */ - if (saved_char != ERR) - { - c = saved_char; - saved_char = ERR; - } - else - { - wtimeout (stdscr, -1); - c = getch (); - } + wtimeout (stdscr, 100); + c = getch (); switch (c) { + case ERR: + return -1; case KEY_LEFT: - c = GRUB_TERM_LEFT; + c = GRUB_TERM_KEY_LEFT; break; case KEY_RIGHT: - c = GRUB_TERM_RIGHT; + c = GRUB_TERM_KEY_RIGHT; break; case KEY_UP: - c = GRUB_TERM_UP; + c = GRUB_TERM_KEY_UP; break; case KEY_DOWN: - c = GRUB_TERM_DOWN; + c = GRUB_TERM_KEY_DOWN; break; case KEY_IC: @@ -166,30 +138,30 @@ grub_ncurses_getkey (struct grub_term_input *term __attribute__ ((unused))) break; case KEY_DC: - c = GRUB_TERM_DC; + c = GRUB_TERM_KEY_DC; break; case KEY_BACKSPACE: /* XXX: For some reason ncurses on xterm does not return KEY_BACKSPACE. */ case 127: - c = GRUB_TERM_BACKSPACE; + c = '\b'; break; case KEY_HOME: - c = GRUB_TERM_HOME; + c = GRUB_TERM_KEY_HOME; break; case KEY_END: - c = GRUB_TERM_END; + c = GRUB_TERM_KEY_END; break; case KEY_NPAGE: - c = GRUB_TERM_NPAGE; + c = GRUB_TERM_KEY_NPAGE; break; case KEY_PPAGE: - c = GRUB_TERM_PPAGE; + c = GRUB_TERM_KEY_PPAGE; break; } @@ -288,7 +260,6 @@ grub_ncurses_fini (struct grub_term_output *term __attribute__ ((unused))) static struct grub_term_input grub_ncurses_term_input = { .name = "console", - .checkkey = grub_ncurses_checkkey, .getkey = grub_ncurses_getkey, }; diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c index 0bd33337f..a5801db2f 100644 --- a/grub-core/kern/emu/full.c +++ b/grub-core/kern/emu/full.c @@ -22,6 +22,7 @@ #include #include #include +#include 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 (); +} diff --git a/grub-core/kern/emu/getroot.c b/grub-core/kern/emu/getroot.c index c0a10d22b..003fe9333 100644 --- a/grub-core/kern/emu/getroot.c +++ b/grub-core/kern/emu/getroot.c @@ -228,8 +228,8 @@ find_root_device_from_libzfs (const char *dir) #ifdef __MINGW32__ -static char * -find_root_device (const char *dir __attribute__ ((unused)), +char * +grub_find_device (const char *dir __attribute__ ((unused)), dev_t dev __attribute__ ((unused))) { return 0; @@ -237,13 +237,22 @@ find_root_device (const char *dir __attribute__ ((unused)), #elif ! defined(__CYGWIN__) -static char * -find_root_device (const char *dir, dev_t dev) +char * +grub_find_device (const char *dir, dev_t dev) { DIR *dp; char *saved_cwd; struct dirent *ent; + if (! dir) + { +#ifdef __CYGWIN__ + return NULL; +#else + dir = "/dev"; +#endif + } + dp = opendir (dir); if (! dp) return 0; @@ -292,7 +301,7 @@ find_root_device (const char *dir, dev_t dev) /* Find it recursively. */ char *res; - res = find_root_device (ent->d_name, dev); + res = grub_find_device (ent->d_name, dev); if (res) { @@ -402,8 +411,8 @@ get_bootsec_serial (const char *os_dev, int mbr) return serial; } -static char * -find_cygwin_root_device (const char *path, dev_t dev) +char * +grub_find_device (const char *path, dev_t dev) { /* No root device for /cygdrive. */ if (dev == (DEV_CYGDRIVE_MAJOR << 16)) @@ -424,7 +433,7 @@ find_cygwin_root_device (const char *path, dev_t dev) /* Cygwin returns the partition serial number in stat.st_dev. This is never identical to the device number of the emulated - /dev/sdXN device, so above find_root_device () does not work. + /dev/sdXN device, so above grub_find_device () does not work. Search the partition with the same serial in boot sector instead. */ char devpath[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia. */ int d; @@ -529,12 +538,12 @@ grub_guess_root_device (const char *dir) #ifdef __CYGWIN__ /* Cygwin specific function. */ - os_dev = find_cygwin_root_device (dir, st.st_dev); + os_dev = grub_find_device (dir, st.st_dev); #else /* This might be truly slow, but is there any better way? */ - os_dev = find_root_device ("/dev", st.st_dev); + os_dev = grub_find_device ("/dev", st.st_dev); #endif #endif /* !__GNU__ */ @@ -572,6 +581,10 @@ int grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused))) { #ifdef __linux__ + /* User explicitly claims that this drive is visible by BIOS. */ + if (grub_util_biosdisk_is_present (os_dev)) + return GRUB_DEV_ABSTRACTION_NONE; + /* Check for LVM. */ if (!strncmp (os_dev, "/dev/mapper/", 12) && ! grub_util_is_dmraid (os_dev) diff --git a/grub-core/kern/emu/hostdisk.c b/grub-core/kern/emu/hostdisk.c index 2cdf449e2..7d9d1dac1 100644 --- a/grub-core/kern/emu/hostdisk.c +++ b/grub-core/kern/emu/hostdisk.c @@ -221,7 +221,6 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no mapping exists for `%s'", name); - disk->has_partitions = 1; disk->id = drive; disk->data = data = xmalloc (sizeof (struct grub_util_biosdisk_data)); data->dev = NULL; @@ -956,13 +955,16 @@ read_device_map (const char *dev_map) #ifdef __linux__ /* On Linux, the devfs uses symbolic links horribly, and that confuses the interface very much, so use realpath to expand - symbolic links. */ - map[drive].device = xmalloc (PATH_MAX); - if (! realpath (p, map[drive].device)) - grub_util_error ("cannot get the real path of `%s'", p); -#else - map[drive].device = xstrdup (p); + symbolic links. Leave /dev/mapper/ alone, though. */ + if (strncmp (p, "/dev/mapper/", 12) != 0) + { + map[drive].device = xmalloc (PATH_MAX); + if (! realpath (p, map[drive].device)) + grub_util_error ("cannot get the real path of `%s'", p); + } + else #endif + map[drive].device = xstrdup (p); } fclose (fp); @@ -1117,6 +1119,16 @@ convert_system_partition_to_system_disk (const char *os_dev, struct stat *st) return path; } + if (strncmp ("md", p, 2) == 0 + && p[2] >= '0' && p[2] <= '9') + { + char *ptr = p + 2; + while (*ptr >= '0' && *ptr <= '9') + ptr++; + *ptr = 0; + return path; + } + /* If this is an IDE, SCSI or Virtio disk. */ if (strncmp ("vdisk", p, 5) == 0 && p[5] >= 'a' && p[5] <= 'z') @@ -1144,22 +1156,22 @@ convert_system_partition_to_system_disk (const char *os_dev, struct stat *st) } #ifdef HAVE_DEVICE_MAPPER - /* If this is a DM-RAID device. */ - if ((strncmp ("mapper/", p, 7) == 0)) + /* If this is a DM-RAID device. + Compare os_dev rather than path here, since nodes under + /dev/mapper/ are often symlinks. */ + if ((strncmp ("/dev/mapper/", os_dev, 12) == 0)) { - static struct dm_tree *tree = NULL; + struct dm_tree *tree; uint32_t maj, min; - struct dm_tree_node *node, *child; + struct dm_tree_node *node = NULL, *child; void *handle; - const char *node_uuid, *mapper_name, *child_uuid, *child_name; - - if (! tree) - tree = dm_tree_create (); + const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name; + tree = dm_tree_create (); if (! tree) { grub_dprintf ("hostdisk", "dm_tree_create failed\n"); - return NULL; + goto devmapper_out; } maj = major (st->st_rdev); @@ -1167,29 +1179,30 @@ convert_system_partition_to_system_disk (const char *os_dev, struct stat *st) if (! dm_tree_add_dev (tree, maj, min)) { grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n"); - return NULL; + goto devmapper_out; } node = dm_tree_find_node (tree, maj, min); if (! node) { grub_dprintf ("hostdisk", "dm_tree_find_node failed\n"); - return NULL; + goto devmapper_out; } node_uuid = dm_tree_node_get_uuid (node); if (! node_uuid) { grub_dprintf ("hostdisk", "%s has no DM uuid\n", path); - return NULL; + node = NULL; + goto devmapper_out; } else if (strncmp (node_uuid, "DMRAID-", 7) != 0) { grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path); - return NULL; + node = NULL; + goto devmapper_out; } handle = NULL; - mapper_name = NULL; /* Counter-intuitively, device-mapper refers to the disk-like device containing a DM-RAID partition device as a "child" of the partition device. */ @@ -1219,17 +1232,20 @@ convert_system_partition_to_system_disk (const char *os_dev, struct stat *st) mapper_name = child_name; devmapper_out: - if (! mapper_name) + if (! mapper_name && node) { /* This is a DM-RAID disk, not a partition. */ mapper_name = dm_tree_node_get_name (node); if (! mapper_name) - { - grub_dprintf ("hostdisk", "%s has no DM name\n", path); - return NULL; - } + grub_dprintf ("hostdisk", "%s has no DM name\n", path); } - return xasprintf ("/dev/mapper/%s", mapper_name); + if (tree) + dm_tree_free (tree); + free (path); + if (mapper_name) + return xasprintf ("/dev/mapper/%s", mapper_name); + else + return NULL; } #endif /* HAVE_DEVICE_MAPPER */ } @@ -1334,7 +1350,7 @@ device_is_wholedisk (const char *os_dev) #endif /* defined(__NetBSD__) */ static int -find_system_device (const char *os_dev, struct stat *st) +find_system_device (const char *os_dev, struct stat *st, int add) { unsigned int i; char *os_disk; @@ -1352,6 +1368,9 @@ find_system_device (const char *os_dev, struct stat *st) return i; } + if (!add) + return -1; + if (i == ARRAY_SIZE (map)) grub_util_error (_("device count exceeds limit")); @@ -1361,6 +1380,17 @@ find_system_device (const char *os_dev, struct stat *st) return i; } +int +grub_util_biosdisk_is_present (const char *os_dev) +{ + struct stat st; + + if (stat (os_dev, &st) < 0) + return 0; + + return find_system_device (os_dev, &st, 0) != -1; +} + char * grub_util_biosdisk_get_grub_dev (const char *os_dev) { @@ -1373,7 +1403,7 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) return 0; } - drive = find_system_device (os_dev, &st); + drive = find_system_device (os_dev, &st, 1); if (drive < 0) { grub_error (GRUB_ERR_UNKNOWN_DEVICE, @@ -1552,3 +1582,29 @@ grub_util_biosdisk_get_osdev (grub_disk_t disk) { return map[disk->id].device; } + +int +grub_util_biosdisk_is_floppy (grub_disk_t disk) +{ + struct stat st; + int fd; + + fd = open (map[disk->id].device, O_RDONLY); + /* Shouldn't happen. */ + if (fd == -1) + return 0; + + /* Shouldn't happen either. */ + if (fstat (fd, &st) < 0) + return 0; + +#if defined(__NetBSD__) + if (major(st.st_rdev) == RAW_FLOPPY_MAJOR) + return 1; +#endif + + if (major(st.st_rdev) == FLOPPY_MAJOR) + return 1; + + return 0; +} diff --git a/grub-core/kern/emu/lite.c b/grub-core/kern/emu/lite.c index 9b3728717..32e12a079 100644 --- a/grub-core/kern/emu/lite.c +++ b/grub-core/kern/emu/lite.c @@ -38,3 +38,8 @@ grub_emu_init (void) { return; } + +void +grub_emu_post_init (void) +{ +} diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c index 9156aa890..c575beb4b 100644 --- a/grub-core/kern/emu/main.c +++ b/grub-core/kern/emu/main.c @@ -190,13 +190,16 @@ main (int argc, char *argv[]) grub_emu_init (); grub_console_init (); grub_host_init (); - grub_hostfs_init (); /* XXX: This is a bit unportable. */ grub_util_biosdisk_init (dev_map); grub_init_all (); + grub_hostfs_init (); + + grub_emu_post_init (); + /* Make sure that there is a root device. */ if (! root_dev) { diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c index 82f579616..4630d335d 100644 --- a/grub-core/kern/emu/misc.c +++ b/grub-core/kern/emu/misc.c @@ -16,6 +16,7 @@ * along with GRUB. If not, see . */ +#include #include #include @@ -61,6 +62,15 @@ # include #endif +#ifdef HAVE_SYS_MNTTAB_H +# include /* Needed by sys/mnttab.h. */ +# include +#endif + +#ifdef HAVE_SYS_MKDEV_H +# include /* makedev */ +#endif + int verbosity; void @@ -165,7 +175,7 @@ asprintf (char **buf, const char *fmt, ...) va_list ap; va_start (ap, fmt); - status = vasprintf (*buf, fmt, ap); + status = vasprintf (buf, fmt, ap); va_end (ap); return status; @@ -282,18 +292,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) diff --git a/grub-core/kern/emu/mm.c b/grub-core/kern/emu/mm.c index 0e9e9f3a8..6a70efb4c 100644 --- a/grub-core/kern/emu/mm.c +++ b/grub-core/kern/emu/mm.c @@ -16,6 +16,8 @@ * along with GRUB. If not, see . */ +#include + #include #include #include diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c index e17c35f95..c93fbf737 100644 --- a/grub-core/kern/file.c +++ b/grub-core/kern/file.c @@ -24,6 +24,9 @@ #include #include +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; } diff --git a/grub-core/kern/i386/coreboot/init.c b/grub-core/kern/i386/coreboot/init.c index 75f385b56..434b9b5a8 100644 --- a/grub-core/kern/i386/coreboot/init.c +++ b/grub-core/kern/i386/coreboot/init.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -64,8 +65,10 @@ grub_machine_init (void) /* Initialize the console as early as possible. */ grub_vga_text_init (); - auto int NESTED_FUNC_ATTR heap_init (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + auto int NESTED_FUNC_ATTR heap_init (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); + int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) { #if GRUB_CPU_SIZEOF_VOID_P == 4 /* Restrict ourselves to 32-bit memory space. */ @@ -75,7 +78,7 @@ grub_machine_init (void) size = GRUB_ULONG_MAX - addr; #endif - if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + if (type != GRUB_MEMORY_AVAILABLE) return 0; /* Avoid the lower memory. */ diff --git a/grub-core/kern/i386/coreboot/mmap.c b/grub-core/kern/i386/coreboot/mmap.c index d06627a08..8b0b20265 100644 --- a/grub-core/kern/i386/coreboot/mmap.c +++ b/grub-core/kern/i386/coreboot/mmap.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -74,7 +75,7 @@ signature_found: } grub_err_t -grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) +grub_machine_mmap_iterate (grub_memory_hook_t hook) { mem_region_t mem_region; diff --git a/grub-core/kern/i386/coreboot/startup.S b/grub-core/kern/i386/coreboot/startup.S index ec3a0e64b..cac023ddf 100644 --- a/grub-core/kern/i386/coreboot/startup.S +++ b/grub-core/kern/i386/coreboot/startup.S @@ -17,6 +17,8 @@ */ #include +/* For stack parameters. */ +#include #include #include #include @@ -51,7 +53,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). diff --git a/grub-core/kern/i386/ieee1275/startup.S b/grub-core/kern/i386/ieee1275/startup.S index 2a04753df..82087323b 100644 --- a/grub-core/kern/i386/ieee1275/startup.S +++ b/grub-core/kern/i386/ieee1275/startup.S @@ -17,7 +17,7 @@ */ #include -#include +#include #include #include #include @@ -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) diff --git a/grub-core/kern/i386/multiboot_mmap.c b/grub-core/kern/i386/multiboot_mmap.c index 0f463c23c..7f4bc3b5c 100644 --- a/grub-core/kern/i386/multiboot_mmap.c +++ b/grub-core/kern/i386/multiboot_mmap.c @@ -16,15 +16,12 @@ * along with GRUB. If not, see . */ -#include #include #include #include #include #include -grub_size_t grub_lower_mem, grub_upper_mem; - /* A pointer to the MBI in its initial location. */ struct multiboot_info *startup_multiboot_info; @@ -57,21 +54,10 @@ grub_machine_mmap_init () } grub_memmove (mmap_entries, (void *) kern_multiboot_info.mmap_addr, kern_multiboot_info.mmap_length); kern_multiboot_info.mmap_addr = (grub_uint32_t) mmap_entries; - - if ((kern_multiboot_info.flags & MULTIBOOT_INFO_MEMORY) == 0) - { - grub_lower_mem = GRUB_MEMORY_MACHINE_LOWER_USABLE; - grub_upper_mem = 0; - } - else - { - grub_lower_mem = kern_multiboot_info.mem_lower * 1024; - grub_upper_mem = kern_multiboot_info.mem_upper * 1024; - } } grub_err_t -grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) +grub_machine_mmap_iterate (grub_memory_hook_t hook) { struct multiboot_mmap_entry *entry = (void *) kern_multiboot_info.mmap_addr; diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c index 57e33569e..122c2c556 100644 --- a/grub-core/kern/i386/pc/init.c +++ b/grub-core/kern/i386/pc/init.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -171,11 +171,6 @@ grub_machine_init (void) if (grub_lower_mem < GRUB_MEMORY_MACHINE_RESERVED_END) grub_fatal ("too small memory"); -#if 0 - /* Turn on Gate A20 to access >1MB. */ - grub_gate_a20 (1); -#endif - /* FIXME: This prevents loader/i386/linux.c from using low memory. When our heap implements support for requesting a chunk in low memory, this should no longer be a problem. */ @@ -186,8 +181,10 @@ grub_machine_init (void) grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END); #endif - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) { /* Avoid the lower memory. */ if (addr < 0x100000) @@ -200,7 +197,7 @@ grub_machine_init (void) } /* Ignore >4GB. */ - if (addr <= 0xFFFFFFFF && type == GRUB_MACHINE_MEMORY_AVAILABLE) + if (addr <= 0xFFFFFFFF && type == GRUB_MEMORY_AVAILABLE) { grub_size_t len; diff --git a/grub-core/kern/i386/pc/mmap.c b/grub-core/kern/i386/pc/mmap.c index b174bc441..a305d4511 100644 --- a/grub-core/kern/i386/pc/mmap.c +++ b/grub-core/kern/i386/pc/mmap.c @@ -16,13 +16,26 @@ * along with GRUB. If not, see . */ -#include -#include #include +#include #include #include #include +struct grub_machine_mmap_entry +{ + grub_uint32_t size; + grub_uint64_t addr; + grub_uint64_t len; +#define GRUB_MACHINE_MEMORY_AVAILABLE 1 +#define GRUB_MACHINE_MEMORY_RESERVED 2 +#define GRUB_MACHINE_MEMORY_ACPI 3 +#define GRUB_MACHINE_MEMORY_NVS 4 +#define GRUB_MACHINE_MEMORY_BADRAM 5 + grub_uint32_t type; +} __attribute__((packed)); + + /* * grub_get_ext_memsize() : return the extended memory size in KB. * BIOS call "INT 15H, AH=88H" to get extended memory size @@ -110,7 +123,7 @@ grub_get_mmap_entry (struct grub_machine_mmap_entry *entry, } grub_err_t -grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) +grub_machine_mmap_iterate (grub_memory_hook_t hook) { grub_uint32_t cont; struct grub_machine_mmap_entry *entry @@ -125,9 +138,9 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin do { if (hook (entry->addr, entry->len, - /* Multiboot mmaps have been defined to match with the E820 definition. + /* GRUB mmaps have been defined to match with the E820 definition. Therefore, we can just pass type through. */ - entry->type)) + ((entry->type <= GRUB_MACHINE_MEMORY_BADRAM) && (entry->type >= GRUB_MACHINE_MEMORY_AVAILABLE)) ? entry->type : GRUB_MEMORY_RESERVED)) break; if (! cont) @@ -144,11 +157,12 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin if (eisa_mmap) { - if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10, GRUB_MACHINE_MEMORY_AVAILABLE) == 0) - hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MACHINE_MEMORY_AVAILABLE); + if (hook (0x100000, (eisa_mmap & 0xFFFF) << 10, + GRUB_MEMORY_AVAILABLE) == 0) + hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MEMORY_AVAILABLE); } else - hook (0x100000, grub_get_ext_memsize () << 10, GRUB_MACHINE_MEMORY_AVAILABLE); + hook (0x100000, grub_get_ext_memsize () << 10, GRUB_MEMORY_AVAILABLE); } return 0; diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S index b5e9a9b85..46e6b1fac 100644 --- a/grub-core/kern/i386/pc/startup.S +++ b/grub-core/kern/i386/pc/startup.S @@ -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: @@ -210,7 +202,7 @@ LOCAL (codestart): .code32 incl %eax - call EXT_C(grub_gate_a20) + call grub_gate_a20 #ifdef ENABLE_LZMA movl $GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR, %edi @@ -300,7 +292,7 @@ VARIABLE(grub_boot_drive) * It also eats any keystrokes in the keyboard buffer. :-( */ -FUNCTION(grub_gate_a20) +grub_gate_a20: movl %eax, %edx gate_a20_test_current_state: @@ -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() @@ -476,7 +478,7 @@ FUNCTION(grub_chainloader_real_boot) /* Turn off Gate A20 */ xorl %eax, %eax - call EXT_C(grub_gate_a20) + call grub_gate_a20 /* set up to pass boot drive */ popl %edx @@ -574,62 +576,29 @@ FUNCTION(grub_console_putchar) ret +LOCAL(bypass_table): + .word 0x0100 | '\e',0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r' + .word 0x1c00 | '\n' +LOCAL(bypass_table_end): + /* * int grub_console_getkey (void) + * if there is a character pending, return it; otherwise return -1 + * BIOS call "INT 16H Function 01H" to check whether a character is pending + * Call with %ah = 0x1 + * Return: + * If key waiting to be input: + * %ah = keyboard scan code + * %al = ASCII character + * Zero flag = clear + * else + * Zero flag = set * BIOS call "INT 16H Function 00H" to read character from keyboard * Call with %ah = 0x0 * Return: %ah = keyboard scan code * %al = ASCII character */ -/* this table is used in translate_keycode below */ -LOCAL (translation_table): - .word GRUB_CONSOLE_KEY_LEFT, GRUB_TERM_LEFT - .word GRUB_CONSOLE_KEY_RIGHT, GRUB_TERM_RIGHT - .word GRUB_CONSOLE_KEY_UP, GRUB_TERM_UP - .word GRUB_CONSOLE_KEY_DOWN, GRUB_TERM_DOWN - .word GRUB_CONSOLE_KEY_HOME, GRUB_TERM_HOME - .word GRUB_CONSOLE_KEY_END, GRUB_TERM_END - .word GRUB_CONSOLE_KEY_DC, GRUB_TERM_DC - .word GRUB_CONSOLE_KEY_BACKSPACE, GRUB_TERM_BACKSPACE - .word GRUB_CONSOLE_KEY_PPAGE, GRUB_TERM_PPAGE - .word GRUB_CONSOLE_KEY_NPAGE, GRUB_TERM_NPAGE - .word 0 - -/* - * translate_keycode translates the key code %dx to an ascii code. - */ - .code16 - -translate_keycode: - pushw %bx - pushw %si - -#ifdef __APPLE__ - movw $(ABS(LOCAL (translation_table)) - 0x10000), %si -#else - movw $ABS(LOCAL (translation_table)), %si -#endif - -1: lodsw - /* check if this is the end */ - testw %ax, %ax - jz 2f - /* load the ascii code into %ax */ - movw %ax, %bx - lodsw - /* check if this matches the key code */ - cmpw %bx, %dx - jne 1b - /* translate %dx, if successful */ - movw %ax, %dx - -2: popw %si - popw %bx - ret - - .code32 - FUNCTION(grub_console_getkey) pushl %ebp @@ -643,70 +612,54 @@ FUNCTION(grub_console_getkey) * INT 16/AH = 1 before calling INT 16/AH = 0. */ -1: movb $1, %ah int $0x16 - jnz 2f - hlt - jmp 1b - -2: + jz notpending movb $0, %ah int $0x16 + xorl %edx, %edx movw %ax, %dx /* real_to_prot uses %eax */ - call translate_keycode DATA32 call real_to_prot .code32 - movw %dx, %ax - - popl %ebp - ret - - -/* - * int grub_console_checkkey (void) - * if there is a character pending, return it; otherwise return -1 - * BIOS call "INT 16H Function 01H" to check whether a character is pending - * Call with %ah = 0x1 - * Return: - * If key waiting to be input: - * %ah = keyboard scan code - * %al = ASCII character - * Zero flag = clear - * else - * Zero flag = set - */ -FUNCTION(grub_console_checkkey) - pushl %ebp - xorl %edx, %edx - - call prot_to_real /* enter real mode */ - .code16 - - movb $0x1, %ah - int $0x16 - - jz notpending - - movw %ax, %dx - DATA32 jmp pending - -notpending: - decl %edx - -pending: - DATA32 call real_to_prot - .code32 + movl $0xff, %eax + testl %eax, %edx + jz 1f + andl %edx, %eax + cmp %eax, 0x20 + ja 2f movl %edx, %eax + leal LOCAL(bypass_table), %esi + movl $((LOCAL(bypass_table_end) - LOCAL(bypass_table)) / 2), %ecx + repne cmpsw + jz 3f + addl $('a' - 1 | GRUB_TERM_CTRL), %eax + jmp 2f +3: + andl $0xff, %eax + jmp 2f + +1: movl %edx, %eax + shrl $8, %eax + orl $GRUB_TERM_EXTENDED, %eax +2: popl %ebp ret +notpending: + .code16 + DATA32 call real_to_prot + .code32 +#if GRUB_TERM_NO_KEY != 0 +#error Fix this asm code +#endif + jmp 2b + /* * grub_uint16_t grub_console_getxy (void) diff --git a/grub-core/kern/i386/qemu/mmap.c b/grub-core/kern/i386/qemu/mmap.c index f8b4b9b4f..208f36b7e 100644 --- a/grub-core/kern/i386/qemu/mmap.c +++ b/grub-core/kern/i386/qemu/mmap.c @@ -16,12 +16,14 @@ * along with GRUB. If not, see . */ +#include #include #include #include #include #include #include +#include #define QEMU_CMOS_MEMSIZE_HIGH 0x35 #define QEMU_CMOS_MEMSIZE_LOW 0x34 @@ -60,38 +62,38 @@ grub_machine_mmap_init () } grub_err_t -grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) +grub_machine_mmap_iterate (grub_memory_hook_t hook) { if (hook (0x0, (grub_addr_t) _start, - GRUB_MACHINE_MEMORY_AVAILABLE)) + GRUB_MEMORY_AVAILABLE)) return 1; if (hook ((grub_addr_t) _end, 0xa0000 - (grub_addr_t) _end, - GRUB_MACHINE_MEMORY_AVAILABLE)) + GRUB_MEMORY_AVAILABLE)) return 1; if (hook (GRUB_MEMORY_MACHINE_UPPER, 0x100000 - GRUB_MEMORY_MACHINE_UPPER, - GRUB_MACHINE_MEMORY_RESERVED)) + GRUB_MEMORY_RESERVED)) return 1; /* Everything else is free. */ if (hook (0x100000, min (mem_size, (grub_uint32_t) -GRUB_BOOT_MACHINE_SIZE) - 0x100000, - GRUB_MACHINE_MEMORY_AVAILABLE)) + GRUB_MEMORY_AVAILABLE)) return 1; /* Protect boot.img, which contains the gdt. It is mapped at the top of memory (it is also mapped below 0x100000, but we already reserved that area). */ if (hook ((grub_uint32_t) -GRUB_BOOT_MACHINE_SIZE, GRUB_BOOT_MACHINE_SIZE, - GRUB_MACHINE_MEMORY_RESERVED)) + GRUB_MEMORY_RESERVED)) return 1; if (above_4g != 0 && hook (0x100000000ULL, above_4g, - GRUB_MACHINE_MEMORY_AVAILABLE)) + GRUB_MEMORY_AVAILABLE)) return 1; return 0; diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S index e705953b5..7834d1df5 100644 --- a/grub-core/kern/i386/qemu/startup.S +++ b/grub-core/kern/i386/qemu/startup.S @@ -18,6 +18,8 @@ #include #include + +#include #include #include @@ -39,7 +41,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. diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c index d3c3a8d88..30eacbbdd 100644 --- a/grub-core/kern/ieee1275/cmain.c +++ b/grub-core/kern/ieee1275/cmain.c @@ -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)) { diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index 99ce7179b..682a8b5a4 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -32,6 +32,7 @@ #include #include #include +#include /* The minimal heap size we can live with. */ #define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) @@ -126,8 +127,10 @@ static void grub_claim_heap (void) { unsigned long total = 0; - auto int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type); - int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type) + auto int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len, + grub_memory_type_t type); + int NESTED_FUNC_ATTR heap_init (grub_uint64_t addr, grub_uint64_t len, + grub_memory_type_t type) { if (type != 1) return 0; @@ -189,31 +192,6 @@ static void grub_claim_heap (void) grub_machine_mmap_iterate (heap_init); } -#ifdef __i386__ - -grub_uint32_t grub_upper_mem; - -/* We need to call this before grub_claim_memory. */ -static void -grub_get_extended_memory (void) -{ - auto int NESTED_FUNC_ATTR find_ext_mem (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type); - int NESTED_FUNC_ATTR find_ext_mem (grub_uint64_t addr, grub_uint64_t len, grub_uint32_t type) - { - if (type == 1 && addr == 0x100000) - { - grub_upper_mem = len; - return 1; - } - - return 0; - } - - grub_machine_mmap_iterate (find_ext_mem); -} - -#endif - static grub_uint64_t ieee1275_get_time_ms (void); void @@ -225,9 +203,6 @@ grub_machine_init (void) grub_ieee1275_init (); grub_console_init_early (); -#ifdef __i386__ - grub_get_extended_memory (); -#endif grub_claim_heap (); grub_console_init_lately (); grub_ofdisk_init (); diff --git a/grub-core/kern/ieee1275/mmap.c b/grub-core/kern/ieee1275/mmap.c index 6f0652770..942e5a354 100644 --- a/grub-core/kern/ieee1275/mmap.c +++ b/grub-core/kern/ieee1275/mmap.c @@ -16,12 +16,12 @@ * along with GRUB. If not, see . */ -#include +#include #include #include grub_err_t -grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) +grub_machine_mmap_iterate (grub_memory_hook_t hook) { grub_ieee1275_phandle_t root; grub_ieee1275_phandle_t memory; @@ -66,7 +66,7 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin if (size_cells == 2) size = (size << 32) | available[i++]; - if (hook (address, size, GRUB_MACHINE_MEMORY_AVAILABLE)) + if (hook (address, size, GRUB_MEMORY_AVAILABLE)) break; } diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c index fcd43f617..f5dc8efb1 100644 --- a/grub-core/kern/ieee1275/openfw.c +++ b/grub-core/kern/ieee1275/openfw.c @@ -423,3 +423,47 @@ grub_reboot (void) for (;;) ; } #endif + +/* Resolve aliases. */ +char * +grub_ieee1275_canonicalise_devname (const char *path) +{ + struct canon_args + { + struct grub_ieee1275_common_hdr common; + grub_ieee1275_cell_t path; + grub_ieee1275_cell_t buf; + grub_ieee1275_cell_t inlen; + grub_ieee1275_cell_t outlen; + } + args; + char *buf = NULL; + grub_size_t bufsize = 64; + int i; + + for (i = 0; i < 2; i++) + { + grub_free (buf); + + buf = grub_malloc (bufsize); + if (!buf) + return NULL; + + INIT_IEEE1275_COMMON (&args.common, "canon", 3, 1); + args.path = (grub_ieee1275_cell_t) path; + args.buf = (grub_ieee1275_cell_t) buf; + args.inlen = (grub_ieee1275_cell_t) (bufsize - 1); + + if (IEEE1275_CALL_ENTRY_FN (&args) == -1) + return 0; + if (args.outlen > bufsize - 1) + { + bufsize = args.outlen + 2; + continue; + } + return buf; + } + /* Shouldn't reach here. */ + grub_free (buf); + return NULL; +} diff --git a/grub-core/kern/mips/qemu-mips/init.c b/grub-core/kern/mips/qemu-mips/init.c index 866c7a82a..f2bb652a8 100644 --- a/grub-core/kern/mips/qemu-mips/init.c +++ b/grub-core/kern/mips/qemu-mips/init.c @@ -51,11 +51,8 @@ grub_reboot (void) } grub_err_t -grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, - grub_uint64_t, - grub_uint32_t)) +grub_machine_mmap_iterate (grub_memory_hook_t hook) { - hook (0, RAMSIZE, - GRUB_MACHINE_MEMORY_AVAILABLE); + hook (0, RAMSIZE, GRUB_MEMORY_AVAILABLE); return GRUB_ERR_NONE; } diff --git a/grub-core/kern/mips/startup.S b/grub-core/kern/mips/startup.S index 134853a9d..6811353ea 100644 --- a/grub-core/kern/mips/startup.S +++ b/grub-core/kern/mips/startup.S @@ -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 diff --git a/grub-core/kern/mips/yeeloong/init.c b/grub-core/kern/mips/yeeloong/init.c index 523f90282..cc7c16806 100644 --- a/grub-core/kern/mips/yeeloong/init.c +++ b/grub-core/kern/mips/yeeloong/init.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ extern void grub_gfxterm_init (void); extern void grub_at_keyboard_init (void); extern void grub_serial_init (void); extern void grub_terminfo_init (void); +extern void grub_keylayouts_init (void); /* FIXME: use interrupt to count high. */ grub_uint64_t @@ -57,14 +59,12 @@ grub_get_rtc (void) } grub_err_t -grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, - grub_uint64_t, - grub_uint32_t)) +grub_machine_mmap_iterate (grub_memory_hook_t hook) { hook (GRUB_ARCH_LOWMEMPSTART, grub_arch_memsize << 20, - GRUB_MACHINE_MEMORY_AVAILABLE); + GRUB_MEMORY_AVAILABLE); hook (GRUB_ARCH_HIGHMEMPSTART, grub_arch_highmemsize << 20, - GRUB_MACHINE_MEMORY_AVAILABLE); + GRUB_MEMORY_AVAILABLE); return GRUB_ERR_NONE; } @@ -205,6 +205,7 @@ grub_machine_init (void) grub_font_init (); grub_gfxterm_init (); + grub_keylayouts_init (); grub_at_keyboard_init (); grub_terminfo_init (); diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c index 69fdc3d42..37ce8decd 100644 --- a/grub-core/kern/misc.c +++ b/grub-core/kern/misc.c @@ -196,6 +196,8 @@ grub_vprintf (const char *fmt, va_list args) grub_size_t s; static char buf[PREALLOC_SIZE + 1]; char *curbuf = buf; + va_list ap2; + va_copy (ap2, args); s = grub_vsnprintf_real (buf, PREALLOC_SIZE, fmt, args); if (s > PREALLOC_SIZE) @@ -210,7 +212,7 @@ grub_vprintf (const char *fmt, va_list args) buf[PREALLOC_SIZE] = 0; } else - s = grub_vsnprintf_real (curbuf, s, fmt, args); + s = grub_vsnprintf_real (curbuf, s, fmt, ap2); } grub_xputs (curbuf); @@ -947,11 +949,13 @@ grub_xvasprintf (const char *fmt, va_list ap) while (1) { + va_list ap2; + va_copy (ap2, ap); ret = grub_malloc (as + 1); if (!ret) return NULL; - s = grub_vsnprintf_real (ret, as, fmt, ap); + s = grub_vsnprintf_real (ret, as, fmt, ap2); if (s <= as) return ret; @@ -990,12 +994,12 @@ 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 -#if defined(NEED_ENABLE_EXECUTE_STACK) && !defined(GRUB_UTIL) && !defined(GRUB_MACHINE_EMU) +#if NEED_ENABLE_EXECUTE_STACK && !defined(GRUB_UTIL) && !defined(GRUB_MACHINE_EMU) /* Some gcc versions generate a call to this function in trampolines for nested functions. */ void __enable_execute_stack (void *addr __attribute__ ((unused))) @@ -1003,7 +1007,7 @@ void __enable_execute_stack (void *addr __attribute__ ((unused))) } #endif -#if defined (NEED_REGISTER_FRAME_INFO) && !defined(GRUB_UTIL) +#if NEED_REGISTER_FRAME_INFO && !defined(GRUB_UTIL) void __register_frame_info (void) { } diff --git a/grub-core/kern/powerpc/ieee1275/startup.S b/grub-core/kern/powerpc/ieee1275/startup.S index 526df1d91..0b1c23346 100644 --- a/grub-core/kern/powerpc/ieee1275/startup.S +++ b/grub-core/kern/powerpc/ieee1275/startup.S @@ -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 diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c index 531fcc8fa..a81008579 100644 --- a/grub-core/kern/rescue_reader.c +++ b/grub-core/kern/rescue_reader.c @@ -39,7 +39,7 @@ grub_rescue_read_line (char **line, int cont) grub_printf ((cont) ? "> " : "grub rescue> "); grub_memset (linebuf, 0, GRUB_RESCUE_BUF_SIZE); - while ((c = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && c != '\r') + while ((c = grub_getkey ()) != '\n' && c != '\r') { if (grub_isprint (c)) { diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S index f0f47416d..cebdca2b6 100644 --- a/grub-core/kern/sparc64/ieee1275/crt0.S +++ b/grub-core/kern/sparc64/ieee1275/crt0.S @@ -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. @@ -61,9 +61,11 @@ codestart: /* Save ieee1275 stack for future use by booter. */ mov %o6, %o1 /* Our future stack. */ - sethi %hi(GRUB_KERNEL_MACHINE_STACK_SIZE - 2047), %o5 - or %o5, %lo(GRUB_KERNEL_MACHINE_STACK_SIZE - 2047), %o5 + sethi %hi(GRUB_KERNEL_MACHINE_STACK_SIZE), %o5 + or %o5, %lo(GRUB_KERNEL_MACHINE_STACK_SIZE), %o5 add %o3, %o5, %o6 + and %o6, ~0xff, %o6 + sub %o6, 2047, %o6 sub %o2, 4, %o2 sub %o3, 4, %o3 diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c index 360539e50..7b3593161 100644 --- a/grub-core/kern/term.c +++ b/grub-core/kern/term.c @@ -78,65 +78,48 @@ grub_xputs_dumb (const char *str) void (*grub_xputs) (const char *str) = grub_xputs_dumb; -int -grub_getkey (void) -{ - grub_term_input_t term; - - grub_refresh (); - - while (1) - { - if (grub_term_poll_usb) - grub_term_poll_usb (); - - FOR_ACTIVE_TERM_INPUTS(term) - { - int key = term->checkkey (term); - if (key != -1) - return term->getkey (term); - } - - grub_cpu_idle (); - } -} +static int pending_key = GRUB_TERM_NO_KEY; int grub_checkkey (void) { grub_term_input_t term; + if (pending_key != GRUB_TERM_NO_KEY) + return pending_key; + if (grub_term_poll_usb) grub_term_poll_usb (); FOR_ACTIVE_TERM_INPUTS(term) { - int key = term->checkkey (term); - if (key != -1) - return key; + pending_key = term->getkey (term); + if (pending_key != GRUB_TERM_NO_KEY) + return pending_key; } return -1; } int -grub_getkeystatus (void) +grub_getkey (void) { - int status = 0; - grub_term_input_t term; + int ret; - if (grub_term_poll_usb) - grub_term_poll_usb (); + grub_refresh (); - FOR_ACTIVE_TERM_INPUTS(term) - { - if (term->getkeystatus) - status |= term->getkeystatus (term); - } - - return status; + grub_checkkey (); + while (pending_key == GRUB_TERM_NO_KEY) + { + grub_cpu_idle (); + grub_checkkey (); + } + ret = pending_key; + pending_key = GRUB_TERM_NO_KEY; + return ret; } + void grub_refresh (void) { diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c index a9b8a520e..f487de7ad 100644 --- a/grub-core/lib/arg.c +++ b/grub-core/lib/arg.c @@ -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; + } } } @@ -223,17 +231,21 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, { int curarg; int arglen; - int complete = 0; char **argl = 0; int num = 0; auto grub_err_t add_arg (char *s); 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; } @@ -245,7 +257,8 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, char *option = 0; /* No option is used. */ - if (arg[0] != '-' || grub_strlen (arg) == 1) + if ((num && GRUB_COMMAND_OPTIONS_AT_START) + || arg[0] != '-' || grub_strlen (arg) == 1) { if (add_arg (arg) != 0) goto fail; @@ -256,11 +269,28 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, /* One or more short options. */ if (arg[1] != '-') { - char *curshort = arg + 1; + char *curshort; + + if (cmd->cmd->flags & GRUB_COMMAND_ACCEPT_DASH) + { + for (curshort = arg + 1; *curshort; curshort++) + if (!find_short (cmd->options, *curshort)) + break; + + if (*curshort) + { + if (add_arg (arg) != 0) + goto fail; + continue; + } + } + + curshort = arg + 1; while (1) { opt = find_short (cmd->options, *curshort); + if (! opt) { grub_error (GRUB_ERR_BAD_ARGUMENT, @@ -310,10 +340,21 @@ 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 && (cmd->cmd->flags & GRUB_COMMAND_ACCEPT_DASH)) + { + if (add_arg (arg) != 0) + goto fail; + continue; + } + if (! opt) { grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown argument `%s'", arg); @@ -382,11 +423,50 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, } } - complete = 1; - *args = argl; *argnum = num; + return 1; fail: - return complete; + return 0; +} + +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; } diff --git a/grub-core/lib/crc.c b/grub-core/lib/crc.c deleted file mode 100644 index bc0d8aa8d..000000000 --- a/grub-core/lib/crc.c +++ /dev/null @@ -1,75 +0,0 @@ -/* crc.c - crc function */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include - -static grub_uint32_t crc32_table [256]; - -static void -init_crc32_table (void) -{ - auto grub_uint32_t reflect (grub_uint32_t ref, int len); - grub_uint32_t reflect (grub_uint32_t ref, int len) - { - grub_uint32_t result = 0; - int i; - - for (i = 1; i <= len; i++) - { - if (ref & 1) - result |= 1 << (len - i); - ref >>= 1; - } - - return result; - } - - grub_uint32_t polynomial = 0x04c11db7; - int i, j; - - for(i = 0; i < 256; i++) - { - crc32_table[i] = reflect(i, 8) << 24; - for (j = 0; j < 8; j++) - crc32_table[i] = (crc32_table[i] << 1) ^ - (crc32_table[i] & (1 << 31) ? polynomial : 0); - crc32_table[i] = reflect(crc32_table[i], 32); - } -} - -grub_uint32_t -grub_getcrc32 (grub_uint32_t crc, void *buf, int size) -{ - int i; - grub_uint8_t *data = buf; - - if (! crc32_table[1]) - init_crc32_table (); - - crc^= 0xffffffff; - - for (i = 0; i < size; i++) - { - crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ *data]; - data++; - } - - return crc ^ 0xffffffff; -} diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c index 6bd038168..f5768b8b5 100644 --- a/grub-core/lib/crypto.c +++ b/grub-core/lib/crypto.c @@ -420,7 +420,7 @@ grub_password_get (char buf[], unsigned buf_size) while (1) { - key = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + key = grub_getkey (); if (key == '\n' || key == '\r') break; diff --git a/grub-core/lib/efi/halt.c b/grub-core/lib/efi/halt.c index ed3e1e1c0..c19536897 100644 --- a/grub-core/lib/efi/halt.c +++ b/grub-core/lib/efi/halt.c @@ -22,11 +22,13 @@ #include #include #include +#include void grub_halt (void) { grub_machine_fini (); + grub_acpi_halt (); efi_call_4 (grub_efi_system_table->runtime_services->reset_system, GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL); diff --git a/grub-core/lib/i386/halt.c b/grub-core/lib/i386/halt.c index 74e0c7301..15c4ba0d6 100644 --- a/grub-core/lib/i386/halt.c +++ b/grub-core/lib/i386/halt.c @@ -18,6 +18,7 @@ #include #include +#include const char bochs_shutdown[] = "Shutdown"; @@ -40,6 +41,10 @@ grub_halt (void) { unsigned int i; +#if defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_MULTIBOOT) + grub_acpi_halt (); +#endif + /* Disable interrupts. */ __asm__ __volatile__ ("cli"); diff --git a/grub-core/lib/i386/pc/vesa_modes_table.c b/grub-core/lib/i386/pc/vesa_modes_table.c new file mode 100644 index 000000000..6dc4b7d8d --- /dev/null +++ b/grub-core/lib/i386/pc/vesa_modes_table.c @@ -0,0 +1,127 @@ + +#include + +/* This is the reverse of the table in [linux]/Documentation/fb/vesafb.txt + plus a few more modes based on the table in + http://en.wikipedia.org/wiki/VESA_BIOS_Extensions */ +struct grub_vesa_mode_table_entry +grub_vesa_mode_table[GRUB_VESA_MODE_TABLE_END + - GRUB_VESA_MODE_TABLE_START + 1] = + { + { 640, 400, 8 }, /* 0x300 */ + { 640, 480, 8 }, /* 0x301 */ + { 800, 600, 4 }, /* 0x302 */ + { 800, 600, 8 }, /* 0x303 */ + { 1024, 768, 4 }, /* 0x304 */ + { 1024, 768, 8 }, /* 0x305 */ + { 1280, 1024, 4 }, /* 0x306 */ + { 1280, 1024, 8 }, /* 0x307 */ + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 320, 200, 15 }, /* 0x30d */ + { 320, 200, 16 }, /* 0x30e */ + { 320, 200, 24 }, /* 0x30f */ + { 640, 480, 15 }, /* 0x310 */ + { 640, 480, 16 }, /* 0x311 */ + { 640, 480, 24 }, /* 0x312 */ + { 800, 600, 15 }, /* 0x313 */ + { 800, 600, 16 }, /* 0x314 */ + { 800, 600, 24 }, /* 0x315 */ + { 1024, 768, 15 }, /* 0x316 */ + { 1024, 768, 16 }, /* 0x317 */ + { 1024, 768, 24 }, /* 0x318 */ + { 1280, 1024, 15 }, /* 0x319 */ + { 1280, 1024, 16 }, /* 0x31a */ + { 1280, 1024, 24 }, /* 0x31b */ + { 1600, 1200, 8 }, /* 0x31c */ + { 1600, 1200, 15 }, /* 0x31d */ + { 1600, 1200, 16 }, /* 0x31e */ + { 1600, 1200, 24 }, /* 0x31f */ + { 0, 0, 0 }, + { 640, 400, 15 }, /* 0x321 */ + { 640, 400, 16 }, /* 0x322 */ + { 640, 400, 24 }, /* 0x323 */ + { 640, 400, 32 }, /* 0x324 */ + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 640, 480, 32 }, /* 0x329 */ + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 896, 672, 8 }, /* 0x32f */ + { 896, 672, 15 }, /* 0x330 */ + { 896, 672, 16 }, /* 0x331 */ + { 896, 672, 24 }, /* 0x332 */ + { 896, 672, 32 }, /* 0x333 */ + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 1600, 1200, 32 }, /* 0x342 */ + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 1440, 900, 8 }, /* 0x360 */ + { 1440, 900, 15 }, /* 0x361 */ + { 1440, 900, 16 }, /* 0x362 */ + { 1440, 900, 24 }, /* 0x363 */ + { 1440, 900, 32 }, /* 0x364 */ + { 1152, 720, 8 }, /* 0x365 */ + { 1152, 720, 15 }, /* 0x366 */ + { 1152, 720, 16 }, /* 0x367 */ + { 1152, 720, 24 }, /* 0x368 */ + { 1152, 720, 32 }, /* 0x369 */ + { 1024, 640, 8 }, /* 0x36a */ + { 1024, 640, 15 }, /* 0x36b */ + { 1024, 640, 16 }, /* 0x36c */ + { 1024, 640, 24 }, /* 0x36d */ + { 1024, 640, 32 }, /* 0x36e */ + { 800, 500, 8 }, /* 0x36f */ + { 800, 500, 15 }, /* 0x370 */ + { 800, 500, 16 }, /* 0x371 */ + { 800, 500, 24 }, /* 0x372 */ + { 800, 500, 32 }, /* 0x373 */ + }; diff --git a/grub-core/lib/i386/relocator.c b/grub-core/lib/i386/relocator.c index f06a6ef86..1bc4240c3 100644 --- a/grub-core/lib/i386/relocator.c +++ b/grub-core/lib/i386/relocator.c @@ -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)); diff --git a/grub-core/lib/i386/relocator32.S b/grub-core/lib/i386/relocator32.S index b581305a5..09ce56ad0 100644 --- a/grub-core/lib/i386/relocator32.S +++ b/grub-core/lib/i386/relocator32.S @@ -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) diff --git a/grub-core/lib/ieee1275/relocator.c b/grub-core/lib/ieee1275/relocator.c index 947346d46..c09f1e9c5 100644 --- a/grub-core/lib/ieee1275/relocator.c +++ b/grub-core/lib/ieee1275/relocator.c @@ -27,10 +27,10 @@ grub_relocator_firmware_get_max_events (void) int counter = 0; auto int NESTED_FUNC_ATTR count (grub_uint64_t addr __attribute__ ((unused)), grub_uint64_t len __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))); + grub_memory_type_t type __attribute__ ((unused))); int NESTED_FUNC_ATTR count (grub_uint64_t addr __attribute__ ((unused)), grub_uint64_t len __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) + grub_memory_type_t type __attribute__ ((unused))) { counter++; return 0; @@ -47,11 +47,11 @@ grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events) { int counter = 0; auto int NESTED_FUNC_ATTR fill (grub_uint64_t addr, grub_uint64_t len, - grub_uint32_t type); + grub_memory_type_t type); int NESTED_FUNC_ATTR fill (grub_uint64_t addr, grub_uint64_t len, - grub_uint32_t type) + grub_memory_type_t type) { - if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + if (type != GRUB_MEMORY_AVAILABLE) return 0; if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM)) diff --git a/grub-core/lib/legacy_parse.c b/grub-core/lib/legacy_parse.c new file mode 100644 index 000000000..6ad15dc49 --- /dev/null +++ b/grub-core/lib/legacy_parse.c @@ -0,0 +1,698 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,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 . + */ + +#include +#include +#include +#include +#include +#include + +struct legacy_command +{ + const char *name; + const char *map; + const char *suffix; + unsigned suffixarg; + unsigned argc; + enum arg_type { + TYPE_VERBATIM, + TYPE_FORCE_OPTION, + TYPE_NOAPM_OPTION, + TYPE_TYPE_OR_NOMEM_OPTION, + TYPE_OPTION, + TYPE_FILE, + TYPE_FILE_NO_CONSUME, + TYPE_PARTITION, + TYPE_BOOL, + TYPE_INT, + TYPE_REST_VERBATIM, + TYPE_VBE_MODE + } argt[4]; + enum { + FLAG_IGNORE_REST = 1, + FLAG_FALLBACK_AVAILABLE = 4, + FLAG_FALLBACK = 8, + FLAG_COLOR_INVERT = 16, + FLAG_NO_MENUENTRY = 32, + FLAG_MENUENTRY_ONLY = 64, + } flags; + const char *shortdesc; + const char *longdesc; +}; + +struct legacy_command legacy_commands[] = + { + {"blocklist", "blocklist '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILE", + "Print the blocklist notation of the file FILE."}, + {"boot", "boot\n", NULL, 0, 0, {}, 0, 0, + "Boot the OS/chain-loader which has been loaded."}, + /* FIXME: bootp unsupported. */ + {"cat", "cat '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILE", + "Print the contents of the file FILE."}, + {"chainloader", "chainloader %s '%s'\n", NULL, 0, + 2, {TYPE_FORCE_OPTION, TYPE_FILE}, 0, "[--force] FILE", + "Load the chain-loader FILE. If --force is specified, then load it" + " forcibly, whether the boot loader signature is present or not."}, + {"cmp", "cmp '%s' '%s'\n", NULL, 0, + 2, {TYPE_FILE, TYPE_FILE}, FLAG_IGNORE_REST, "FILE1 FILE2", + "Compare the file FILE1 with the FILE2 and inform the different values" + " if any."}, + {"color", "set color_normal='%s'; set color_highlight='%s'\n", NULL, 0, + 2, {TYPE_VERBATIM, TYPE_VERBATIM}, + FLAG_IGNORE_REST | FLAG_FALLBACK_AVAILABLE, "NORMAL [HIGHLIGHT]", + "Change the menu colors. The color NORMAL is used for most" + " lines in the menu, and the color HIGHLIGHT is used to highlight the" + " line where the cursor points. If you omit HIGHLIGHT, then the" + " inverted color of NORMAL is used for the highlighted line." + " The format of a color is \"FG/BG\". FG and BG are symbolic color names." + " A symbolic color name must be one of these: black, blue, green," + " cyan, red, magenta, brown, light-gray, dark-gray, light-blue," + " light-green, light-cyan, light-red, light-magenta, yellow and white." + " But only the first eight names can be used for BG. You can prefix" + " \"blink-\" to FG if you want a blinking foreground color."}, + {"color", "set color_normal='%s'; set color_highlight='%s'\n", NULL, 0, + 1, {TYPE_VERBATIM}, + FLAG_IGNORE_REST | FLAG_FALLBACK | FLAG_COLOR_INVERT, NULL, NULL}, + {"configfile", "legacy_configfile '%s'\n", NULL, 0, 1, {TYPE_FILE}, + 0, "FILE", "Load FILE as the configuration file."}, + {"debug", + "if [ -z \"$debug\" ]; then set debug=all; else set debug=; fi\n", NULL, 0, + 0, {}, 0, 0, "Turn on/off the debug mode."}, + {"default", + "set default='%s'; if [ x\"$default\" = xsaved ]; then load_env; " + "set default=\"$saved_entry\"; fi\n", NULL, 0, 1, {TYPE_VERBATIM}, 0, + "[NUM | `saved']", + "Set the default entry to entry number NUM (if not specified, it is" + " 0, the first entry) or the entry number saved by savedefault."}, + /* FIXME: dhcp unsupported. */ + {"displayapm", "lsapm\n", NULL, 0, 0, {}, 0, 0, + "Display APM BIOS information."}, + {"displaymem", "lsmmap\n", NULL, 0, 0, {}, 0, 0, + "Display what GRUB thinks the system address space map of the" + " machine is, including all regions of physical RAM installed."}, + /* NOTE: embed unsupported. */ + {"fallback", "set fallback='%s'\n", NULL, 0, + 1, {TYPE_VERBATIM}, 0, "NUM...", + "Go into unattended boot mode: if the default boot entry has any" + " errors, instead of waiting for the user to do anything, it" + " immediately starts over using the NUM entry (same numbering as the" + " `default' command). This obviously won't help if the machine" + " was rebooted by a kernel that GRUB loaded."}, + {"find", "search -sf '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILENAME", + "Search for the filename FILENAME in all of partitions and print the list of" + " the devices which contain the file."}, + /* FIXME: fstest unsupported. */ + /* NOTE: The obsolete C/H/S geometry isn't shown anymore. */ + {"geometry", "insmod regexp; ls -l (%s*)\n", NULL, 0, 1, {TYPE_VERBATIM}, 0, "DRIVE", + "Print the information for a drive DRIVE. "}, + {"halt", "halt %s\n", NULL, 0, 1, {TYPE_NOAPM_OPTION}, 0, "[--no-apm]", + "Halt your system. If APM is available on it, turn off the power using" + " the APM BIOS, unless you specify the option `--no-apm'."}, + /* FIXME: help unsupported. */ /* NUL_TERMINATE */ + {"hiddenmenu", NULL, + "if sleep -i $timeout; then timeout=0; else timeout=-1; fi\n", 0, + 0, {}, 0, "", "Hide the menu."}, + {"hide", "parttool '%s' hidden+\n", NULL, 0, 1, {TYPE_PARTITION}, + 0, "PARTITION", + "Hide PARTITION by setting the \"hidden\" bit in" + " its partition type code."}, + /* FIXME: ifconfig unsupported. */ + /* FIXME: impsprobe unsupported. */ + {"initrd", "legacy_initrd '%s' %s\n", NULL, 0, 2, {TYPE_FILE_NO_CONSUME, + TYPE_REST_VERBATIM}, 0, + "FILE [ARG ...]", + "Load an initial ramdisk FILE for a Linux format boot image and set the" + " appropriate parameters in the Linux setup area in memory."}, + /* NOTE: install unsupported. */ + /* FIXME: ioprobe unsupported. */ + /* FIXME: really support --no-mem-option. */ + {"kernel", "legacy_kernel %s %s '%s' %s\n", NULL, 0, + 4, {TYPE_TYPE_OR_NOMEM_OPTION, TYPE_TYPE_OR_NOMEM_OPTION, + TYPE_FILE_NO_CONSUME, TYPE_REST_VERBATIM}, 0, + "[--no-mem-option] [--type=TYPE] FILE [ARG ...]", + "Attempt to load the primary boot image from FILE. The rest of the" + " line is passed verbatim as the \"kernel command line\". Any modules" + " must be reloaded after using this command. The option --type is used" + " to suggest what type of kernel to be loaded. TYPE must be either of" + " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and" + " \"multiboot\". The option --no-mem-option tells GRUB not to pass a" + " Linux's mem option automatically."}, + {"lock", "if ! authenticate legacy; then return; fi", NULL, 0, 0, {}, 0, + 0, "Break a command execution unless the user is authenticated."}, + {"makeactive", "parttool \"$root\" boot+\n", NULL, 0, 0, {}, 0, 0, + "Set the active partition on the root disk to GRUB's root device." + " This command is limited to _primary_ PC partitions on a hard disk."}, + {"map", "drivemap '%s' '%s'\n", NULL, 0, + 2, {TYPE_PARTITION, TYPE_PARTITION}, + FLAG_IGNORE_REST, "TO_DRIVE FROM_DRIVE", + "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary" + " when you chain-load some operating systems, such as DOS, if such an" + " OS resides at a non-first drive."}, + /* NOTE: md5crypt unsupported since GRUB has not enough entropy and this + hash shouldn't be used anymore. */ + {"module", "legacy_initrd '%s' %s\n", NULL, 0, 2, {TYPE_FILE_NO_CONSUME, + TYPE_REST_VERBATIM}, 0, + "FILE [ARG ...]", + "Load a boot module FILE for a Multiboot format boot image (no" + " interpretation of the file contents is made, so users of this" + " command must know what the kernel in question expects). The" + " rest of the line is passed as the \"module command line\", like" + " the `kernel' command."}, + {"modulenounzip", "legacy_initrd_nounzip '%s' %s\n", NULL, 0, 2, + {TYPE_FILE_NO_CONSUME, TYPE_REST_VERBATIM}, 0, + "FILE [ARG ...]", + "The same as `module', except that automatic decompression is" + " disabled."}, + {"pager", "set pager=%s; if [ \"$pager\" = 0 ]; then " + " echo Internal pager is now off; else " + "echo Internal pager is now on; fi\n", NULL, 0, + 1, {TYPE_BOOL}, FLAG_FALLBACK_AVAILABLE, "[FLAG]", + "Toggle pager mode with no argument. If FLAG is given and its value" + " is `on', turn on the mode. If FLAG is `off', turn off the mode."}, + {"pager", + "if [ \"$pager\" = 1 ]; then pager=0; echo Internal pager is now off;" + "else pager=1; echo Internal pager is now on; fi\n", NULL, 0, 0, {}, + FLAG_FALLBACK, NULL, NULL}, + /* FIXME: partnew unsupported. */ + {"parttype", "parttool '%s' type=%s\n", NULL, 0, + 2, {TYPE_PARTITION, TYPE_INT}, 0, + "PART TYPE", "Change the type of the partition PART to TYPE."}, + {"password", "if [ \"$superusers\" = "" ]; then superusers=legacy; fi;\n" + "legacy_password %s '%s'\n", + "menuentry \"Superuser menu\" --users \"legacy\" { configfile '%s'; }\n", + 2, 3, {TYPE_OPTION, TYPE_VERBATIM, TYPE_FILE}, + FLAG_IGNORE_REST | FLAG_FALLBACK_AVAILABLE | FLAG_NO_MENUENTRY, + "[--md5] PASSWD [FILE]", + "If used in the first section of a menu file, disable all" + " interactive editing control (menu entry editor and" + " command line). If the password PASSWD is entered, it loads the" + " FILE as a new config file and restarts the GRUB Stage 2. If you" + " omit the argument FILE, then GRUB just unlocks privileged" + " instructions. You can also use it in the script section, in" + " which case it will ask for the password, before continuing." + " The option --md5 tells GRUB that PASSWD is encrypted with" + " md5crypt."}, + {"password", "if [ \"$superusers\" = "" ]; then superusers=legacy; fi;\n" + "legacy_password %s '%s'\n", NULL, 0, 2, {TYPE_OPTION, TYPE_VERBATIM}, + FLAG_IGNORE_REST | FLAG_FALLBACK | FLAG_NO_MENUENTRY, NULL, NULL}, + {"password", "if legacy_check_password %s '%s'; then configfile '%s'; " + "else return; fi\n", NULL, 2, 3, {TYPE_OPTION, TYPE_VERBATIM, TYPE_FILE}, + FLAG_IGNORE_REST | FLAG_FALLBACK_AVAILABLE | FLAG_MENUENTRY_ONLY, + NULL, NULL}, + {"password", "if ! legacy_check_password %s '%s'; then return fi;\n", + NULL, 0, 2, {TYPE_OPTION, TYPE_VERBATIM}, + FLAG_IGNORE_REST | FLAG_FALLBACK | FLAG_MENUENTRY_ONLY, NULL, NULL}, + /* NOTE: GRUB2 has a design principle of not eternally waiting for user + input. 60 seconds should be enough. + */ + {"pause", "echo %s; if ! sleep -i 60; then return; fi\n", NULL, 0, 1, + {TYPE_REST_VERBATIM}, 0, + "[MESSAGE ...]", "Print MESSAGE, then wait until a key is pressed."}, + /* FIXME: rarp unsupported. */ + {"read", "read_dword %s\n", NULL, 0, 1, {TYPE_INT}, 0, "ADDR", + "Read a 32-bit value from memory at address ADDR and" + " display it in hex format."}, + {"reboot", "reboot\n", NULL, 0, 0, {}, 0, 0, "Reboot your system."}, + {"root", "set root='%s'; set legacy_hdbias='%s'\n", NULL, 0, + 2, {TYPE_PARTITION, TYPE_INT}, FLAG_FALLBACK_AVAILABLE, + "[DEVICE [HDBIAS]]", + "Set the current \"root device\" to the device DEVICE, then" + " attempt to mount it to get the partition size (for passing the" + " partition descriptor in `ES:ESI', used by some chain-loaded" + " bootloaders), the BSD drive-type (for booting BSD kernels using" + " their native boot format), and correctly determine " + " the PC partition where a BSD sub-partition is located. The" + " optional HDBIAS parameter is a number to tell a BSD kernel" + " how many BIOS drive numbers are on controllers before the current" + " one. For example, if there is an IDE disk and a SCSI disk, and your" + " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."}, + {"root", "echo \"$root\"\n", NULL, 0, 0, {}, FLAG_FALLBACK, NULL, NULL}, + {"rootnoverify", "set root='%s'; set legacy_hdbias='%s'\n", NULL, 0, + 2, {TYPE_PARTITION, TYPE_INT}, 0, + "[DEVICE [HDBIAS]]", + "Similar to `root', but don't attempt to mount the partition. This" + " is useful for when an OS is outside of the area of the disk that" + " GRUB can read, but setting the correct root device is still" + " desired. Note that the items mentioned in `root' which" + " derived from attempting the mount will NOT work correctly."}, + {"rootnoverify", "echo \"$root\"\n", NULL, 0, + 0, {}, FLAG_FALLBACK, NULL, NULL}, + /* FIXME: support saving NUM and fallback. */ + {"savedefault", "saved_entry=${chosen}; save_env saved_entry\n", NULL, 0, + 0, {}, 0, "[NUM | `fallback']", + "Save the current entry as the default boot entry if no argument is" + " specified. If a number is specified, this number is saved. If" + " `fallback' is used, next fallback entry is saved."}, + {"serial", "serial %s\n", NULL, 0, 1, {TYPE_REST_VERBATIM}, 0, + "[--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] " + "[--parity=PARITY] [--stop=STOP] [--device=DEV]", + "Initialize a serial device. UNIT is a digit that specifies which serial" + " device is used (e.g. 0 == COM1). If you need to specify the port number," + " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length," + " PARITY is the type of parity, which is one of `no', `odd' and `even'." + " STOP is the length of stop bit(s). The option --device can be used only" + " in the grub shell, which specifies the file name of a tty device. The" + " default values are COM1, 9600, 8N1."}, + /* FIXME: setkey unsupported. */ /* NUL_TERMINATE */ + /* NOTE: setup unsupported. */ + /* FIXME: terminal unsupported. */ /* NUL_TERMINATE */ + /* FIXME: terminfo unsupported. */ /* NUL_TERMINATE */ + {"testload", "cat '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILE", + "Read the entire contents of FILE in several different ways and" + " compares them, to test the filesystem code. " + " If this test succeeds, then a good next" + " step is to try loading a kernel."}, + {"testvbe", "insmod vbe; videotest '%s'\n", NULL, 0, 1, {TYPE_VBE_MODE}, 0, + "MODE", "Test the VBE mode MODE. Hit any key to return."}, + /* FIXME: tftpserver unsupported. */ + {"timeout", "set timeout=%s\n", NULL, 0, 1, {TYPE_INT}, 0, "SEC", + "Set a timeout, in SEC seconds, before automatically booting the" + " default entry (normally the first entry defined)."}, + /* title is handled separately. */ + {"unhide", "parttool '%s' hidden-\n", NULL, 0, + 1, {TYPE_PARTITION}, 0, "PARTITION", + "Unhide PARTITION by clearing the \"hidden\" bit in its" + " partition type code."}, + /* FIXME: uppermem unsupported. */ + {"uuid", "search --set=root --fs-uuid '%s'\n", NULL, 0, 1, {TYPE_VERBATIM}, + 0, "UUID", "Find root by UUID"}, + {"vbeprobe", "insmod vbe; videoinfo '%s'\n", NULL, 0, 1, {TYPE_VBE_MODE}, + FLAG_FALLBACK_AVAILABLE, "[MODE]", + "Probe VBE information. If the mode number MODE is specified, show only" + " the information about only the mode."}, + {"vbeprobe", "insmod vbe; videoinfo\n", NULL, 0, 0, {}, + FLAG_FALLBACK, NULL, NULL} + }; + +char * +grub_legacy_escape (const char *in, grub_size_t len) +{ + const char *ptr; + char *ret, *outptr; + int overhead = 0; + for (ptr = in; ptr < in + len && *ptr; ptr++) + if (*ptr == '\'' || *ptr == '\\') + overhead++; + ret = grub_malloc (ptr - in + overhead + 1); + if (!ret) + return NULL; + outptr = ret; + for (ptr = in; ptr < in + len && *ptr; ptr++) + { + if (*ptr == '\'' || *ptr == '\\') + *outptr++ = '\\'; + + *outptr++ = *ptr; + } + *outptr++ = 0; + return ret; +} + +static char * +adjust_file (const char *in, grub_size_t len) +{ + const char *comma, *ptr, *rest; + char *ret, *outptr; + int overhead = 0; + int part = -1, subpart = -1; + if (in[0] != '(') + return grub_legacy_escape (in, len); + for (ptr = in + 1; ptr < in + len && *ptr && *ptr != ')' + && *ptr != ','; ptr++) + if (*ptr == '\'' || *ptr == '\\') + overhead++; + comma = ptr; + if (*comma != ',') + return grub_legacy_escape (in, len); + part = grub_strtoull (comma + 1, (char **) &rest, 0); + if (rest[0] == ',' && rest[1] >= 'a' && rest[1] <= 'z') + { + subpart = rest[1] - 'a'; + rest += 2; + } + for (ptr = rest; ptr < in + len && *ptr; ptr++) + if (*ptr == '\'' || *ptr == '\\') + overhead++; + + /* 35 is enough for any 2 numbers. */ + ret = grub_malloc (ptr - in + overhead + 35); + if (!ret) + return NULL; + + outptr = ret; + for (ptr = in; ptr < in + len && ptr <= comma; ptr++) + { + if (*ptr == '\'' || *ptr == '\\') + *outptr++ = '\\'; + + *outptr++ = *ptr; + } + if (subpart != -1) + grub_snprintf (outptr, 35, "%d,%d", part + 1, subpart + 1); + else + grub_snprintf (outptr, 35, "%d", part + 1); + while (*outptr) + outptr++; + for (ptr = rest; ptr < in + len; ptr++) + { + if (*ptr == '\'' || *ptr == '\\') + *outptr++ = '\\'; + + *outptr++ = *ptr; + } + *outptr = 0; + return ret; +} + +static int +check_option (const char *a, char *b, grub_size_t len) +{ + if (grub_strlen (b) != len) + return 0; + return grub_strncmp (a, b, len) == 0; +} + +static int +is_option (enum arg_type opt, const char *curarg, grub_size_t len) +{ + switch (opt) + { + case TYPE_NOAPM_OPTION: + return check_option (curarg, "--no-apm", len); + case TYPE_FORCE_OPTION: + return check_option (curarg, "--force", len); + case TYPE_TYPE_OR_NOMEM_OPTION: + return check_option (curarg, "--type=netbsd", len) + || check_option (curarg, "--type=freebsd", len) + || check_option (curarg, "--type=openbsd", len) + || check_option (curarg, "--type=linux", len) + || check_option (curarg, "--type=biglinux", len) + || check_option (curarg, "--type=multiboot", len) + || check_option (curarg, "--no-mem-option", len); + case TYPE_OPTION: + return (len >= 2 && curarg[0] == '-' && curarg[1] == '-'); + default: + return 0; + } +} + +char * +grub_legacy_parse (const char *buf, char **entryname, char **suffix) +{ + const char *ptr; + const char *cmdname; + unsigned i, cmdnum; + + *suffix = NULL; + + for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++); + if (!*ptr || *ptr == '#') + { + char *ret; + int len = grub_strlen (buf); + ret = grub_malloc (len + 2); + grub_memcpy (ret, buf, len); + if (len && ret[len - 1] == '\n') + ret[len] = 0; + else + { + ret[len] = '\n'; + ret[len + 1] = 0; + } + return ret; + } + + cmdname = ptr; + for (ptr = buf; *ptr && !grub_isspace (*ptr) && *ptr != '='; ptr++); + + if (entryname && grub_strncmp ("title", cmdname, ptr - cmdname) == 0 + && ptr - cmdname == sizeof ("title") - 1) + { + const char *ptr2; + for (; grub_isspace (*ptr) || *ptr == '='; ptr++); + ptr2 = ptr + grub_strlen (ptr); + while (ptr2 > ptr && grub_isspace (*(ptr2 - 1))) + ptr2--; + *entryname = grub_strndup (ptr, ptr2 - ptr); + return NULL; + } + + for (cmdnum = 0; cmdnum < ARRAY_SIZE (legacy_commands); cmdnum++) + if (grub_strncmp (legacy_commands[cmdnum].name, cmdname, ptr - cmdname) == 0 + && legacy_commands[cmdnum].name[ptr - cmdname] == 0 + && (!(*entryname != NULL && (legacy_commands[cmdnum].flags + & FLAG_NO_MENUENTRY))) + && (!(*entryname == NULL && (legacy_commands[cmdnum].flags + & FLAG_MENUENTRY_ONLY)))) + break; + if (cmdnum == ARRAY_SIZE (legacy_commands)) + return grub_xasprintf ("# Unsupported legacy command: %s\n", buf); + + for (; grub_isspace (*ptr) || *ptr == '='; ptr++); + + char *args[ARRAY_SIZE (legacy_commands[0].argt)]; + grub_memset (args, 0, sizeof (args)); + + { + int hold_arg = 0; + const char *curarg = NULL; + for (i = 0; i < legacy_commands[cmdnum].argc; i++) + { + grub_size_t curarglen; + if (hold_arg) + { + ptr = curarg; + hold_arg = 0; + } + for (; grub_isspace (*ptr); ptr++); + curarg = ptr; + if (!*curarg) + break; + for (; *ptr && !grub_isspace (*ptr); ptr++); + if (i != legacy_commands[cmdnum].argc - 1 + || (legacy_commands[cmdnum].flags & FLAG_IGNORE_REST)) + curarglen = ptr - curarg; + else + { + curarglen = grub_strlen (curarg); + while (curarglen > 0 && grub_isspace (curarg[curarglen - 1])) + curarglen--; + } + if (*ptr) + ptr++; + switch (legacy_commands[cmdnum].argt[i]) + { + case TYPE_FILE_NO_CONSUME: + hold_arg = 1; + case TYPE_PARTITION: + case TYPE_FILE: + args[i] = adjust_file (curarg, curarglen); + break; + + case TYPE_REST_VERBATIM: + { + char *outptr, *outptr0; + int overhead = 3; + ptr = curarg; + while (*ptr) + { + for (; *ptr && grub_isspace (*ptr); ptr++); + for (; *ptr && !grub_isspace (*ptr); ptr++) + if (*ptr == '\\' || *ptr == '\'') + overhead++; + if (*ptr) + ptr++; + overhead += 3; + } + outptr0 = args[i] = grub_malloc (overhead + (ptr - curarg)); + if (!outptr0) + return NULL; + ptr = curarg; + outptr = outptr0; + while (*ptr) + { + for (; *ptr && grub_isspace (*ptr); ptr++); + if (outptr != outptr0) + *outptr++ = ' '; + *outptr++ = '\''; + for (; *ptr && !grub_isspace (*ptr); ptr++) + { + if (*ptr == '\\' || *ptr == '\'') + *outptr++ = '\\'; + *outptr++ = *ptr; + } + *outptr++ = '\''; + if (*ptr) + ptr++; + } + *outptr++ = 0; + } + break; + + case TYPE_VERBATIM: + args[i] = grub_legacy_escape (curarg, curarglen); + break; + case TYPE_FORCE_OPTION: + case TYPE_NOAPM_OPTION: + case TYPE_TYPE_OR_NOMEM_OPTION: + case TYPE_OPTION: + if (is_option (legacy_commands[cmdnum].argt[i], curarg, curarglen)) + { + args[i] = grub_strndup (curarg, curarglen); + break; + } + args[i] = grub_strdup (""); + hold_arg = 1; + break; + case TYPE_INT: + { + const char *brk; + int base = 10; + brk = curarg; + if (brk[0] == '0' && brk[1] == 'x') + base = 16; + else if (brk[0] == '0') + base = 8; + for (; *brk && brk < curarg + curarglen; brk++) + { + if (base == 8 && (*brk == '8' || *brk == '9')) + break; + if (grub_isdigit (*brk)) + continue; + if (base != 16) + break; + if (!(*brk >= 'a' && *brk <= 'f') + && !(*brk >= 'A' && *brk <= 'F')) + break; + } + if (brk == curarg) + args[i] = grub_strdup ("0"); + else + args[i] = grub_strndup (curarg, brk - curarg); + } + break; + case TYPE_VBE_MODE: + { + unsigned mod; + struct grub_vesa_mode_table_entry *modedesc; + + mod = grub_strtoul (curarg, 0, 0); + if (grub_errno) + { + mod = 0; + grub_errno = GRUB_ERR_NONE; + } + if (mod < GRUB_VESA_MODE_TABLE_START + || mod > GRUB_VESA_MODE_TABLE_END) + { + args[i] = grub_strdup ("auto"); + break; + } + modedesc = &grub_vesa_mode_table[mod - GRUB_VESA_MODE_TABLE_START]; + if (!modedesc->width) + { + args[i] = grub_strdup ("auto"); + break; + } + args[i] = grub_xasprintf ("%ux%ux%u", + modedesc->width, modedesc->height, + modedesc->depth); + break; + } + case TYPE_BOOL: + if (curarglen == 2 && curarg[0] == 'o' && curarg[1] == 'n') + args[i] = grub_strdup ("1"); + else + args[i] = grub_strdup ("0"); + break; + } + } + } + + while (legacy_commands[cmdnum].argc > 0 + && args[legacy_commands[cmdnum].argc - 1] == NULL + && (legacy_commands[cmdnum].flags & FLAG_FALLBACK_AVAILABLE) + && args[legacy_commands[cmdnum + 1].argc] == NULL) + cmdnum++; + + for (; i < legacy_commands[cmdnum].argc; i++) + switch (legacy_commands[cmdnum].argt[i]) + { + case TYPE_FILE_NO_CONSUME: + case TYPE_PARTITION: + case TYPE_FILE: + case TYPE_REST_VERBATIM: + case TYPE_VERBATIM: + case TYPE_FORCE_OPTION: + case TYPE_NOAPM_OPTION: + case TYPE_TYPE_OR_NOMEM_OPTION: + case TYPE_OPTION: + args[i] = grub_strdup (""); + break; + case TYPE_BOOL: + case TYPE_INT: + args[i] = grub_strdup ("0"); + break; + case TYPE_VBE_MODE: + args[i] = grub_strdup ("auto"); + break; + } + + if (legacy_commands[cmdnum].flags & FLAG_COLOR_INVERT) + { + char *corig = args[legacy_commands[cmdnum].argc - 1]; + char *slash = grub_strchr (corig, '/'); + char *invert; + grub_size_t len; + + len = grub_strlen (corig); + if (!slash) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "bad color specification %s", + args[0]); + return NULL; + } + invert = grub_malloc (len + 1); + if (!invert) + return NULL; + grub_memcpy (invert, slash + 1, len - (slash - corig) - 1); + invert[len - (slash - args[0]) - 1] = '/'; + grub_memcpy (invert + len - (slash - corig), corig, slash - corig); + invert[len] = 0; + args[legacy_commands[cmdnum].argc] = invert; + } + + if (legacy_commands[cmdnum].suffix) + { + *suffix = grub_xasprintf (legacy_commands[cmdnum].suffix, + args[legacy_commands[cmdnum].suffixarg]); + if (*suffix) + return NULL; + } + + { + char *ret = grub_xasprintf (legacy_commands[cmdnum].map, args[0], args[1], + args[2], args[3]); + grub_free (args[0]); + grub_free (args[1]); + grub_free (args[2]); + grub_free (args[3]); + return ret; + } +} diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h index ce3794087..28e354759 100644 --- a/grub-core/lib/posix_wrap/sys/types.h +++ b/grub-core/lib/posix_wrap/sys/types.h @@ -22,11 +22,14 @@ #include 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 diff --git a/grub-core/lib/relocator.c b/grub-core/lib/relocator.c index 53acda52f..9a6941332 100644 --- a/grub-core/lib/relocator.c +++ b/grub-core/lib/relocator.c @@ -1379,11 +1379,13 @@ grub_relocator_alloc_chunk_align (struct grub_relocator *rel, { int found = 0; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t sz, grub_uint32_t type) + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t sz, + grub_memory_type_t type) { grub_uint64_t candidate; - if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + if (type != GRUB_MEMORY_AVAILABLE) return 0; candidate = ALIGN_UP (addr, align); if (candidate < min_addr) diff --git a/grub-core/lib/xzembed/xz.h b/grub-core/lib/xzembed/xz.h new file mode 100644 index 000000000..f0a7dbbca --- /dev/null +++ b/grub-core/lib/xzembed/xz.h @@ -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 . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#ifndef XZ_H +#define XZ_H + +#include + +/** + * 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 diff --git a/grub-core/lib/xzembed/xz_config.h b/grub-core/lib/xzembed/xz_config.h new file mode 100644 index 000000000..0af0d2b81 --- /dev/null +++ b/grub-core/lib/xzembed/xz_config.h @@ -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 . + */ +/* + * 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 + +#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 diff --git a/grub-core/lib/xzembed/xz_dec_bcj.c b/grub-core/lib/xzembed/xz_dec_bcj.c new file mode 100644 index 000000000..7eec9de7d --- /dev/null +++ b/grub-core/lib/xzembed/xz_dec_bcj.c @@ -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 . + */ +/* + * 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; +} diff --git a/grub-core/lib/xzembed/xz_dec_lzma2.c b/grub-core/lib/xzembed/xz_dec_lzma2.c new file mode 100644 index 000000000..a0d422697 --- /dev/null +++ b/grub-core/lib/xzembed/xz_dec_lzma2.c @@ -0,0 +1,1168 @@ +/* xz_dec_lzma2.c - LZMA2 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 . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#include "xz_private.h" +#include "xz_lzma2.h" + +/* + * Range decoder initialization eats the first five bytes of each LZMA chunk. + */ +#define RC_INIT_BYTES 5 + +/* + * Minimum number of usable input buffer to safely decode one LZMA symbol. + * The worst case is that we decode 22 bits using probabilities and 26 + * direct bits. This may decode at maximum of 20 bytes of input. However, + * lzma_main() does an extra normalization before returning, thus we + * need to put 21 here. + */ +#define LZMA_IN_REQUIRED 21 + +/* + * Dictionary (history buffer) + * + * These are always true: + * start <= pos <= full <= end + * pos <= limit <= end + * + * In multi-call mode, also these are true: + * end == size + * size <= allocated + * + * Most of these variables are size_t to support single-call mode, + * in which the dictionary variables address the actual output + * buffer directly. + */ +struct dictionary { + /* Beginning of the history buffer */ + uint8_t *buf; + + /* Old position in buf (before decoding more data) */ + size_t start; + + /* Position in buf */ + size_t pos; + + /* + * How full dictionary is. This is used to detect corrupt input that + * would read beyond the beginning of the uncompressed stream. + */ + size_t full; + + /* Write limit; we don't write to buf[limit] or later bytes. */ + size_t limit; + + /* + * End of the dictionary buffer. In multi-call mode, this is + * the same as the dictionary size. In single-call mode, this + * indicates the size of the output buffer. + */ + size_t end; + + /* + * Size of the dictionary as specified in Block Header. This is used + * together with "full" to detect corrupt input that would make us + * read beyond the beginning of the uncompressed stream. + */ + uint32_t size; + + /* + * Amount of memory allocated for the dictionary. A special + * value of zero indicates that we are in single-call mode, + * where the output buffer works as the dictionary. + */ + uint32_t allocated; +}; + +/* Range decoder */ +struct rc_dec { + uint32_t range; + uint32_t code; + + /* + * Number of initializing bytes remaining to be read + * by rc_read_init(). + */ + uint32_t init_bytes_left; + + /* + * Buffer from which we read our input. It can be either + * temp.buf or the caller-provided input buffer. + */ + const uint8_t *in; + size_t in_pos; + size_t in_limit; +}; + +/* Probabilities for a length decoder. */ +struct lzma_len_dec { + /* Probability of match length being at least 10 */ + uint16_t choice; + + /* Probability of match length being at least 18 */ + uint16_t choice2; + + /* Probabilities for match lengths 2-9 */ + uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS]; + + /* Probabilities for match lengths 10-17 */ + uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS]; + + /* Probabilities for match lengths 18-273 */ + uint16_t high[LEN_HIGH_SYMBOLS]; +}; + +struct lzma_dec { + /* + * LZMA properties or related bit masks (number of literal + * context bits, a mask dervied from the number of literal + * position bits, and a mask dervied from the number + * position bits) + */ + uint32_t lc; + uint32_t literal_pos_mask; /* (1 << lp) - 1 */ + uint32_t pos_mask; /* (1 << pb) - 1 */ + + /* Types of the most recently seen LZMA symbols */ + enum lzma_state state; + + /* Distances of latest four matches */ + uint32_t rep0; + uint32_t rep1; + uint32_t rep2; + uint32_t rep3; + + /* + * Length of a match. This is updated so that dict_repeat can + * be called again to finish repeating the whole match. + */ + uint32_t len; + + /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ + uint16_t is_match[STATES][POS_STATES_MAX]; + + /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ + uint16_t is_rep[STATES]; + + /* + * If 0, distance of a repeated match is rep0. + * Otherwise check is_rep1. + */ + uint16_t is_rep0[STATES]; + + /* + * If 0, distance of a repeated match is rep1. + * Otherwise check is_rep2. + */ + uint16_t is_rep1[STATES]; + + /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ + uint16_t is_rep2[STATES]; + + /* + * If 1, the repeated match has length of one byte. Otherwise + * the length is decoded from rep_len_decoder. + */ + uint16_t is_rep0_long[STATES][POS_STATES_MAX]; + + /* + * Probability tree for the highest two bits of the match + * distance. There is a separate probability tree for match + * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. + */ + uint16_t dist_slot[DIST_STATES][DIST_SLOTS]; + + /* + * Probility trees for additional bits for match distance + * when the distance is in the range [4, 127]. + */ + uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END]; + + /* + * Probability tree for the lowest four bits of a match + * distance that is equal to or greater than 128. + */ + uint16_t dist_align[ALIGN_SIZE]; + + /* Length of a normal match */ + struct lzma_len_dec match_len_dec; + + /* Length of a repeated match */ + struct lzma_len_dec rep_len_dec; + + /* Probabilities of literals */ + uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; +}; + +struct xz_dec_lzma2 { + /* LZMA2 */ + struct { + /* Position in xz_dec_lzma2_run(). */ + enum lzma2_seq { + SEQ_CONTROL, + SEQ_UNCOMPRESSED_1, + SEQ_UNCOMPRESSED_2, + SEQ_COMPRESSED_0, + SEQ_COMPRESSED_1, + SEQ_PROPERTIES, + SEQ_LZMA_PREPARE, + SEQ_LZMA_RUN, + SEQ_COPY + } sequence; + + /* + * Next position after decoding the compressed size of + * the chunk. + */ + enum lzma2_seq next_sequence; + + /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ + uint32_t uncompressed; + + /* + * Compressed size of LZMA chunk or compressed/uncompressed + * size of uncompressed chunk (64 KiB at maximum) + */ + uint32_t compressed; + + /* + * True if dictionary reset is needed. This is false before + * the first chunk (LZMA or uncompressed). + */ + bool need_dict_reset; + + /* + * True if new LZMA properties are needed. This is false + * before the first LZMA chunk. + */ + bool need_props; + } lzma2; + + /* + * Temporary buffer which holds small number of input bytes between + * decoder calls. See lzma2_lzma() for details. + */ + struct { + uint32_t size; + uint8_t buf[3 * LZMA_IN_REQUIRED]; + } temp; + + struct dictionary dict; + struct rc_dec rc; + struct lzma_dec lzma; +}; + +/************** + * Dictionary * + **************/ + +/* + * Reset the dictionary state. When in single-call mode, set up the beginning + * of the dictionary to point to the actual output buffer. + */ +static void dict_reset(struct dictionary *dict, struct xz_buf *b) +{ + if (dict->allocated == 0) { + dict->buf = b->out + b->out_pos; + dict->end = b->out_size - b->out_pos; + } + dict->start = 0; + dict->pos = 0; + dict->limit = 0; + dict->full = 0; +} + +/* Set dictionary write limit */ +static void dict_limit(struct dictionary *dict, size_t out_max) +{ + if (dict->end - dict->pos <= out_max) + dict->limit = dict->end; + else + dict->limit = dict->pos + out_max; +} + +/* Return true if at least one byte can be written into the dictionary. */ +static inline bool dict_has_space(const struct dictionary *dict) +{ + return dict->pos < dict->limit; +} + +/* + * Get a byte from the dictionary at the given distance. The distance is + * assumed to valid, or as a special case, zero when the dictionary is + * still empty. This special case is needed for single-call decoding to + * avoid writing a '\0' to the end of the destination buffer. + */ +static inline uint32_t dict_get( + const struct dictionary *dict, uint32_t dist) +{ + size_t offset = dict->pos - dist - 1; + + if (dist >= dict->pos) + offset += dict->end; + + return dict->full > 0 ? dict->buf[offset] : 0; +} + +/* + * Put one byte into the dictionary. It is assumed that there is space for it. + */ +static inline void dict_put(struct dictionary *dict, uint8_t byte) +{ + dict->buf[dict->pos++] = byte; + + if (dict->full < dict->pos) + dict->full = dict->pos; +} + +/* + * Repeat given number of bytes from the given distance. If the distance is + * invalid, false is returned. On success, true is returned and *len is + * updated to indicate how many bytes were left to be repeated. + */ +static bool dict_repeat( + struct dictionary *dict, uint32_t *len, uint32_t dist) +{ + size_t back; + uint32_t left; + + if (dist >= dict->full || dist >= dict->size) + return false; + + left = min_t(size_t, dict->limit - dict->pos, *len); + *len -= left; + + back = dict->pos - dist - 1; + if (dist >= dict->pos) + back += dict->end; + + do { + dict->buf[dict->pos++] = dict->buf[back++]; + if (back == dict->end) + back = 0; + } while (--left > 0); + + if (dict->full < dict->pos) + dict->full = dict->pos; + + return true; +} + +/* Copy uncompressed data as is from input to dictionary and output buffers. */ +static void dict_uncompressed( + struct dictionary *dict, struct xz_buf *b, uint32_t *left) +{ + size_t copy_size; + + while (*left > 0 && b->in_pos < b->in_size + && b->out_pos < b->out_size) { + copy_size = min(b->in_size - b->in_pos, + b->out_size - b->out_pos); + if (copy_size > dict->end - dict->pos) + copy_size = dict->end - dict->pos; + if (copy_size > *left) + copy_size = *left; + + *left -= copy_size; + + memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); + dict->pos += copy_size; + + if (dict->full < dict->pos) + dict->full = dict->pos; + + if (dict->allocated != 0) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, b->in + b->in_pos, + copy_size); + } + + dict->start = dict->pos; + + b->out_pos += copy_size; + b->in_pos += copy_size; + + } +} + +/* + * Flush pending data from dictionary to b->out. It is assumed that there is + * enough space in b->out. This is guaranteed because caller uses dict_limit() + * before decoding data into the dictionary. + */ +static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b) +{ + size_t copy_size = dict->pos - dict->start; + + if (dict->allocated != 0) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, dict->buf + dict->start, + copy_size); + } + + dict->start = dict->pos; + b->out_pos += copy_size; + return copy_size; +} + +/***************** + * Range decoder * + *****************/ + +/* Reset the range decoder. */ +static void rc_reset(struct rc_dec *rc) +{ + rc->range = (uint32_t)-1; + rc->code = 0; + rc->init_bytes_left = RC_INIT_BYTES; +} + +/* + * Read the first five initial bytes into rc->code if they haven't been + * read already. (Yes, the first byte gets completely ignored.) + */ +static bool rc_read_init(struct rc_dec *rc, struct xz_buf *b) +{ + while (rc->init_bytes_left > 0) { + if (b->in_pos == b->in_size) + return false; + + rc->code = (rc->code << 8) + b->in[b->in_pos++]; + --rc->init_bytes_left; + } + + return true; +} + +/* Return true if there may not be enough input for the next decoding loop. */ +static inline bool rc_limit_exceeded(const struct rc_dec *rc) +{ + return rc->in_pos > rc->in_limit; +} + +/* + * Return true if it is possible (from point of view of range decoder) that + * we have reached the end of the LZMA chunk. + */ +static inline bool rc_is_finished(const struct rc_dec *rc) +{ + return rc->code == 0; +} + +/* Read the next input byte if needed. */ +static __always_inline void rc_normalize(struct rc_dec *rc) +{ + if (rc->range < RC_TOP_VALUE) { + rc->range <<= RC_SHIFT_BITS; + rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++]; + } +} + +/* + * Decode one bit. In some versions, this function has been splitted in three + * functions so that the compiler is supposed to be able to more easily avoid + * an extra branch. In this particular version of the LZMA decoder, this + * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3 + * on x86). Using a non-splitted version results in nicer looking code too. + * + * NOTE: This must return an int. Do not make it return a bool or the speed + * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, + * and it generates 10-20 % faster code than GCC 3.x from this file anyway.) + */ +static __always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob) +{ + uint32_t bound; + int bit; + + rc_normalize(rc); + bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob; + if (rc->code < bound) { + rc->range = bound; + *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS; + bit = 0; + } else { + rc->range -= bound; + rc->code -= bound; + *prob -= *prob >> RC_MOVE_BITS; + bit = 1; + } + + return bit; +} + +/* Decode a bittree starting from the most significant bit. */ +static __always_inline uint32_t rc_bittree( + struct rc_dec *rc, uint16_t *probs, uint32_t limit) +{ + uint32_t symbol = 1; + + do { + if (rc_bit(rc, &probs[symbol])) + symbol = (symbol << 1) + 1; + else + symbol <<= 1; + } while (symbol < limit); + + return symbol; +} + +/* Decode a bittree starting from the least significant bit. */ +static __always_inline void rc_bittree_reverse(struct rc_dec *rc, + uint16_t *probs, uint32_t *dest, uint32_t limit) +{ + uint32_t symbol = 1; + uint32_t i = 0; + + do { + if (rc_bit(rc, &probs[symbol])) { + symbol = (symbol << 1) + 1; + *dest += 1 << i; + } else { + symbol <<= 1; + } + } while (++i < limit); +} + +/* Decode direct bits (fixed fifty-fifty probability) */ +static inline void rc_direct( + struct rc_dec *rc, uint32_t *dest, uint32_t limit) +{ + uint32_t mask; + + do { + rc_normalize(rc); + rc->range >>= 1; + rc->code -= rc->range; + mask = (uint32_t)0 - (rc->code >> 31); + rc->code += rc->range & mask; + *dest = (*dest << 1) + (mask + 1); + } while (--limit > 0); +} + +/******** + * LZMA * + ********/ + +/* Get pointer to literal coder probability array. */ +static uint16_t * lzma_literal_probs(struct xz_dec_lzma2 *s) +{ + uint32_t prev_byte = dict_get(&s->dict, 0); + uint32_t low = prev_byte >> (8 - s->lzma.lc); + uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc; + return s->lzma.literal[low + high]; +} + +/* Decode a literal (one 8-bit byte) */ +static void lzma_literal(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + uint32_t symbol; + uint32_t match_byte; + uint32_t match_bit; + uint32_t offset; + uint32_t i; + + probs = lzma_literal_probs(s); + + if (lzma_state_is_literal(s->lzma.state)) { + symbol = rc_bittree(&s->rc, probs, 0x100); + } else { + symbol = 1; + match_byte = dict_get(&s->dict, s->lzma.rep0) << 1; + offset = 0x100; + + do { + match_bit = match_byte & offset; + match_byte <<= 1; + i = offset + match_bit + symbol; + + if (rc_bit(&s->rc, &probs[i])) { + symbol = (symbol << 1) + 1; + offset &= match_bit; + } else { + symbol <<= 1; + offset &= ~match_bit; + } + } while (symbol < 0x100); + } + + dict_put(&s->dict, (uint8_t)symbol); + lzma_state_literal(&s->lzma.state); +} + +/* Decode the length of the match into s->lzma.len. */ +static void lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l, + uint32_t pos_state) +{ + uint16_t *probs; + uint32_t limit; + + if (!rc_bit(&s->rc, &l->choice)) { + probs = l->low[pos_state]; + limit = LEN_LOW_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN; + } else { + if (!rc_bit(&s->rc, &l->choice2)) { + probs = l->mid[pos_state]; + limit = LEN_MID_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; + } else { + probs = l->high; + limit = LEN_HIGH_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS + + LEN_MID_SYMBOLS; + } + } + + s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit; +} + +/* Decode a match. The distance will be stored in s->lzma.rep0. */ +static void lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint16_t *probs; + uint32_t dist_slot; + uint32_t limit; + + lzma_state_match(&s->lzma.state); + + s->lzma.rep3 = s->lzma.rep2; + s->lzma.rep2 = s->lzma.rep1; + s->lzma.rep1 = s->lzma.rep0; + + lzma_len(s, &s->lzma.match_len_dec, pos_state); + + probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)]; + dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS; + + if (dist_slot < DIST_MODEL_START) { + s->lzma.rep0 = dist_slot; + } else { + limit = (dist_slot >> 1) - 1; + s->lzma.rep0 = 2 + (dist_slot & 1); + + if (dist_slot < DIST_MODEL_END) { + s->lzma.rep0 <<= limit; + probs = s->lzma.dist_special + s->lzma.rep0 + - dist_slot - 1; + rc_bittree_reverse(&s->rc, probs, + &s->lzma.rep0, limit); + } else { + rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS); + s->lzma.rep0 <<= ALIGN_BITS; + rc_bittree_reverse(&s->rc, s->lzma.dist_align, + &s->lzma.rep0, ALIGN_BITS); + } + } +} + +/* + * Decode a repeated match. The distance is one of the four most recently + * seen matches. The distance will be stored in s->lzma.rep0. + */ +static void lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint32_t tmp; + + if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) { + if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[ + s->lzma.state][pos_state])) { + lzma_state_short_rep(&s->lzma.state); + s->lzma.len = 1; + return; + } + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) { + tmp = s->lzma.rep1; + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) { + tmp = s->lzma.rep2; + } else { + tmp = s->lzma.rep3; + s->lzma.rep3 = s->lzma.rep2; + } + + s->lzma.rep2 = s->lzma.rep1; + } + + s->lzma.rep1 = s->lzma.rep0; + s->lzma.rep0 = tmp; + } + + lzma_state_long_rep(&s->lzma.state); + lzma_len(s, &s->lzma.rep_len_dec, pos_state); +} + +/* LZMA decoder core */ +static bool lzma_main(struct xz_dec_lzma2 *s) +{ + uint32_t pos_state; + + /* + * If the dictionary was reached during the previous call, try to + * finish the possibly pending repeat in the dictionary. + */ + if (dict_has_space(&s->dict) && s->lzma.len > 0) + dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0); + + /* + * Decode more LZMA symbols. One iteration may consume up to + * LZMA_IN_REQUIRED - 1 bytes. + */ + while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) { + pos_state = s->dict.pos & s->lzma.pos_mask; + + if (!rc_bit(&s->rc, &s->lzma.is_match[ + s->lzma.state][pos_state])) { + lzma_literal(s); + } else { + if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state])) + lzma_rep_match(s, pos_state); + else + lzma_match(s, pos_state); + + if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0)) + return false; + } + } + + /* + * Having the range decoder always normalized when we are outside + * this function makes it easier to correctly handle end of the chunk. + */ + rc_normalize(&s->rc); + + return true; +} + +/* + * Reset the LZMA decoder and range decoder state. Dictionary is nore reset + * here, because LZMA state may be reset without resetting the dictionary. + */ +static void lzma_reset(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + size_t i; + + s->lzma.state = STATE_LIT_LIT; + s->lzma.rep0 = 0; + s->lzma.rep1 = 0; + s->lzma.rep2 = 0; + s->lzma.rep3 = 0; + + /* + * All probabilities are initialized to the same value. This hack + * makes the code smaller by avoiding a separate loop for each + * probability array. + * + * This could be optimized so that only that part of literal + * probabilities that are actually required. In the common case + * we would write 12 KiB less. + */ + probs = s->lzma.is_match[0]; + for (i = 0; i < PROBS_TOTAL; ++i) + probs[i] = RC_BIT_MODEL_TOTAL / 2; + + rc_reset(&s->rc); +} + +/* + * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks + * from the decoded lp and pb values. On success, the LZMA decoder state is + * reset and true is returned. + */ +static bool lzma_props(struct xz_dec_lzma2 *s, uint8_t props) +{ + if (props > (4 * 5 + 4) * 9 + 8) + return false; + + s->lzma.pos_mask = 0; + while (props >= 9 * 5) { + props -= 9 * 5; + ++s->lzma.pos_mask; + } + + s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1; + + s->lzma.literal_pos_mask = 0; + while (props >= 9) { + props -= 9; + ++s->lzma.literal_pos_mask; + } + + s->lzma.lc = props; + + if (s->lzma.lc + s->lzma.literal_pos_mask > 4) + return false; + + s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1; + + lzma_reset(s); + + return true; +} + +/********* + * LZMA2 * + *********/ + +/* + * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't + * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This + * wrapper function takes care of making the LZMA decoder's assumption safe. + * + * As long as there is plenty of input left to be decoded in the current LZMA + * chunk, we decode directly from the caller-supplied input buffer until + * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into + * s->temp.buf, which (hopefully) gets filled on the next call to this + * function. We decode a few bytes from the temporary buffer so that we can + * continue decoding from the caller-supplied input buffer again. + */ +static bool lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b) +{ + size_t in_avail; + uint32_t tmp; + + in_avail = b->in_size - b->in_pos; + if (s->temp.size > 0 || s->lzma2.compressed == 0) { + tmp = 2 * LZMA_IN_REQUIRED - s->temp.size; + if (tmp > s->lzma2.compressed - s->temp.size) + tmp = s->lzma2.compressed - s->temp.size; + if (tmp > in_avail) + tmp = in_avail; + + memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp); + + if (s->temp.size + tmp == s->lzma2.compressed) { + memzero(s->temp.buf + s->temp.size + tmp, + sizeof(s->temp.buf) + - s->temp.size - tmp); + s->rc.in_limit = s->temp.size + tmp; + } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) { + s->temp.size += tmp; + b->in_pos += tmp; + return true; + } else { + s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED; + } + + s->rc.in = s->temp.buf; + s->rc.in_pos = 0; + + if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp) + return false; + + s->lzma2.compressed -= s->rc.in_pos; + + if (s->rc.in_pos < s->temp.size) { + s->temp.size -= s->rc.in_pos; + memmove(s->temp.buf, s->temp.buf + s->rc.in_pos, + s->temp.size); + return true; + } + + b->in_pos += s->rc.in_pos - s->temp.size; + s->temp.size = 0; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail >= LZMA_IN_REQUIRED) { + s->rc.in = b->in; + s->rc.in_pos = b->in_pos; + + if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED) + s->rc.in_limit = b->in_pos + s->lzma2.compressed; + else + s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED; + + if (!lzma_main(s)) + return false; + + in_avail = s->rc.in_pos - b->in_pos; + if (in_avail > s->lzma2.compressed) + return false; + + s->lzma2.compressed -= in_avail; + b->in_pos = s->rc.in_pos; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail < LZMA_IN_REQUIRED) { + if (in_avail > s->lzma2.compressed) + in_avail = s->lzma2.compressed; + + memcpy(s->temp.buf, b->in + b->in_pos, in_avail); + s->temp.size = in_avail; + b->in_pos += in_avail; + } + + return true; +} + +/* + * Take care of the LZMA2 control layer, and forward the job of actual LZMA + * decoding or copying of uncompressed chunks to other functions. + */ +enum xz_ret xz_dec_lzma2_run( + struct xz_dec_lzma2 *s, struct xz_buf *b) +{ + uint32_t tmp; + + while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) { + switch (s->lzma2.sequence) { + case SEQ_CONTROL: + /* + * LZMA2 control byte + * + * Exact values: + * 0x00 End marker + * 0x01 Dictionary reset followed by + * an uncompressed chunk + * 0x02 Uncompressed chunk (no dictionary reset) + * + * Highest three bits (s->control & 0xE0): + * 0xE0 Dictionary reset, new properties and state + * reset, followed by LZMA compressed chunk + * 0xC0 New properties and state reset, followed + * by LZMA compressed chunk (no dictionary + * reset) + * 0xA0 State reset using old properties, + * followed by LZMA compressed chunk (no + * dictionary reset) + * 0x80 LZMA chunk (no dictionary or state reset) + * + * For LZMA compressed chunks, the lowest five bits + * (s->control & 1F) are the highest bits of the + * uncompressed size (bits 16-20). + * + * A new LZMA2 stream must begin with a dictionary + * reset. The first LZMA chunk must set new + * properties and reset the LZMA state. + * + * Values that don't match anything described above + * are invalid and we return XZ_DATA_ERROR. + */ + tmp = b->in[b->in_pos++]; + + if (tmp >= 0xE0 || tmp == 0x01) { + s->lzma2.need_props = true; + s->lzma2.need_dict_reset = false; + dict_reset(&s->dict, b); + } else if (s->lzma2.need_dict_reset) { + return XZ_DATA_ERROR; + } + + if (tmp >= 0x80) { + s->lzma2.uncompressed = (tmp & 0x1F) << 16; + s->lzma2.sequence = SEQ_UNCOMPRESSED_1; + + if (tmp >= 0xC0) { + /* + * When there are new properties, + * state reset is done at + * SEQ_PROPERTIES. + */ + s->lzma2.need_props = false; + s->lzma2.next_sequence + = SEQ_PROPERTIES; + + } else if (s->lzma2.need_props) { + return XZ_DATA_ERROR; + + } else { + s->lzma2.next_sequence + = SEQ_LZMA_PREPARE; + if (tmp >= 0xA0) + lzma_reset(s); + } + } else { + if (tmp == 0x00) + return XZ_STREAM_END; + + if (tmp > 0x02) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_COMPRESSED_0; + s->lzma2.next_sequence = SEQ_COPY; + } + + break; + + case SEQ_UNCOMPRESSED_1: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_UNCOMPRESSED_2; + break; + + case SEQ_UNCOMPRESSED_2: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = SEQ_COMPRESSED_0; + break; + + case SEQ_COMPRESSED_0: + s->lzma2.compressed + = (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_COMPRESSED_1; + break; + + case SEQ_COMPRESSED_1: + s->lzma2.compressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = s->lzma2.next_sequence; + break; + + case SEQ_PROPERTIES: + if (!lzma_props(s, b->in[b->in_pos++])) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_LZMA_PREPARE; + + case SEQ_LZMA_PREPARE: + if (s->lzma2.compressed < RC_INIT_BYTES) + return XZ_DATA_ERROR; + + if (!rc_read_init(&s->rc, b)) + return XZ_OK; + + s->lzma2.compressed -= RC_INIT_BYTES; + s->lzma2.sequence = SEQ_LZMA_RUN; + + case SEQ_LZMA_RUN: + /* + * Set dictionary limit to indicate how much we want + * to be encoded at maximum. Decode new data into the + * dictionary. Flush the new data from dictionary to + * b->out. Check if we finished decoding this chunk. + * In case the dictionary got full but we didn't fill + * the output buffer yet, we may run this loop + * multiple times without changing s->lzma2.sequence. + */ + dict_limit(&s->dict, min_t(size_t, + b->out_size - b->out_pos, + s->lzma2.uncompressed)); + if (!lzma2_lzma(s, b)) + return XZ_DATA_ERROR; + + s->lzma2.uncompressed -= dict_flush(&s->dict, b); + + if (s->lzma2.uncompressed == 0) { + if (s->lzma2.compressed > 0 || s->lzma.len > 0 + || !rc_is_finished(&s->rc)) + return XZ_DATA_ERROR; + + rc_reset(&s->rc); + s->lzma2.sequence = SEQ_CONTROL; + + } else if (b->out_pos == b->out_size + || (b->in_pos == b->in_size + && s->temp.size + < s->lzma2.compressed)) { + return XZ_OK; + } + + break; + + case SEQ_COPY: + dict_uncompressed(&s->dict, b, &s->lzma2.compressed); + if (s->lzma2.compressed > 0) + return XZ_OK; + + s->lzma2.sequence = SEQ_CONTROL; + break; + } + } + + return XZ_OK; +} + +struct xz_dec_lzma2 * xz_dec_lzma2_create(uint32_t dict_max) +{ + struct xz_dec_lzma2 *s; + + /* Maximum supported dictionary by this implementation is 3 GiB. */ + if (dict_max > ((uint32_t)3 << 30)) + return NULL; + + s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + if (dict_max > 0) { + s->dict.buf = vmalloc(dict_max); + if (s->dict.buf == NULL) { + kfree(s); + return NULL; + } + } + + s->dict.allocated = dict_max; + + return s; +} + +enum xz_ret xz_dec_lzma2_reset( + struct xz_dec_lzma2 *s, uint8_t props) +{ + /* This limits dictionary size to 3 GiB (39) to keep parsing simpler. */ + if (props > ( min (DICT_BIT_SIZE,39)) ) + return XZ_OPTIONS_ERROR; + + s->dict.size = 2 + (props & 1); + s->dict.size <<= (props >> 1) + 11; + + if (s->dict.allocated > 0 && s->dict.allocated < s->dict.size) + { + /* enlarge dictionary buffer */ + uint8_t * newdict = realloc(s->dict.buf,s->dict.size); + + if (! newdict) + return XZ_MEMLIMIT_ERROR; + + s->dict.buf = newdict; + s->dict.allocated = s->dict.size; + } + + s->dict.end = s->dict.size; + + s->lzma.len = 0; + + s->lzma2.sequence = SEQ_CONTROL; + s->lzma2.need_dict_reset = true; + + s->temp.size = 0; + + return XZ_OK; +} + +void xz_dec_lzma2_end(struct xz_dec_lzma2 *s) +{ + if (s->dict.allocated > 0) + vfree(s->dict.buf); + + kfree(s); +} diff --git a/grub-core/lib/xzembed/xz_dec_stream.c b/grub-core/lib/xzembed/xz_dec_stream.c new file mode 100644 index 000000000..273041edb --- /dev/null +++ b/grub-core/lib/xzembed/xz_dec_stream.c @@ -0,0 +1,872 @@ +/* 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 . + */ +/* + * 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 + +/* 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, 2 * sizeof(vli_type)); + + ++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, 2 * sizeof(vli_type)); + + --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. */ + GRUB_MD_CRC32->final(s->block.hash.crc32_context); + GRUB_MD_CRC32->final(s->index.hash.crc32_context); + uint32_t block_crc = *(uint32_t*)GRUB_MD_CRC32->read(s->block.hash.crc32_context); + uint32_t index_crc = *(uint32_t*)GRUB_MD_CRC32->read(s->index.hash.crc32_context); + + if (s->block.hash.unpadded != s->index.hash.unpadded + || s->block.hash.uncompressed != s->index.hash.uncompressed + || block_crc != index_crc) + { + 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; + + { + uint8_t *t; + t = s->block.hash.crc32_context; + memzero(&s->block, sizeof(s->block)); + s->block.hash.crc32_context = t; + t = s->index.hash.crc32_context; + memzero(&s->index, sizeof(s->index)); + s->index.hash.crc32_context = t; + } + 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); + kfree(s->index.hash.crc32_context); + kfree(s->block.hash.crc32_context); + kfree(s->crc32_context); +#ifdef XZ_DEC_BCJ + xz_dec_bcj_end(s->bcj); +#endif + kfree(s); + } +} diff --git a/grub-core/lib/xzembed/xz_lzma2.h b/grub-core/lib/xzembed/xz_lzma2.h new file mode 100644 index 000000000..15e553dc0 --- /dev/null +++ b/grub-core/lib/xzembed/xz_lzma2.h @@ -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 . + */ +/* + * 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 diff --git a/grub-core/lib/xzembed/xz_private.h b/grub-core/lib/xzembed/xz_private.h new file mode 100644 index 000000000..fc845c92d --- /dev/null +++ b/grub-core/lib/xzembed/xz_private.h @@ -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 . + */ +/* + * 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 diff --git a/grub-core/lib/xzembed/xz_stream.h b/grub-core/lib/xzembed/xz_stream.h new file mode 100644 index 000000000..f58397a15 --- /dev/null +++ b/grub-core/lib/xzembed/xz_stream.h @@ -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 . + */ +/* + * 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 diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index cfea3b6a1..456c5f36c 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -19,8 +19,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -262,37 +261,30 @@ generate_e820_mmap (grub_size_t *len, grub_size_t *cnt, void *buf) struct grub_e820_mmap *mmap = buf; struct grub_e820_mmap prev, cur; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { cur.addr = addr; cur.size = size; switch (type) { - case GRUB_MACHINE_MEMORY_AVAILABLE: + case GRUB_MEMORY_AVAILABLE: cur.type = GRUB_E820_RAM; break; -#ifdef GRUB_MACHINE_MEMORY_ACPI - case GRUB_MACHINE_MEMORY_ACPI: + case GRUB_MEMORY_ACPI: cur.type = GRUB_E820_ACPI; break; -#endif -#ifdef GRUB_MACHINE_MEMORY_NVS - case GRUB_MACHINE_MEMORY_NVS: + case GRUB_MEMORY_NVS: cur.type = GRUB_E820_NVS; break; -#endif default: -#ifdef GRUB_MACHINE_MEMORY_CODE - case GRUB_MACHINE_MEMORY_CODE: -#endif -#ifdef GRUB_MACHINE_MEMORY_RESERVED - case GRUB_MACHINE_MEMORY_RESERVED: -#endif + case GRUB_MEMORY_CODE: + case GRUB_MEMORY_RESERVED: cur.type = GRUB_E820_RESERVED; break; } @@ -746,6 +738,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 +823,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 +1039,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 +1318,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 +1364,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 +1388,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 +1421,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 +1451,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 +1460,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 +1506,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 +1518,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 +1543,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 +1559,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 +1622,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 +1723,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 +1774,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 +1860,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 +1896,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,16 +1932,16 @@ static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk; GRUB_MOD_INIT (bsd) { - cmd_freebsd = grub_register_extcmd ("kfreebsd", grub_cmd_freebsd, - GRUB_COMMAND_FLAG_BOTH, + /* Net and OpenBSD kernels are often compressed. */ + grub_dl_load ("gzio"); + + cmd_freebsd = grub_register_extcmd ("kfreebsd", grub_cmd_freebsd, 0, N_("FILE"), N_("Load kernel of FreeBSD."), freebsd_opts); - cmd_openbsd = grub_register_extcmd ("kopenbsd", grub_cmd_openbsd, - GRUB_COMMAND_FLAG_BOTH, + cmd_openbsd = grub_register_extcmd ("kopenbsd", grub_cmd_openbsd, 0, N_("FILE"), N_("Load kernel of OpenBSD."), openbsd_opts); - cmd_netbsd = grub_register_extcmd ("knetbsd", grub_cmd_netbsd, - GRUB_COMMAND_FLAG_BOTH, + cmd_netbsd = grub_register_extcmd ("knetbsd", grub_cmd_netbsd, 0, N_("FILE"), N_("Load kernel of NetBSD."), netbsd_opts); cmd_freebsd_loadenv = diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index debcdb71f..4a6b7eafa 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -17,7 +17,6 @@ */ #include -#include #include #include #include @@ -35,6 +34,10 @@ #include #include +#ifdef GRUB_MACHINE_PCBIOS +#include +#endif + #ifdef GRUB_MACHINE_EFI #include #define HAS_VGA_TEXT 0 @@ -89,175 +92,6 @@ static struct idt_descriptor idt_desc = }; #endif -#ifdef GRUB_MACHINE_PCBIOS -struct linux_vesafb_res -{ - grub_uint16_t width; - grub_uint16_t height; -}; - -struct linux_vesafb_mode -{ - grub_uint8_t res_index; - grub_uint8_t depth; -}; - -enum vga_modes - { - VGA_320_200, - VGA_640_400, - VGA_640_480, - VGA_800_500, - VGA_800_600, - VGA_896_672, - VGA_1024_640, - VGA_1024_768, - VGA_1152_720, - VGA_1280_1024, - VGA_1440_900, - VGA_1600_1200, - }; - -static struct linux_vesafb_res linux_vesafb_res[] = - { - { 320, 200 }, - { 640, 400 }, - { 640, 480 }, - { 800, 500 }, - { 800, 600 }, - { 896, 672 }, - { 1024, 640 }, - { 1024, 768 }, - { 1152, 720 }, - { 1280, 1024 }, - { 1440, 900 }, - { 1600, 1200 }, - }; - -/* This is the reverse of the table in [linux]/Documentation/fb/vesafb.txt - plus a few more modes based on the table in - http://en.wikipedia.org/wiki/VESA_BIOS_Extensions */ -struct linux_vesafb_mode linux_vesafb_modes[] = - { - { VGA_640_400, 8 }, /* 0x300 */ - { VGA_640_480, 8 }, /* 0x301 */ - { VGA_800_600, 4 }, /* 0x302 */ - { VGA_800_600, 8 }, /* 0x303 */ - { VGA_1024_768, 4 }, /* 0x304 */ - { VGA_1024_768, 8 }, /* 0x305 */ - { VGA_1280_1024, 4 }, /* 0x306 */ - { VGA_1280_1024, 8 }, /* 0x307 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { VGA_320_200, 15 }, /* 0x30d */ - { VGA_320_200, 16 }, /* 0x30e */ - { VGA_320_200, 24 }, /* 0x30f */ - { VGA_640_480, 15 }, /* 0x310 */ - { VGA_640_480, 16 }, /* 0x311 */ - { VGA_640_480, 24 }, /* 0x312 */ - { VGA_800_600, 15 }, /* 0x313 */ - { VGA_800_600, 16 }, /* 0x314 */ - { VGA_800_600, 24 }, /* 0x315 */ - { VGA_1024_768, 15 }, /* 0x316 */ - { VGA_1024_768, 16 }, /* 0x317 */ - { VGA_1024_768, 24 }, /* 0x318 */ - { VGA_1280_1024, 15 }, /* 0x319 */ - { VGA_1280_1024, 16 }, /* 0x31a */ - { VGA_1280_1024, 24 }, /* 0x31b */ - { VGA_1600_1200, 8 }, /* 0x31c */ - { VGA_1600_1200, 15 }, /* 0x31d */ - { VGA_1600_1200, 16 }, /* 0x31e */ - { VGA_1600_1200, 24 }, /* 0x31f */ - { 0, 0 }, - { VGA_640_400, 15 }, /* 0x321 */ - { VGA_640_400, 16 }, /* 0x322 */ - { VGA_640_400, 24 }, /* 0x323 */ - { VGA_640_400, 32 }, /* 0x324 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { VGA_640_480, 32 }, /* 0x329 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { VGA_896_672, 8 }, /* 0x32f */ - { VGA_896_672, 15 }, /* 0x330 */ - { VGA_896_672, 16 }, /* 0x331 */ - { VGA_896_672, 24 }, /* 0x332 */ - { VGA_896_672, 32 }, /* 0x333 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { VGA_1600_1200, 32 }, /* 0x342 */ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { VGA_1440_900, 8 }, /* 0x360 */ - { VGA_1440_900, 15 }, /* 0x361 */ - { VGA_1440_900, 16 }, /* 0x362 */ - { VGA_1440_900, 24 }, /* 0x363 */ - { VGA_1440_900, 32 }, /* 0x364 */ - { VGA_1152_720, 8 }, /* 0x365 */ - { VGA_1152_720, 15 }, /* 0x366 */ - { VGA_1152_720, 16 }, /* 0x367 */ - { VGA_1152_720, 24 }, /* 0x368 */ - { VGA_1152_720, 32 }, /* 0x369 */ - { VGA_1024_640, 8 }, /* 0x36a */ - { VGA_1024_640, 15 }, /* 0x36b */ - { VGA_1024_640, 16 }, /* 0x36c */ - { VGA_1024_640, 24 }, /* 0x36d */ - { VGA_1024_640, 32 }, /* 0x36e */ - { VGA_800_500, 8 }, /* 0x36f */ - { VGA_800_500, 15 }, /* 0x370 */ - { VGA_800_500, 16 }, /* 0x371 */ - { VGA_800_500, 24 }, /* 0x372 */ - { VGA_800_500, 32 }, /* 0x373 */ - }; -#endif - static inline grub_size_t page_align (grub_size_t size) { @@ -312,10 +146,11 @@ find_mmap_size (void) { grub_size_t count = 0, mmap_size; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) + grub_memory_type_t type __attribute__ ((unused))) { count++; return 0; @@ -379,12 +214,14 @@ allocate_pages (grub_size_t prot_size) /* FIXME: Should request low memory from the heap when this feature is implemented. */ - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) { /* We must put real mode code in the traditional space. */ - if (type == GRUB_MACHINE_MEMORY_AVAILABLE + if (type == GRUB_MEMORY_AVAILABLE && addr <= 0x90000) { if (addr < 0x10000) @@ -559,36 +396,32 @@ grub_linux_boot (void) grub_dprintf ("linux", "code32_start = %x\n", (unsigned) params->code32_start); - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) { switch (type) { - case GRUB_MACHINE_MEMORY_AVAILABLE: + case GRUB_MEMORY_AVAILABLE: grub_e820_add_region (params->e820_map, &e820_num, addr, size, GRUB_E820_RAM); break; -#ifdef GRUB_MACHINE_MEMORY_ACPI - case GRUB_MACHINE_MEMORY_ACPI: + case GRUB_MEMORY_ACPI: grub_e820_add_region (params->e820_map, &e820_num, addr, size, GRUB_E820_ACPI); break; -#endif -#ifdef GRUB_MACHINE_MEMORY_NVS - case GRUB_MACHINE_MEMORY_NVS: + case GRUB_MEMORY_NVS: grub_e820_add_region (params->e820_map, &e820_num, addr, size, GRUB_E820_NVS); break; -#endif -#ifdef GRUB_MACHINE_MEMORY_CODE - case GRUB_MACHINE_MEMORY_CODE: + case GRUB_MEMORY_CODE: grub_e820_add_region (params->e820_map, &e820_num, addr, size, GRUB_E820_EXEC_CODE); break; -#endif default: grub_e820_add_region (params->e820_map, &e820_num, @@ -716,7 +549,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; @@ -882,7 +715,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* Video mode selection support. */ char *val = argv[i] + 4; unsigned vid_mode = GRUB_LINUX_VID_MODE_NORMAL; - struct linux_vesafb_mode *linux_mode; + struct grub_vesa_mode_table_entry *linux_mode; grub_err_t err; char *buf; @@ -925,9 +758,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), break; default: /* Ignore invalid values. */ - if (vid_mode < GRUB_LINUX_VID_MODE_VESA_START || - vid_mode >= GRUB_LINUX_VID_MODE_VESA_START + - ARRAY_SIZE (linux_vesafb_modes)) + if (vid_mode < GRUB_VESA_MODE_TABLE_START || + vid_mode > GRUB_VESA_MODE_TABLE_END) { grub_env_set ("gfxpayload", "text"); grub_printf ("%s is deprecated. Mode %d isn't recognized. " @@ -941,15 +773,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), is built-in because `vga=' parameter was used. */ params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA; - linux_mode - = &linux_vesafb_modes[vid_mode - GRUB_LINUX_VID_MODE_VESA_START]; + linux_mode = &grub_vesa_mode_table[vid_mode + - GRUB_VESA_MODE_TABLE_START]; buf = grub_xasprintf ("%ux%ux%u,%ux%u", - linux_vesafb_res[linux_mode->res_index].width, - linux_vesafb_res[linux_mode->res_index].height, + linux_mode->width, linux_mode->height, linux_mode->depth, - linux_vesafb_res[linux_mode->res_index].width, - linux_vesafb_res[linux_mode->res_index].height); + linux_mode->width, linux_mode->height); if (! buf) goto fail; @@ -1069,6 +899,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; diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index bf17863cf..1c9a77b8b 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -16,10 +16,10 @@ * along with GRUB. If not, see . */ -#include #include #ifdef GRUB_MACHINE_PCBIOS #include +#include #endif #include #include @@ -194,7 +194,8 @@ grub_multiboot_get_mbi_size (void) + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry) + elf_sec_entsize * elf_sec_num - + 256 * sizeof (struct multiboot_color); + + 256 * sizeof (struct multiboot_color) + + ALIGN_UP (sizeof (struct multiboot_apm_info), 4); } /* Fill previously allocated Multiboot mmap. */ @@ -203,28 +204,26 @@ grub_fill_multiboot_mmap (struct multiboot_mmap_entry *first_entry) { struct multiboot_mmap_entry *mmap_entry = (struct multiboot_mmap_entry *) first_entry; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) { mmap_entry->addr = addr; mmap_entry->len = size; switch (type) { - case GRUB_MACHINE_MEMORY_AVAILABLE: + case GRUB_MEMORY_AVAILABLE: mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE; break; -#ifdef GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE - case GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE: + case GRUB_MEMORY_ACPI: mmap_entry->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE; break; -#endif -#ifdef GRUB_MACHINE_MEMORY_NVS - case GRUB_MACHINE_MEMORY_NVS: + case GRUB_MEMORY_NVS: mmap_entry->type = MULTIBOOT_MEMORY_NVS; break; -#endif default: mmap_entry->type = MULTIBOOT_MEMORY_RESERVED; @@ -356,6 +355,29 @@ grub_multiboot_make_mbi (grub_uint32_t *target) ptrorig += ALIGN_UP (sizeof(PACKAGE_STRING), 4); ptrdest += ALIGN_UP (sizeof(PACKAGE_STRING), 4); +#ifdef GRUB_MACHINE_PCBIOS + { + struct grub_apm_info info; + if (grub_apm_get_info (&info)) + { + struct multiboot_apm_info *mbinfo = (void *) ptrorig; + + mbinfo->cseg = info.cseg; + mbinfo->offset = info.offset; + mbinfo->cseg_16 = info.cseg_16; + mbinfo->dseg = info.dseg; + mbinfo->flags = info.flags; + mbinfo->cseg_len = info.cseg_len; + mbinfo->dseg_len = info.dseg_len; + mbinfo->cseg_16_len = info.cseg_16_len; + mbinfo->version = info.version; + + ptrorig += ALIGN_UP (sizeof (struct multiboot_apm_info), 4); + ptrdest += ALIGN_UP (sizeof (struct multiboot_apm_info), 4); + } + } +#endif + if (modcnt) { mbi->flags |= MULTIBOOT_INFO_MODS; diff --git a/grub-core/loader/i386/pc/chainloader.c b/grub-core/loader/i386/pc/chainloader.c index 502031d0e..fd99c81d5 100644 --- a/grub-core/loader/i386/pc/chainloader.c +++ b/grub-core/loader/i386/pc/chainloader.c @@ -20,19 +20,20 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include -#include +#include #include #include #include #include +#include #include #include #include @@ -69,6 +70,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; diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index 0719cfb26..90de70f66 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -25,8 +25,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -401,6 +400,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; diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index 556f1dbf1..a9435eff3 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -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); } diff --git a/grub-core/loader/macho.c b/grub-core/loader/macho.c index 199d6f111..ecf0d8c53 100644 --- a/grub-core/loader/macho.c +++ b/grub-core/loader/macho.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -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; diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c index 018cfdcc5..44ab64eb5 100644 --- a/grub-core/loader/mips/linux.c +++ b/grub-core/loader/mips/linux.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include /* For frequencies. */ @@ -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; diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index 1de1def86..c6182109b 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -21,17 +21,14 @@ * FIXME: The following features from the Multiboot specification still * need to be implemented: * - VBE support - * - symbol table * - drives table * - ROM configuration table - * - APM table */ #include #include #include #include -#include #include #include #include @@ -39,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -74,7 +70,7 @@ grub_get_multiboot_mmap_count (void) auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr __attribute__ ((unused)), grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) + grub_memory_type_t type __attribute__ ((unused))) { count++; return 0; @@ -225,7 +221,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 +287,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; diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index f453dcc6a..08b882ed7 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -16,10 +16,11 @@ * along with GRUB. If not, see . */ -#include #include #ifdef GRUB_MACHINE_PCBIOS #include +#include +#include #endif #include #include @@ -279,7 +280,8 @@ grub_multiboot_get_mbi_size (void) + elf_sec_entsize * elf_sec_num + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry)) - + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1; + + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1 + + sizeof (struct multiboot_tag_apm) + MULTIBOOT_TAG_ALIGN - 1; } /* Fill previously allocated Multiboot mmap. */ @@ -288,28 +290,26 @@ grub_fill_multiboot_mmap (struct multiboot_tag_mmap *tag) { struct multiboot_mmap_entry *mmap_entry = tag->entries; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type) { mmap_entry->addr = addr; mmap_entry->len = size; switch (type) { - case GRUB_MACHINE_MEMORY_AVAILABLE: + case GRUB_MEMORY_AVAILABLE: mmap_entry->type = MULTIBOOT_MEMORY_AVAILABLE; break; -#ifdef GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE - case GRUB_MACHINE_MEMORY_ACPI_RECLAIMABLE: + case GRUB_MEMORY_ACPI: mmap_entry->type = MULTIBOOT_MEMORY_ACPI_RECLAIMABLE; break; -#endif -#ifdef GRUB_MACHINE_MEMORY_NVS - case GRUB_MACHINE_MEMORY_NVS: + case GRUB_MEMORY_NVS: mmap_entry->type = MULTIBOOT_MEMORY_NVS; break; -#endif default: mmap_entry->type = MULTIBOOT_MEMORY_RESERVED; @@ -515,6 +515,31 @@ grub_multiboot_make_mbi (grub_uint32_t *target) ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } +#ifdef GRUB_MACHINE_PCBIOS + { + struct grub_apm_info info; + if (grub_apm_get_info (&info)) + { + struct multiboot_tag_apm *tag = (struct multiboot_tag_apm *) ptrorig; + + tag->type = MULTIBOOT_TAG_TYPE_APM; + tag->size = sizeof (struct multiboot_tag_apm); + + tag->cseg = info.cseg; + tag->offset = info.offset; + tag->cseg_16 = info.cseg_16; + tag->dseg = info.dseg; + tag->flags = info.flags; + tag->cseg_len = info.cseg_len; + tag->dseg_len = info.dseg_len; + tag->cseg_16_len = info.cseg_16_len; + tag->version = info.version; + + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + } +#endif + { unsigned i; struct module *cur; diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c index 351d050e5..249238d45 100644 --- a/grub-core/loader/powerpc/ieee1275/linux.c +++ b/grub-core/loader/powerpc/ieee1275/linux.c @@ -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; diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c index 948729a5d..d4b5f2aea 100644 --- a/grub-core/loader/sparc64/ieee1275/linux.c +++ b/grub-core/loader/sparc64/ieee1275/linux.c @@ -24,9 +24,9 @@ #include #include #include -#include #include #include +#include static grub_dl_t my_mod; @@ -182,8 +182,10 @@ alloc_phys (grub_addr_t size) { grub_addr_t ret = (grub_addr_t) -1; - auto int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type); - int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len __attribute__((unused)), grub_uint32_t type) + auto int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len, + grub_memory_type_t type); + int NESTED_FUNC_ATTR choose (grub_uint64_t addr, grub_uint64_t len, + grub_memory_type_t type) { grub_addr_t end = addr + len; @@ -305,7 +307,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 +395,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; diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c index 17f850018..d0b32dc6f 100644 --- a/grub-core/loader/xnu.c +++ b/grub-core/loader/xnu.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -661,7 +660,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) macho = 0; if (infoplistname) - infoplist = grub_gzfile_open (infoplistname, 1); + infoplist = grub_file_open (infoplistname); else infoplist = 0; grub_errno = GRUB_ERR_NONE; @@ -756,7 +755,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); - 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 driver package"); @@ -869,7 +868,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); - 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"); @@ -909,7 +908,7 @@ grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq, if (binname) *binname = 0; - file = grub_gzfile_open (plistname, 1); + file = grub_file_open (plistname); if (! file) { grub_file_close (file); @@ -1166,7 +1165,7 @@ grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, grub_strcpy (binname + grub_strlen (binname), "/"); grub_strcpy (binname + grub_strlen (binname), binsuffix); grub_dprintf ("xnu", "%s:%s\n", plistname, binname); - binfile = grub_gzfile_open (binname, 1); + binfile = grub_file_open (binname); if (! binfile) grub_errno = GRUB_ERR_NONE; @@ -1204,7 +1203,7 @@ grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)), /* User explicitly specified plist and binary. */ if (grub_strcmp (args[1], "-") != 0) { - binfile = grub_gzfile_open (args[1], 1); + binfile = grub_file_open (args[1]); if (! binfile) { grub_error (GRUB_ERR_BAD_OS, "can't open file"); @@ -1364,15 +1363,15 @@ static const struct grub_arg_option xnu_splash_cmd_options[] = }; static grub_err_t -grub_cmd_xnu_splash (grub_extcmd_t cmd, +grub_cmd_xnu_splash (grub_extcmd_context_t ctxt, int argc, char *args[]) { grub_err_t err; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); - if (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set && - grub_strcmp (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg, + if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set && + grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg, "stretch") == 0) grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH; else @@ -1435,8 +1434,7 @@ GRUB_MOD_INIT(xnu) "Load XNU ramdisk. " "It will be seen as md0."); cmd_splash = grub_register_extcmd ("xnu_splash", - grub_cmd_xnu_splash, - GRUB_COMMAND_FLAG_BOTH, 0, + grub_cmd_xnu_splash, 0, 0, N_("Load a splash image for XNU."), xnu_splash_cmd_options); diff --git a/grub-core/loader/xnu_resume.c b/grub-core/loader/xnu_resume.c index 6aebc1f34..8f0e24483 100644 --- a/grub-core/loader/xnu_resume.c +++ b/grub-core/loader/xnu_resume.c @@ -52,6 +52,7 @@ grub_xnu_resume (char *imagename) grub_addr_t target_image; grub_err_t err; + grub_file_filter_disable_compression (); file = grub_file_open (imagename); if (! file) return 0; diff --git a/grub-core/mmap/efi/mmap.c b/grub-core/mmap/efi/mmap.c index 316c997c7..5b82a8717 100644 --- a/grub-core/mmap/efi/mmap.c +++ b/grub-core/mmap/efi/mmap.c @@ -29,9 +29,7 @@ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) grub_err_t -grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, - grub_uint64_t, - grub_uint32_t)) +grub_machine_mmap_iterate (grub_memory_hook_t hook) { grub_efi_uintn_t mmap_size = 0; grub_efi_memory_descriptor_t *map_buf = 0; @@ -69,7 +67,12 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, { case GRUB_EFI_RUNTIME_SERVICES_CODE: hook (desc->physical_start, desc->num_pages * 4096, - GRUB_MACHINE_MEMORY_CODE); + GRUB_MEMORY_CODE); + break; + + case GRUB_EFI_UNUSABLE_MEMORY: + hook (desc->physical_start, desc->num_pages * 4096, + GRUB_MEMORY_BADRAM); break; default: @@ -78,12 +81,11 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, case GRUB_EFI_RESERVED_MEMORY_TYPE: case GRUB_EFI_RUNTIME_SERVICES_DATA: - case GRUB_EFI_UNUSABLE_MEMORY: case GRUB_EFI_MEMORY_MAPPED_IO: case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE: case GRUB_EFI_PAL_CODE: hook (desc->physical_start, desc->num_pages * 4096, - GRUB_MACHINE_MEMORY_RESERVED); + GRUB_MEMORY_RESERVED); break; case GRUB_EFI_LOADER_CODE: @@ -92,17 +94,17 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, case GRUB_EFI_BOOT_SERVICES_DATA: case GRUB_EFI_CONVENTIONAL_MEMORY: hook (desc->physical_start, desc->num_pages * 4096, - GRUB_MACHINE_MEMORY_AVAILABLE); + GRUB_MEMORY_AVAILABLE); break; case GRUB_EFI_ACPI_RECLAIM_MEMORY: hook (desc->physical_start, desc->num_pages * 4096, - GRUB_MACHINE_MEMORY_ACPI); + GRUB_MEMORY_ACPI); break; case GRUB_EFI_ACPI_MEMORY_NVS: hook (desc->physical_start, desc->num_pages * 4096, - GRUB_MACHINE_MEMORY_NVS); + GRUB_MEMORY_NVS); break; } } @@ -115,29 +117,26 @@ make_efi_memtype (int type) { switch (type) { - case GRUB_MACHINE_MEMORY_CODE: + case GRUB_MEMORY_CODE: return GRUB_EFI_RUNTIME_SERVICES_CODE; /* No way to remove a chunk of memory from EFI mmap. So mark it as unusable. */ - case GRUB_MACHINE_MEMORY_HOLE: - - default: - - case GRUB_MACHINE_MEMORY_RESERVED: + case GRUB_MEMORY_HOLE: + case GRUB_MEMORY_RESERVED: return GRUB_EFI_UNUSABLE_MEMORY; - case GRUB_MACHINE_MEMORY_AVAILABLE: + case GRUB_MEMORY_AVAILABLE: return GRUB_EFI_CONVENTIONAL_MEMORY; - case GRUB_MACHINE_MEMORY_ACPI: - return GRUB_EFI_ACPI_RECLAIM_MEMORY; - - case GRUB_MACHINE_MEMORY_NVS: + case GRUB_MEMORY_ACPI: return GRUB_EFI_ACPI_RECLAIM_MEMORY; + case GRUB_MEMORY_NVS: + return GRUB_EFI_ACPI_MEMORY_NVS; } + return GRUB_EFI_UNUSABLE_MEMORY; } struct overlay diff --git a/grub-core/mmap/i386/mmap.c b/grub-core/mmap/i386/mmap.c index f6e16129e..e9c030b7b 100644 --- a/grub-core/mmap/i386/mmap.c +++ b/grub-core/mmap/i386/mmap.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -33,12 +34,12 @@ grub_mmap_malign_and_register (grub_uint64_t align, grub_uint64_t size, grub_uint64_t highestlow = 0; auto int NESTED_FUNC_ATTR find_hook (grub_uint64_t, grub_uint64_t, - grub_uint32_t); + grub_memory_type_t); int NESTED_FUNC_ATTR find_hook (grub_uint64_t start, grub_uint64_t rangesize, - grub_uint32_t memtype) + grub_memory_type_t memtype) { grub_uint64_t end = start + rangesize; - if (memtype != GRUB_MACHINE_MEMORY_AVAILABLE) + if (memtype != GRUB_MEMORY_AVAILABLE) return 0; if (end > 0x100000) end = 0x100000; diff --git a/grub-core/mmap/i386/pc/mmap.c b/grub-core/mmap/i386/pc/mmap.c index 7d5a43fec..8dec083f8 100644 --- a/grub-core/mmap/i386/pc/mmap.c +++ b/grub-core/mmap/i386/pc/mmap.c @@ -57,7 +57,7 @@ preboot (int noreturn __attribute__ ((unused))) auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { grub_dprintf ("mmap", "mmap chunk %llx-%llx:%x\n", addr, addr + size, type); hookmmapcur->addr = addr; @@ -135,7 +135,7 @@ malloc_hook (void) grub_uint32_t); int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)), grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) + grub_memory_type_t type __attribute__ ((unused))) { regcount++; return 0; @@ -172,7 +172,7 @@ malloc_hook (void) reentry = 1; hooktarget = grub_mmap_malign_and_register (16, hooksize, &mmapregion, - GRUB_MACHINE_MEMORY_RESERVED, + GRUB_MEMORY_RESERVED, GRUB_MMAP_MALLOC_LOW); reentry = 0; diff --git a/grub-core/mmap/i386/uppermem.c b/grub-core/mmap/i386/uppermem.c index cd1a45239..2aa430155 100644 --- a/grub-core/mmap/i386/uppermem.c +++ b/grub-core/mmap/i386/uppermem.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -26,11 +27,12 @@ grub_mmap_get_lower (void) { grub_uint64_t lower = 0; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { - if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + if (type != GRUB_MEMORY_AVAILABLE) return 0; if (addr == 0) lower = size; @@ -48,11 +50,12 @@ grub_mmap_get_upper (void) { grub_uint64_t upper = 0; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { - if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + if (type != GRUB_MEMORY_AVAILABLE) return 0; if (addr <= 0x100000 && addr + size > 0x100000) upper = addr + size - 0x100000; @@ -69,11 +72,12 @@ grub_mmap_get_post64 (void) { grub_uint64_t post64 = 0; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { - if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + if (type != GRUB_MEMORY_AVAILABLE) return 0; if (addr <= 0x4000000 && addr + size > 0x4000000) post64 = addr + size - 0x4000000; diff --git a/grub-core/mmap/mips/yeeloong/uppermem.c b/grub-core/mmap/mips/yeeloong/uppermem.c index 3c5f814de..723b6a888 100644 --- a/grub-core/mmap/mips/yeeloong/uppermem.c +++ b/grub-core/mmap/mips/yeeloong/uppermem.c @@ -27,11 +27,12 @@ grub_mmap_get_lower (void) { grub_uint64_t lower = 0; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { - if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + if (type != GRUB_MEMORY_AVAILABLE) return 0; if (addr == 0) lower = size; @@ -49,11 +50,12 @@ grub_mmap_get_upper (void) { grub_uint64_t upper = 0; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { - if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + if (type != GRUB_MEMORY_AVAILABLE) return 0; if (addr <= GRUB_ARCH_HIGHMEMPSTART && addr + size > GRUB_ARCH_HIGHMEMPSTART) diff --git a/grub-core/mmap/mmap.c b/grub-core/mmap/mmap.c index a1afc8b06..7c3430e9f 100644 --- a/grub-core/mmap/mmap.c +++ b/grub-core/mmap/mmap.c @@ -17,8 +17,8 @@ * along with GRUB. If not, see . */ -#include #include +#include #include #include #include @@ -34,8 +34,7 @@ static int curhandle = 1; #endif grub_err_t -grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, - grub_uint64_t, grub_uint32_t)) +grub_mmap_iterate (grub_memory_hook_t hook) { /* This function resolves overlapping regions and sorts the memory map. @@ -48,27 +47,17 @@ grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, 3 - unusable memory 4 - a range deliberately empty */ - int priority[GRUB_MACHINE_MEMORY_MAX_TYPE + 2] = + int priority[] = { -#ifdef GRUB_MACHINE_MEMORY_AVAILABLE - [GRUB_MACHINE_MEMORY_AVAILABLE] = 1, -#endif -#if defined (GRUB_MACHINE_MEMORY_RESERVED) && GRUB_MACHINE_MEMORY_RESERVED != GRUB_MACHINE_MEMORY_HOLE - [GRUB_MACHINE_MEMORY_RESERVED] = 3, -#endif -#ifdef GRUB_MACHINE_MEMORY_ACPI - [GRUB_MACHINE_MEMORY_ACPI] = 2, -#endif -#ifdef GRUB_MACHINE_MEMORY_CODE - [GRUB_MACHINE_MEMORY_CODE] = 3, -#endif -#ifdef GRUB_MACHINE_MEMORY_NVS - [GRUB_MACHINE_MEMORY_NVS] = 3, -#endif - [GRUB_MACHINE_MEMORY_HOLE] = 4, + [GRUB_MEMORY_AVAILABLE] = 1, + [GRUB_MEMORY_RESERVED] = 3, + [GRUB_MEMORY_ACPI] = 2, + [GRUB_MEMORY_CODE] = 3, + [GRUB_MEMORY_NVS] = 3, + [GRUB_MEMORY_HOLE] = 4, }; - int i, k, done; + int i, done; /* Scanline events. */ struct grub_mmap_scan @@ -89,7 +78,7 @@ grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, /* Current scanline event. */ int curtype; /* How many regions of given type overlap at current location? */ - int present[GRUB_MACHINE_MEMORY_MAX_TYPE + 2]; + int present[ARRAY_SIZE (priority)]; /* Number of mmap chunks. */ int mmap_num; @@ -101,7 +90,7 @@ grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint32_t); int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)), grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) + grub_memory_type_t type __attribute__ ((unused))) { mmap_num++; return 0; @@ -111,17 +100,17 @@ grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint32_t); int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type) + grub_memory_type_t type) { scanline_events[i].pos = addr; scanline_events[i].type = 0; - if (type <= GRUB_MACHINE_MEMORY_MAX_TYPE && priority[type]) + if (type < ARRAY_SIZE (priority) && priority[type]) scanline_events[i].memtype = type; else { grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n", type); - scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED; + scanline_events[i].memtype = GRUB_MEMORY_RESERVED; } i++; @@ -160,12 +149,10 @@ grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, { scanline_events[i].pos = cur->start; scanline_events[i].type = 0; - if (cur->type == GRUB_MACHINE_MEMORY_HOLE - || (cur->type >= 0 && cur->type <= GRUB_MACHINE_MEMORY_MAX_TYPE - && priority[cur->type])) + if (cur->type < ARRAY_SIZE (priority) && priority[cur->type]) scanline_events[i].memtype = cur->type; else - scanline_events[i].memtype = GRUB_MACHINE_MEMORY_RESERVED; + scanline_events[i].memtype = GRUB_MEMORY_RESERVED; i++; scanline_events[i].pos = cur->end; @@ -201,6 +188,7 @@ grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, lasttype = scanline_events[0].memtype; for (i = 0; i < 2 * mmap_num; i++) { + unsigned k; /* Process event. */ if (scanline_events[i].type) present[scanline_events[i].memtype]--; @@ -209,7 +197,7 @@ grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, /* Determine current region type. */ curtype = -1; - for (k = 0; k <= GRUB_MACHINE_MEMORY_MAX_TYPE + 1; k++) + for (k = 0; k < ARRAY_SIZE (priority); k++) if (present[k] && (curtype == -1 || priority[k] > priority[curtype])) curtype = k; @@ -217,7 +205,7 @@ grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, if ((curtype == -1 || curtype != lasttype) && lastaddr != scanline_events[i].pos && lasttype != -1 - && lasttype != GRUB_MACHINE_MEMORY_HOLE + && lasttype != GRUB_MEMORY_HOLE && hook (lastaddr, scanline_events[i].pos - lastaddr, lasttype)) { grub_free (scanline_events); @@ -324,10 +312,11 @@ grub_cmd_badram (grub_command_t cmd __attribute__ ((unused)), char * str; grub_uint64_t badaddr, badmask; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, + grub_memory_type_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, - grub_uint32_t type __attribute__ ((unused))) + grub_memory_type_t type __attribute__ ((unused))) { grub_uint64_t iterator, low, high, cur; int tail, var; @@ -370,7 +359,7 @@ grub_cmd_badram (grub_command_t cmd __attribute__ ((unused)), { grub_dprintf ("badram", "%llx (size %llx) is a badram range\n", (unsigned long long) cur, (1ULL << tail)); - grub_mmap_register (cur, (1ULL << tail), GRUB_MACHINE_MEMORY_HOLE); + grub_mmap_register (cur, (1ULL << tail), GRUB_MEMORY_HOLE); } return 0; } diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c index bf1efbfdd..459d4cdbd 100644 --- a/grub-core/normal/auth.c +++ b/grub-core/normal/auth.c @@ -161,7 +161,7 @@ grub_username_get (char buf[], unsigned buf_size) while (1) { - key = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + key = grub_getkey (); if (key == '\n' || key == '\r') break; @@ -248,3 +248,27 @@ grub_auth_check_authentication (const char *userlist) return GRUB_ACCESS_DENIED; } + +static grub_err_t +grub_cmd_authenticate (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + return grub_auth_check_authentication ((argc >= 1) ? args[0] : ""); +} + +static grub_command_t cmd; + +void +grub_normal_auth_init (void) +{ + cmd = grub_register_command ("authenticate", + grub_cmd_authenticate, + N_("[USERLIST]"), N_("Authenticate users")); + +} + +void +grub_normal_auth_fini (void) +{ + grub_unregister_command (cmd); +} diff --git a/grub-core/normal/cmdline.c b/grub-core/normal/cmdline.c index 3647dcd3a..b8c20d91c 100644 --- a/grub-core/normal/cmdline.c +++ b/grub-core/normal/cmdline.c @@ -388,16 +388,18 @@ grub_cmdline_get (const char *prompt) grub_refresh (); - while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r') + while ((key = grub_getkey ()) != '\n' && key != '\r') { switch (key) { - case 1: /* Ctrl-a */ + case GRUB_TERM_CTRL | 'a': + case GRUB_TERM_KEY_HOME: lpos = 0; cl_set_pos_all (); break; - case 2: /* Ctrl-b */ + case GRUB_TERM_CTRL | 'b': + case GRUB_TERM_KEY_LEFT: if (lpos > 0) { lpos--; @@ -405,12 +407,14 @@ grub_cmdline_get (const char *prompt) } break; - case 5: /* Ctrl-e */ + case GRUB_TERM_CTRL | 'e': + case GRUB_TERM_KEY_END: lpos = llen; cl_set_pos_all (); break; - case 6: /* Ctrl-f */ + case GRUB_TERM_CTRL | 'f': + case GRUB_TERM_KEY_RIGHT: if (lpos < llen) { lpos++; @@ -418,7 +422,8 @@ grub_cmdline_get (const char *prompt) } break; - case 9: /* Ctrl-i or TAB */ + case GRUB_TERM_CTRL | 'i': + case '\t': { int restore; char *insertu8; @@ -492,7 +497,7 @@ grub_cmdline_get (const char *prompt) } break; - case 11: /* Ctrl-k */ + case GRUB_TERM_CTRL | 'k': if (lpos < llen) { if (kill_buf) @@ -516,7 +521,8 @@ grub_cmdline_get (const char *prompt) } break; - case 14: /* Ctrl-n */ + case GRUB_TERM_CTRL | 'n': + case GRUB_TERM_KEY_DOWN: { grub_uint32_t *hist; @@ -534,7 +540,9 @@ grub_cmdline_get (const char *prompt) break; } - case 16: /* Ctrl-p */ + + case GRUB_TERM_KEY_UP: + case GRUB_TERM_CTRL | 'p': { grub_uint32_t *hist; @@ -553,7 +561,7 @@ grub_cmdline_get (const char *prompt) } break; - case 21: /* Ctrl-u */ + case GRUB_TERM_CTRL | 'u': if (lpos > 0) { grub_size_t n = lpos; @@ -579,7 +587,7 @@ grub_cmdline_get (const char *prompt) } break; - case 25: /* Ctrl-y */ + case GRUB_TERM_CTRL | 'y': if (kill_buf) cl_insert (kill_buf); break; @@ -598,7 +606,8 @@ grub_cmdline_get (const char *prompt) break; /* fall through */ - case 4: /* Ctrl-d */ + case GRUB_TERM_CTRL | 'd': + case GRUB_TERM_KEY_DC: if (lpos < llen) cl_delete (1); break; diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c index d127f9baf..197cb1145 100644 --- a/grub-core/normal/completion.c +++ b/grub-core/normal/completion.c @@ -160,14 +160,23 @@ iterate_dev (const char *devname) if (dev) { - if (dev->disk && dev->disk->has_partitions) + char tmp[grub_strlen (devname) + sizeof (",")]; + + grub_memcpy (tmp, devname, grub_strlen (devname)); + + if (grub_strcmp (devname, current_word) == 0) { - if (add_completion (devname, ",", GRUB_COMPLETION_TYPE_DEVICE)) + if (add_completion (devname, ")", GRUB_COMPLETION_TYPE_PARTITION)) return 1; + + if (dev->disk) + if (grub_partition_iterate (dev->disk, iterate_partition)) + return 1; } else { - if (add_completion (devname, ")", GRUB_COMPLETION_TYPE_DEVICE)) + grub_memcpy (tmp + grub_strlen (devname), "", sizeof ("")); + if (add_completion (tmp, "", GRUB_COMPLETION_TYPE_DEVICE)) return 1; } } @@ -200,7 +209,7 @@ complete_device (void) if (dev) { - if (dev->disk && dev->disk->has_partitions) + if (dev->disk) { if (grub_partition_iterate (dev->disk, iterate_partition)) { @@ -247,7 +256,8 @@ complete_file (void) goto fail; } - dir = grub_strchr (current_word, '/'); + dir = grub_strchr (current_word + (device ? 2 + grub_strlen (device) : 0), + '/'); last_dir = grub_strrchr (current_word, '/'); if (dir) { @@ -419,11 +429,8 @@ grub_normal_do_completion (char *buf, int *restore, { if (cmd->prio & GRUB_PRIO_LIST_FLAG_ACTIVE) { - if (cmd->flags & GRUB_COMMAND_FLAG_CMDLINE) - { - if (add_completion (cmd->name, " ", GRUB_COMPLETION_TYPE_COMMAND)) - goto fail; - } + if (add_completion (cmd->name, " ", GRUB_COMPLETION_TYPE_COMMAND)) + goto fail; } } } @@ -500,8 +507,8 @@ grub_normal_do_completion (char *buf, int *restore, fail: if (argc != 0) { - grub_free (argv); grub_free (argv[0]); + grub_free (argv); } grub_free (match); grub_errno = GRUB_ERR_NONE; diff --git a/grub-core/normal/dyncmd.c b/grub-core/normal/dyncmd.c index a3cafa514..ed98855eb 100644 --- a/grub-core/normal/dyncmd.c +++ b/grub-core/normal/dyncmd.c @@ -23,16 +23,21 @@ #include #include #include +#include +#include #include static grub_err_t -grub_dyncmd_dispatcher (struct grub_command *cmd, +grub_dyncmd_dispatcher (struct grub_extcmd_context *ctxt, int argc, char **args) { - char *modname = cmd->data; + char *modname; grub_dl_t mod; grub_err_t ret; + grub_extcmd_t extcmd = ctxt->extcmd; + grub_command_t cmd = extcmd->cmd; + modname = extcmd->data; mod = grub_dl_load (modname); if (mod) { @@ -42,11 +47,17 @@ grub_dyncmd_dispatcher (struct grub_command *cmd, grub_dl_ref (mod); name = (char *) cmd->name; - grub_unregister_command (cmd); + grub_unregister_extcmd (extcmd); cmd = grub_command_find (name); if (cmd) - ret = (cmd->func) (cmd, argc, args); + { + if (cmd->flags & GRUB_COMMAND_FLAG_BLOCKS && + cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) + ret = grub_extcmd_dispatcher (cmd, argc, args, ctxt->script); + else + ret = (cmd->func) (cmd, argc, args); + } else ret = grub_errno; @@ -81,13 +92,14 @@ read_command_list (const char *prefix) for (ptr = grub_command_list; ptr; ptr = next) { next = ptr->next; - if (ptr->func == grub_dyncmd_dispatcher) + if (ptr->flags & GRUB_COMMAND_FLAG_DYNCMD) { if (last) last->next = ptr->next; else grub_command_list = ptr->next; grub_free (ptr); + grub_free (ptr->data); /* extcmd struct */ } else last = ptr; @@ -96,7 +108,7 @@ read_command_list (const char *prefix) for (;; grub_free (buf)) { char *p, *name, *modname; - grub_command_t cmd; + grub_extcmd_t cmd; int prio = 0; buf = grub_file_getline (file); @@ -139,16 +151,19 @@ read_command_list (const char *prefix) continue; } - cmd = grub_register_command_prio (name, - grub_dyncmd_dispatcher, - 0, N_("not loaded"), prio); + cmd = grub_register_extcmd_prio (name, + grub_dyncmd_dispatcher, + GRUB_COMMAND_FLAG_BLOCKS + | GRUB_COMMAND_FLAG_EXTCMD + | GRUB_COMMAND_FLAG_DYNCMD, + 0, N_("not loaded"), 0, + prio); if (! cmd) { grub_free (name); grub_free (modname); continue; } - cmd->flags |= GRUB_COMMAND_FLAG_DYNCMD; cmd->data = modname; /* Update the active flag. */ diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index cddb15216..f2e5eaf51 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -141,209 +141,6 @@ free_menu (grub_menu_t menu) grub_env_unset_menu (); } -static void -free_menu_entry_classes (struct grub_menu_entry_class *head) -{ - /* Free all the classes. */ - while (head) - { - struct grub_menu_entry_class *next; - - grub_free (head->name); - next = head->next; - grub_free (head); - head = next; - } -} - -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. */ -grub_err_t -grub_normal_add_menu_entry (int argc, const char **args, - const char *sourcecode) -{ - const char *menutitle = 0; - const char *menusourcecode; - grub_menu_t menu; - grub_menu_entry_t *last; - int failed = 0; - int i; - struct grub_menu_entry_class *classes_head; /* Dummy head node for list. */ - struct grub_menu_entry_class *classes_tail; - char *users = NULL; - int hotkey = 0; - - /* Allocate dummy head node for class list. */ - classes_head = grub_zalloc (sizeof (struct grub_menu_entry_class)); - if (! classes_head) - return grub_errno; - classes_tail = classes_head; - - menu = grub_env_get_menu (); - if (! menu) - return grub_error (GRUB_ERR_MENU, "no menu context"); - - last = &menu->entry_list; - - menusourcecode = grub_strdup (sourcecode); - if (! menusourcecode) - return grub_errno; - - /* Parse menu arguments. */ - for (i = 0; i < argc; i++) - { - /* Capture arguments. */ - if (grub_strncmp ("--", args[i], 2) == 0 && i + 1 < argc) - { - const char *arg = &args[i][2]; - - /* Handle menu class. */ - if (grub_strcmp(arg, "class") == 0) - { - char *class_name; - struct grub_menu_entry_class *new_class; - - i++; - class_name = grub_strdup (args[i]); - if (! class_name) - { - failed = 1; - break; - } - - /* Create a new class and add it at the tail of the list. */ - new_class = grub_zalloc (sizeof (struct grub_menu_entry_class)); - if (! new_class) - { - grub_free (class_name); - failed = 1; - break; - } - /* Fill in the new class node. */ - new_class->name = class_name; - /* Link the tail to it, and make it the new tail. */ - classes_tail->next = new_class; - classes_tail = new_class; - continue; - } - else if (grub_strcmp(arg, "users") == 0) - { - i++; - users = grub_strdup (args[i]); - if (! users) - { - failed = 1; - break; - } - - continue; - } - else if (grub_strcmp(arg, "hotkey") == 0) - { - unsigned j; - - i++; - if (args[i][1] == 0) - { - hotkey = args[i][0]; - continue; - } - - for (j = 0; j < ARRAY_SIZE (hotkey_aliases); j++) - if (grub_strcmp (args[i], hotkey_aliases[j].name) == 0) - { - hotkey = hotkey_aliases[j].key; - break; - } - - if (j < ARRAY_SIZE (hotkey_aliases)) - continue; - - failed = 1; - grub_error (GRUB_ERR_MENU, - "Invalid hotkey: '%s'.", args[i]); - break; - } - else - { - /* Handle invalid argument. */ - failed = 1; - grub_error (GRUB_ERR_MENU, - "invalid argument for menuentry: %s", args[i]); - break; - } - } - - /* Capture title. */ - if (! menutitle) - { - menutitle = grub_strdup (args[i]); - } - else - { - failed = 1; - grub_error (GRUB_ERR_MENU, - "too many titles for menuentry: %s", args[i]); - break; - } - } - - /* Validate arguments. */ - if ((! failed) && (! menutitle)) - { - grub_error (GRUB_ERR_MENU, "menuentry is missing title"); - failed = 1; - } - - /* If argument parsing failed, free any allocated resources. */ - if (failed) - { - free_menu_entry_classes (classes_head); - grub_free ((void *) menutitle); - grub_free ((void *) menusourcecode); - - /* Here we assume that grub_error has been used to specify failure details. */ - return grub_errno; - } - - /* Add the menu entry at the end of the list. */ - while (*last) - last = &(*last)->next; - - *last = grub_zalloc (sizeof (**last)); - if (! *last) - { - free_menu_entry_classes (classes_head); - grub_free ((void *) menutitle); - grub_free ((void *) menusourcecode); - return grub_errno; - } - - (*last)->title = menutitle; - (*last)->hotkey = hotkey; - (*last)->classes = classes_head; - if (users) - (*last)->restricted = 1; - (*last)->users = users; - (*last)->sourcecode = menusourcecode; - - menu->size++; - - return GRUB_ERR_NONE; -} - static grub_menu_t read_config_file (const char *config) { @@ -677,8 +474,13 @@ static void (*grub_xputs_saved) (const char *str); GRUB_MOD_INIT(normal) { + /* Previously many modules depended on gzio. Be nice to user and load it. */ + grub_dl_load ("gzio"); + + grub_normal_auth_init (); grub_context_init (); grub_script_init (); + grub_menu_init (); grub_xputs_saved = grub_xputs; grub_xputs = grub_xputs_normal; @@ -718,6 +520,8 @@ GRUB_MOD_FINI(normal) { grub_context_fini (); grub_script_fini (); + grub_menu_fini (); + grub_normal_auth_fini (); grub_xputs = grub_xputs_saved; diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c index cc84ce38c..62b0d0a6a 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c @@ -153,44 +153,6 @@ get_and_remove_first_entry_number (const char *name) return entry; } -static void -grub_menu_execute_entry_real (grub_menu_entry_t entry) -{ - const char *source; - - auto grub_err_t getline (char **line, int cont); - grub_err_t getline (char **line, int cont __attribute__ ((unused))) - { - const char *p; - - if (!source) - { - *line = 0; - return 0; - } - - p = grub_strchr (source, '\n'); - - if (p) - *line = grub_strndup (source, p - source); - else - *line = grub_strdup (source); - source = p ? p + 1 : 0; - return 0; - } - - source = entry->sourcecode; - - while (source) - { - char *line; - - getline (&line, 0); - grub_normal_parse_line (line, getline); - grub_free (line); - } -} - /* Run a menu entry. */ void grub_menu_execute_entry(grub_menu_entry_t entry) @@ -208,8 +170,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry) } grub_env_set ("chosen", entry->title); - - grub_menu_execute_entry_real (entry); + grub_script_execute_sourcecode (entry->sourcecode, entry->argc, entry->args); if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) /* Implicit execution of boot, only if something is loaded. */ @@ -446,7 +407,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) if (grub_checkkey () >= 0 || timeout < 0) { - c = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + c = grub_getkey (); if (timeout >= 0) { @@ -457,31 +418,36 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) switch (c) { - case GRUB_TERM_HOME: + case GRUB_TERM_KEY_HOME: + case GRUB_TERM_CTRL | 'a': current_entry = 0; menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_END: + case GRUB_TERM_KEY_END: + case GRUB_TERM_CTRL | 'e': current_entry = menu->size - 1; menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_UP: + case GRUB_TERM_KEY_UP: + case GRUB_TERM_CTRL | 'p': case '^': if (current_entry > 0) current_entry--; menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_DOWN: + case GRUB_TERM_CTRL | 'n': + case GRUB_TERM_KEY_DOWN: case 'v': if (current_entry < menu->size - 1) current_entry++; menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_PPAGE: + case GRUB_TERM_CTRL | 'g': + case GRUB_TERM_KEY_PPAGE: if (current_entry < GRUB_MENU_PAGE_SIZE) current_entry = 0; else @@ -489,7 +455,8 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) menu_set_chosen_entry (current_entry); break; - case GRUB_TERM_NPAGE: + case GRUB_TERM_CTRL | 'c': + case GRUB_TERM_KEY_NPAGE: if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size) current_entry += GRUB_MENU_PAGE_SIZE; else @@ -499,7 +466,8 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) case '\n': case '\r': - case 6: + case GRUB_TERM_KEY_RIGHT: + case GRUB_TERM_CTRL | 'f': menu_fini (); *auto_boot = 0; return current_entry; diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c index 238c94ecd..87292d445 100644 --- a/grub-core/normal/menu_entry.c +++ b/grub-core/normal/menu_entry.c @@ -1272,7 +1272,7 @@ grub_menu_entry_run (grub_menu_entry_t entry) while (1) { - int c = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + int c = grub_getkey (); if (screen->completion_shown) { @@ -1288,70 +1288,79 @@ grub_menu_entry_run (grub_menu_entry_t entry) switch (c) { - case 16: /* C-p */ + case GRUB_TERM_KEY_UP: + case GRUB_TERM_CTRL | 'p': if (! previous_line (screen, 1)) goto fail; break; - case 14: /* C-n */ + case GRUB_TERM_CTRL | 'n': + case GRUB_TERM_KEY_DOWN: if (! next_line (screen, 1)) goto fail; break; - case 6: /* C-f */ + case GRUB_TERM_CTRL | 'f': + case GRUB_TERM_KEY_RIGHT: if (! forward_char (screen, 1)) goto fail; break; - case 2: /* C-b */ + case GRUB_TERM_CTRL | 'b': + case GRUB_TERM_KEY_LEFT: if (! backward_char (screen, 1)) goto fail; break; - case 1: /* C-a */ + case GRUB_TERM_CTRL | 'a': + case GRUB_TERM_KEY_HOME: if (! beginning_of_line (screen, 1)) goto fail; break; - case 5: /* C-e */ + case GRUB_TERM_CTRL | 'e': + case GRUB_TERM_KEY_END: if (! end_of_line (screen, 1)) goto fail; break; - case '\t': /* C-i */ + case GRUB_TERM_CTRL | 'i': + case '\t': if (! complete (screen, prev_c == c, 1)) goto fail; break; - case 4: /* C-d */ + case GRUB_TERM_CTRL | 'd': + case GRUB_TERM_KEY_DC: if (! delete_char (screen, 1)) goto fail; break; - case 8: /* C-h */ + case GRUB_TERM_CTRL | 'h': + case '\b': if (! backward_delete_char (screen, 1)) goto fail; break; - case 11: /* C-k */ + case GRUB_TERM_CTRL | 'k': if (! kill_line (screen, prev_c == c, 1)) goto fail; break; - case 21: /* C-u */ + case GRUB_TERM_CTRL | 'u': /* FIXME: What behavior is good for this key? */ break; - case 25: /* C-y */ + case GRUB_TERM_CTRL | 'y': if (! yank (screen, 1)) goto fail; break; - case 12: /* C-l */ + case GRUB_TERM_CTRL | 'l': /* FIXME: centering. */ goto refresh; - case 15: /* C-o */ + case GRUB_TERM_CTRL | 'o': if (! open_line (screen, 1)) goto fail; break; @@ -1366,11 +1375,13 @@ grub_menu_entry_run (grub_menu_entry_t entry) destroy_screen (screen); return; - case 3: /* C-c */ + case GRUB_TERM_CTRL | 'c': + case GRUB_TERM_KEY_F2: grub_cmdline_run (1); goto refresh; - case 24: /* C-x */ + case GRUB_TERM_CTRL | 'x': + case GRUB_TERM_KEY_F10: { int chars_before = grub_normal_get_char_counter (); run (screen); @@ -1380,9 +1391,9 @@ grub_menu_entry_run (grub_menu_entry_t entry) } goto refresh; - case 18: /* C-r */ - case 19: /* C-s */ - case 20: /* C-t */ + case GRUB_TERM_CTRL | 'r': + case GRUB_TERM_CTRL | 's': + case GRUB_TERM_CTRL | 't': /* FIXME */ break; diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c index 3e3e7e2fa..fc4a89196 100644 --- a/grub-core/normal/menu_text.c +++ b/grub-core/normal/menu_text.c @@ -120,17 +120,10 @@ print_message (int nested, int edit, struct grub_term_output *term) if (edit) { grub_putcode ('\n', term); -#ifdef GRUB_MACHINE_EFI grub_print_message_indented (_("Minimum Emacs-like screen editing is \ -supported. TAB lists completions. Press F1 to boot, F2=Ctrl-a, F3=Ctrl-e, \ -F4 for a command-line or ESC to discard edits and return to the GRUB menu."), - STANDARD_MARGIN, STANDARD_MARGIN, term); -#else - grub_print_message_indented (_("Minimum Emacs-like screen editing is \ -supported. TAB lists completions. Press Ctrl-x to boot, Ctrl-c for a \ +supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a \ command-line or ESC to discard edits and return to the GRUB menu."), STANDARD_MARGIN, STANDARD_MARGIN, term); -#endif } else { diff --git a/grub-core/normal/misc.c b/grub-core/normal/misc.c index 2b84b1c82..d81b6d26f 100644 --- a/grub-core/normal/misc.c +++ b/grub-core/normal/misc.c @@ -26,6 +26,7 @@ #include #include #include +#include /* Print the information on the device NAME. */ grub_err_t @@ -107,10 +108,18 @@ grub_normal_print_device_info (const char *name) grub_errno = GRUB_ERR_NONE; } } - else if (! dev->disk->has_partitions || dev->disk->partition) - grub_printf ("%s", _("Unknown filesystem")); else - grub_printf ("%s", _("Partition table")); + grub_printf ("%s", _("Not a known filesystem")); + + if (dev->disk->partition) + grub_printf (_(" - Partition start at %u"), + grub_partition_get_start (dev->disk->partition)); + if (grub_disk_get_size (dev->disk) == GRUB_DISK_SIZE_UNKNOWN) + grub_printf (_(" - Total size unknown"), + grub_disk_get_size (dev->disk)); + else + grub_printf (_(" - Total size %u sectors"), + grub_disk_get_size (dev->disk)); grub_device_close (dev); } diff --git a/grub-core/normal/term.c b/grub-core/normal/term.c index b55c0f06a..760900e86 100644 --- a/grub-core/normal/term.c +++ b/grub-core/normal/term.c @@ -657,7 +657,7 @@ put_glyphs_terminal (const struct grub_unicode_glyph *visual, >= (grub_ssize_t) grub_term_height (term) - 2) { state->backlog_glyphs = visual_ptr + 1; - state->backlog_len = visual_len - (visual - visual_ptr) - 1; + state->backlog_len = visual_len - (visual_ptr - visual) - 1; return 1; } @@ -688,6 +688,7 @@ print_backlog (struct grub_term_output *term, grub_free (state->free); state->free = NULL; state->backlog_len = 0; + state->backlog_ucs4 = 0; } return ret; } @@ -703,6 +704,7 @@ print_backlog (struct grub_term_output *term, grub_free (state->free); state->free = NULL; state->backlog_len = 0; + state->backlog_glyphs = 0; } return ret; } diff --git a/grub-core/partmap/gpt.c b/grub-core/partmap/gpt.c index 0dd670cce..c9393d932 100644 --- a/grub-core/partmap/gpt.c +++ b/grub-core/partmap/gpt.c @@ -32,6 +32,10 @@ static grub_uint8_t grub_gpt_magic[8] = static const grub_gpt_part_type_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY; +#ifdef GRUB_UTIL +static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT; +#endif + /* 512 << 7 = 65536 byte sectors. */ #define MAX_SECTOR_LOG 7 @@ -97,6 +101,7 @@ gpt_partition_map_iterate (grub_disk_t disk, part.number = i; part.index = last_offset; part.partmap = &grub_gpt_partition_map; + part.parent = disk->partition; grub_dprintf ("gpt", "GPT entry %d: start=%lld, length=%lld\n", i, (unsigned long long) part.start, @@ -117,12 +122,73 @@ gpt_partition_map_iterate (grub_disk_t disk, return GRUB_ERR_NONE; } +#ifdef GRUB_UTIL +static grub_err_t +gpt_partition_map_embed (struct grub_disk *disk, unsigned int nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t *sectors) +{ + grub_disk_addr_t start = 0, len = 0; + unsigned i; + grub_err_t err; + + auto int NESTED_FUNC_ATTR find_usable_region (grub_disk_t disk, + const grub_partition_t p); + int NESTED_FUNC_ATTR find_usable_region (grub_disk_t disk __attribute__ ((unused)), + const grub_partition_t p) + { + struct grub_gpt_partentry gptdata; + + disk->partition = p->parent; + if (grub_disk_read (disk, p->offset, p->index, + sizeof (gptdata), &gptdata)) + return 0; + + /* If there's an embed region, it is in a dedicated partition. */ + if (! grub_memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16)) + { + start = p->start; + len = p->len; + return 1; + } + + return 0; + } + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "GPT curently supports only PC-BIOS embedding"); + + err = gpt_partition_map_iterate (disk, find_usable_region); + if (err) + return err; + + if (len == 0) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + "This GPT partition label has no BIOS Boot Partition;" + " embedding won't be possible!"); + + if (len < nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Your BIOS Boot Partition is too small;" + " embedding won't be possible!"); + + for (i = 0; i < nsectors; i++) + sectors[i] = start + i; + + return GRUB_ERR_NONE; +} +#endif + /* Partition map type. */ static struct grub_partition_map grub_gpt_partition_map = { .name = "gpt", .iterate = gpt_partition_map_iterate, +#ifdef GRUB_UTIL + .embed = gpt_partition_map_embed +#endif }; GRUB_MOD_INIT(part_gpt) diff --git a/grub-core/partmap/msdos.c b/grub-core/partmap/msdos.c index 3898d09fa..7dab4aa0f 100644 --- a/grub-core/partmap/msdos.c +++ b/grub-core/partmap/msdos.c @@ -133,12 +133,128 @@ pc_partition_map_iterate (grub_disk_t disk, return grub_errno; } +#ifdef GRUB_UTIL +static grub_err_t +pc_partition_map_embed (struct grub_disk *disk, unsigned int nsectors, + grub_embed_type_t embed_type, + grub_disk_addr_t *sectors) +{ + grub_disk_addr_t end = ~0ULL; + struct grub_msdos_partition_mbr mbr; + int labeln = 0; + /* Any value different than `p.offset' will satisfy the check during + first loop. */ + grub_disk_addr_t lastaddr = 1; + grub_disk_addr_t ext_offset = 0; + grub_disk_addr_t offset = 0; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "PC-style partitions curently support " + "only PC-BIOS embedding"); + + if (disk->partition) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Embedding on MSDOS subpartition isn't supported"); + + while (1) + { + int i; + struct grub_msdos_partition_entry *e; + grub_err_t err; + + /* Read the MBR. */ + err = grub_disk_read (disk, offset, 0, sizeof (mbr), &mbr); + if (err) + return err; + + /* This is our loop-detection algorithm. It works the following way: + It saves last position which was a power of two. Then it compares the + saved value with a current one. This way it's guaranteed that the loop + will be broken by at most third walk. + */ + if (labeln && lastaddr == offset) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected"); + + labeln++; + if ((labeln & (labeln - 1)) == 0) + lastaddr = offset; + + /* Check if it is valid. */ + if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE)) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); + + for (i = 0; i < 4; i++) + if (mbr.entries[i].flag & 0x7f) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag"); + + /* Analyze DOS partitions. */ + for (i = 0; i < 4; i++) + { + e = mbr.entries + i; + + if (!grub_msdos_partition_is_empty (e->type) + && end > offset + grub_le_to_cpu32 (e->start)) + end = offset + grub_le_to_cpu32 (e->start); + + /* If this is a GPT partition, this MBR is just a dummy. */ + if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr"); + } + + /* Find an extended partition. */ + for (i = 0; i < 4; i++) + { + e = mbr.entries + i; + + if (grub_msdos_partition_is_extended (e->type)) + { + offset = ext_offset + grub_le_to_cpu32 (e->start); + if (! ext_offset) + ext_offset = offset; + + break; + } + } + + /* If no extended partition, the end. */ + if (i == 4) + break; + } + + if (end >= nsectors + 1) + { + int i; + for (i = 0; i < nsectors; i++) + sectors[i] = 1 + i; + return GRUB_ERR_NONE; + } + + if (end <= 1) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + "This msdos-style partition label has no " + "post-MBR gap; embedding won't be possible!"); + + if (nsectors > 62) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Your core.img is unusually large. " + "It won't fit in the embedding area."); + + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Your embedding area is unusually small. " + "core.img won't fit in it."); +} +#endif + /* Partition map type. */ static struct grub_partition_map grub_msdos_partition_map = { .name = "msdos", .iterate = pc_partition_map_iterate, +#ifdef GRUB_UTIL + .embed = pc_partition_map_embed +#endif }; GRUB_MOD_INIT(part_msdos) diff --git a/grub-core/partmap/sun.c b/grub-core/partmap/sun.c index 7a7eaef27..7af95c939 100644 --- a/grub-core/partmap/sun.c +++ b/grub-core/partmap/sun.c @@ -87,36 +87,23 @@ sun_partition_map_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, const grub_partition_t partition)) { - grub_partition_t p; + struct grub_partition p; struct grub_sun_block block; int partnum; grub_err_t err; - p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition)); - if (! p) - return grub_errno; - - p->partmap = &grub_sun_partition_map; + p.partmap = &grub_sun_partition_map; err = grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block), &block); if (err) - { - grub_free (p); - return err; - } + return err; if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.magic)) - { - grub_free (p); - return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table"); - } + return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table"); if (! grub_sun_is_valid (&block)) - { - grub_free (p); return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum"); - } - + /* Maybe another error value would be better, because partition table _is_ recognized but invalid. */ for (partnum = 0; partnum < GRUB_PARTMAP_SUN_MAX_PARTS; partnum++) @@ -128,20 +115,18 @@ sun_partition_map_iterate (grub_disk_t disk, continue; desc = &block.partitions[partnum]; - p->start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder) + p.start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder) * grub_be_to_cpu16 (block.ntrks) * grub_be_to_cpu16 (block.nsect)); - p->len = grub_be_to_cpu32 (desc->num_sectors); - p->number = p->index = partnum; - if (p->len) + p.len = grub_be_to_cpu32 (desc->num_sectors); + p.number = p.index = partnum; + if (p.len) { - if (hook (disk, p)) + if (hook (disk, &p)) partnum = GRUB_PARTMAP_SUN_MAX_PARTS; } } - grub_free (p); - return grub_errno; } diff --git a/grub-core/script/argv.c b/grub-core/script/argv.c index b69ee39c5..50f810fcf 100644 --- a/grub-core/script/argv.c +++ b/grub-core/script/argv.c @@ -18,6 +18,7 @@ */ #include +#include #include /* Return nearest power of two that is >= v. */ @@ -55,6 +56,24 @@ grub_script_argv_free (struct grub_script_argv *argv) argv->argc = 0; argv->args = 0; + argv->script = 0; +} + +/* Make argv from argc, args pair. */ +int +grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args) +{ + int i; + struct grub_script_argv r = { 0, 0, 0 }; + + for (i = 0; i < argc; i++) + if (grub_script_argv_next (&r) || grub_script_argv_append (&r, args[i])) + { + grub_script_argv_free (&r); + return 1; + } + *argv = r; + return 0; } /* Prepare for next argc. */ @@ -63,7 +82,7 @@ grub_script_argv_next (struct grub_script_argv *argv) { char **p = argv->args; - if (argv->args && argv->args[argv->argc - 1] == 0) + if (argv->args && argv->argc && argv->args[argv->argc - 1] == 0) return 0; p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *))); @@ -83,7 +102,8 @@ grub_script_argv_next (struct grub_script_argv *argv) int grub_script_argv_append (struct grub_script_argv *argv, const char *s) { - int a, b; + int a; + int b; char *p = argv->args[argv->argc - 1]; if (! s) @@ -98,6 +118,7 @@ grub_script_argv_append (struct grub_script_argv *argv, const char *s) grub_strcpy (p + a, s); argv->args[argv->argc - 1] = p; + return 0; } diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index 26a46b12b..e24c4b1af 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -25,6 +25,7 @@ #include #include #include +#include /* Max digits for a char is 3 (0xFF is 255), similarly for an int it is sizeof (int) * 3, and one extra for a possible -ve sign. */ @@ -33,14 +34,40 @@ static unsigned long is_continue; static unsigned long active_loops; static unsigned long active_breaks; +static unsigned long function_return; + +#define GRUB_SCRIPT_SCOPE_MALLOCED 1 +#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2 /* Scope for grub script functions. */ struct grub_script_scope { + unsigned flags; + unsigned shifts; struct grub_script_argv argv; }; static struct grub_script_scope *scope = 0; +/* Wildcard translator for GRUB script. */ +struct grub_script_wildcard_translator *grub_wildcard_translator; + +static void +replace_scope (struct grub_script_scope *new_scope) +{ + if (scope) + { + scope->argv.argc += scope->shifts; + scope->argv.args -= scope->shifts; + + if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED) + grub_script_argv_free (&scope->argv); + + if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED) + grub_free (scope); + } + scope = new_scope; +} + grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]) { @@ -85,11 +112,65 @@ grub_script_shift (grub_command_t cmd __attribute__((unused)), if (n > scope->argv.argc) return GRUB_ERR_BAD_ARGUMENT; + scope->shifts += n; scope->argv.argc -= n; scope->argv.args += n; return GRUB_ERR_NONE; } +grub_err_t +grub_script_setparams (grub_command_t cmd __attribute__((unused)), + int argc, char **args) +{ + struct grub_script_scope *new_scope; + struct grub_script_argv argv = { 0, 0, 0 }; + + if (! scope) + return GRUB_ERR_INVALID_COMMAND; + + new_scope = grub_malloc (sizeof (*new_scope)); + if (! new_scope) + return grub_errno; + + if (grub_script_argv_make (&argv, argc, args)) + { + grub_free (new_scope); + return grub_errno; + } + + new_scope->shifts = 0; + new_scope->argv = argv; + new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED | + GRUB_SCRIPT_SCOPE_ARGS_MALLOCED; + + replace_scope (new_scope); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_script_return (grub_command_t cmd __attribute__((unused)), + int argc, char *argv[]) +{ + char *p; + unsigned long n; + + if (! scope || argc > 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in function scope"); + + if (argc == 0) + { + function_return = 1; + return grub_strtoul (grub_env_get ("?"), NULL, 10); + } + + n = grub_strtoul (argv[0], &p, 10); + if (*p != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad argument"); + + function_return = 1; + return n ? grub_error (GRUB_ERR_TEST_FAILURE, "false") : GRUB_ERR_NONE; +} + static int grub_env_special (const char *name) { @@ -104,7 +185,8 @@ grub_env_special (const char *name) static char ** grub_script_env_get (const char *name, grub_script_arg_type_t type) { - struct grub_script_argv result = { 0, 0 }; + unsigned i; + struct grub_script_argv result = { 0, 0, 0 }; if (grub_script_argv_next (&result)) goto fail; @@ -138,8 +220,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "*") == 0) { - unsigned i; - for (i = 0; i < scope->argv.argc; i++) if (type == GRUB_SCRIPT_ARG_TYPE_VAR) { @@ -160,8 +240,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "@") == 0) { - unsigned i; - for (i = 0; i < scope->argv.argc; i++) { if (i != 0 && grub_script_argv_next (&result)) @@ -214,7 +292,7 @@ grub_script_env_set (const char *name, const char *val) return grub_env_set (name, val); } -/* Expand arguments in ARGLIST into multiple arguments. */ +/* Convert arguments in ARGLIST into ARGV form. */ static int grub_script_arglist_to_argv (struct grub_script_arglist *arglist, struct grub_script_argv *argv) @@ -222,7 +300,29 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, int i; char **values = 0; struct grub_script_arg *arg = 0; - struct grub_script_argv result = { 0, 0 }; + struct grub_script_argv result = { 0, 0, 0 }; + + auto int append (char *s, int escape_type); + int append (char *s, int escape_type) + { + int r; + char *p = 0; + + if (! grub_wildcard_translator || escape_type == 0) + return grub_script_argv_append (&result, s); + + if (escape_type > 0) + p = grub_wildcard_translator->escape (s); + else if (escape_type < 0) + p = grub_wildcard_translator->unescape (s); + + if (! p) + return 1; + + r = grub_script_argv_append (&result, p); + grub_free (p); + return r; + } for (; arglist && arglist->arg; arglist = arglist->next) { @@ -242,12 +342,30 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, if (i != 0 && grub_script_argv_next (&result)) goto fail; - if (grub_script_argv_append (&result, values[i])) - goto fail; + if (arg->type == GRUB_SCRIPT_ARG_TYPE_VAR) + { + if (grub_script_argv_append (&result, values[i])) + goto fail; + } + else + { + if (append (values[i], 1)) + goto fail; + } + + grub_free (values[i]); } grub_free (values); break; + case GRUB_SCRIPT_ARG_TYPE_BLOCK: + if (grub_script_argv_append (&result, "{") || + grub_script_argv_append (&result, arg->str) || + grub_script_argv_append (&result, "}")) + goto fail; + result.script = arg->script; + break; + case GRUB_SCRIPT_ARG_TYPE_TEXT: if (grub_strlen (arg->str) && grub_script_argv_append (&result, arg->str)) @@ -267,6 +385,51 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, if (! result.args[result.argc - 1]) result.argc--; + /* Perform wildcard expansion. */ + + if (grub_wildcard_translator) + { + int j; + int failed = 0; + char **expansions = 0; + struct grub_script_argv unexpanded = result; + + result.argc = 0; + result.args = 0; + for (i = 0; unexpanded.args[i]; i++) + { + if (grub_wildcard_translator->expand (unexpanded.args[i], + &expansions)) + { + grub_script_argv_free (&unexpanded); + goto fail; + } + + if (! expansions) + { + grub_script_argv_next (&result); + append (unexpanded.args[i], -1); + } + else + { + for (j = 0; expansions[j]; j++) + { + failed = (failed || grub_script_argv_next (&result) || + append (expansions[j], -1)); + grub_free (expansions[j]); + } + grub_free (expansions); + + if (failed) + { + grub_script_argv_free (&unexpanded); + goto fail; + } + } + } + grub_script_argv_free (&unexpanded); + } + *argv = result; return 0; @@ -302,6 +465,8 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) struct grub_script_scope new_scope; active_loops = 0; + new_scope.flags = 0; + new_scope.shifts = 0; new_scope.argv.argc = argc; new_scope.argv.args = args; @@ -310,7 +475,64 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) ret = grub_script_execute (func->func); + function_return = 0; active_loops = loops; + replace_scope (old_scope); /* free any scopes by setparams */ + return ret; +} + +/* Execute a source script. */ +grub_err_t +grub_script_execute_sourcecode (const char *source, int argc, char **args) +{ + grub_err_t ret = 0; + struct grub_script *parsed_script; + struct grub_script_scope new_scope; + struct grub_script_scope *old_scope; + + auto grub_err_t getline (char **line, int cont); + grub_err_t getline (char **line, int cont __attribute__ ((unused))) + { + const char *p; + + if (! source) + { + *line = 0; + return 0; + } + + p = grub_strchr (source, '\n'); + + if (p) + *line = grub_strndup (source, p - source); + else + *line = grub_strdup (source); + source = p ? p + 1 : 0; + return 0; + } + + new_scope.argv.argc = argc; + new_scope.argv.args = args; + + old_scope = scope; + scope = &new_scope; + + while (source) + { + char *line; + + getline (&line, 0); + parsed_script = grub_script_parse (line, getline); + if (! parsed_script) + { + ret = grub_errno; + break; + } + + ret = grub_script_execute (parsed_script); + grub_free (line); + } + scope = old_scope; return ret; } @@ -325,13 +547,32 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) grub_script_function_t func = 0; char errnobuf[18]; char *cmdname; - struct grub_script_argv argv = { 0, 0 }; + int argc; + char **args; + int invert; + struct grub_script_argv argv = { 0, 0, 0 }; /* Lookup the command. */ if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0]) return grub_errno; + invert = 0; + argc = argv.argc - 1; + args = argv.args + 1; cmdname = argv.args[0]; + if (grub_strcmp (cmdname, "!") == 0) + { + if (argv.argc < 2 || ! argv.args[1]) + { + grub_script_argv_free (&argv); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments"); + } + + invert = 1; + argc = argv.argc - 2; + args = argv.args + 2; + cmdname = argv.args[1]; + } grubcmd = grub_command_find (cmdname); if (! grubcmd) { @@ -369,9 +610,28 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) /* Execute the GRUB command or function. */ if (grubcmd) - ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1); + { + if ((grubcmd->flags & GRUB_COMMAND_FLAG_BLOCKS) && + (grubcmd->flags & GRUB_COMMAND_FLAG_EXTCMD)) + ret = grub_extcmd_dispatcher (grubcmd, argc, args, argv.script); + else + ret = (grubcmd->func) (grubcmd, argc, args); + } else - ret = grub_script_function_call (func, argv.argc - 1, argv.args + 1); + ret = grub_script_function_call (func, argc, args); + + if (invert) + { + if (ret == GRUB_ERR_TEST_FAILURE) + grub_errno = ret = GRUB_ERR_NONE; + else if (ret == GRUB_ERR_NONE) + ret = grub_error (GRUB_ERR_TEST_FAILURE, "false"); + else + { + grub_print_error (); + ret = GRUB_ERR_NONE; + } + } /* Free arguments. */ grub_script_argv_free (&argv); @@ -395,8 +655,16 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list) struct grub_script_cmd *cmd; /* Loop over every command and execute it. */ - for (cmd = list->next; cmd && ! active_breaks; cmd = cmd->next) - ret = grub_script_execute_cmd (cmd); + for (cmd = list->next; cmd; cmd = cmd->next) + { + if (active_breaks) + break; + + ret = grub_script_execute_cmd (cmd); + + if (function_return) + break; + } return ret; } @@ -405,14 +673,17 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list) grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd) { - struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd; + int ret; char *result; + struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd; /* Check if the commands results in a true or a false. The value is read from the env variable `?'. */ - grub_script_execute_cmd (cmdif->exec_to_evaluate); - result = grub_env_get ("?"); + ret = grub_script_execute_cmd (cmdif->exec_to_evaluate); + if (function_return) + return ret; + result = grub_env_get ("?"); grub_errno = GRUB_ERR_NONE; /* Execute the `if' or the `else' part depending on the value of @@ -429,8 +700,7 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { unsigned i; grub_err_t result; - struct grub_script_argv argv = { 0, 0 }; - + struct grub_script_argv argv = { 0, 0, 0 }; struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd; if (grub_script_arglist_to_argv (cmdfor->words, &argv)) @@ -447,6 +717,8 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { grub_script_env_set (cmdfor->name->str, argv.args[i]); result = grub_script_execute_cmd (cmdfor->list); + if (function_return) + break; } } @@ -462,18 +734,21 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) grub_err_t grub_script_execute_cmdwhile (struct grub_script_cmd *cmd) { - int cond; int result; struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd; active_loops++; - result = 0; do { - cond = grub_script_execute_cmd (cmdwhile->cond); - if (cmdwhile->until ? !cond : cond) + result = grub_script_execute_cmd (cmdwhile->cond); + if (function_return) + break; + + if (cmdwhile->until ? !result : result) break; result = grub_script_execute_cmd (cmdwhile->list); + if (function_return) + break; if (active_breaks == 1 && is_continue) active_breaks = 0; @@ -490,31 +765,6 @@ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd) return result; } -/* Execute the menu entry generate statement. */ -grub_err_t -grub_script_execute_menuentry (struct grub_script_cmd *cmd) -{ - struct grub_script_cmd_menuentry *cmd_menuentry; - struct grub_script_argv argv = { 0, 0 }; - - cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd; - - if (cmd_menuentry->arglist) - { - if (grub_script_arglist_to_argv (cmd_menuentry->arglist, &argv)) - return grub_errno; - } - - grub_normal_add_menu_entry (argv.argc, (const char **) argv.args, - cmd_menuentry->sourcecode); - - grub_script_argv_free (&argv); - - return grub_errno; -} - - - /* Execute any GRUB pre-parsed command or script. */ grub_err_t grub_script_execute (struct grub_script *script) diff --git a/grub-core/script/lexer.c b/grub-core/script/lexer.c index 64da45ed8..8d1623fb8 100644 --- a/grub-core/script/lexer.c +++ b/grub-core/script/lexer.c @@ -38,68 +38,57 @@ grub_script_lexer_deref (struct grub_lexer_param *state) } /* Start recording all characters passing through the lexer. */ -void +unsigned grub_script_lexer_record_start (struct grub_parser_param *parser) { struct grub_lexer_param *lexer = parser->lexerstate; - lexer->record = 1; - lexer->recordpos = 0; - if (lexer->recording) /* reuse last record */ - return; + lexer->record++; + if (lexer->recording) + return lexer->recordpos; + lexer->recordpos = 0; lexer->recordlen = GRUB_LEXER_INITIAL_RECORD_SIZE; lexer->recording = grub_malloc (lexer->recordlen); if (!lexer->recording) { grub_script_yyerror (parser, 0); - lexer->record = 0; lexer->recordlen = 0; } + return lexer->recordpos; } char * -grub_script_lexer_record_stop (struct grub_parser_param *parser) +grub_script_lexer_record_stop (struct grub_parser_param *parser, unsigned offset) { - char *ptr; + int count; char *result; struct grub_lexer_param *lexer = parser->lexerstate; - auto char *compact (char *start, char *end); - char *compact (char *start, char *end) - { - /* Delete '{' and '}' characters and whitespaces. */ - while (*start && grub_isspace (*start)) start++; - if (*start == '{') start++; - while (*start && grub_isspace (*start)) start++; - - while (*end && grub_isspace (*end)) end--; - if (*end == '}') end--; - while (*end && grub_isspace (*end)) end--; - end[1] = '\0'; - - return start; - } - - if (!lexer->record || !lexer->recording) + if (!lexer->record) return 0; - /* XXX This is not necessary in BASH. */ + lexer->record--; + if (!lexer->recording) + return 0; - ptr = compact (lexer->recording, lexer->recording + lexer->recordpos - 1); - lexer->record = 0; - lexer->recordpos = 0; - - /* This memory would be freed by, grub_script_free. */ - result = grub_script_malloc (parser, grub_strlen (ptr) + 1); - if (result) - grub_strcpy (result, ptr); + count = lexer->recordpos - offset; + result = grub_script_malloc (parser, count + 1); + if (result) { + grub_strncpy (result, lexer->recording + offset, count); + result[count] = '\0'; + } + if (lexer->record == 0) + { + grub_free (lexer->recording); + lexer->recording = 0; + lexer->recordlen = 0; + lexer->recordpos = 0; + } return result; } -#define MAX(a,b) ((a) < (b) ? (b) : (a)) - /* Record STR if input recording is enabled. */ void grub_script_lexer_record (struct grub_parser_param *parser, char *str) @@ -108,21 +97,20 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str) char *old; struct grub_lexer_param *lexer = parser->lexerstate; - if (!lexer->record) + if (!lexer->record || !lexer->recording) return; len = grub_strlen (str); if (lexer->recordpos + len + 1 > lexer->recordlen) { old = lexer->recording; - lexer->recordlen = MAX (len, lexer->recordlen) * 2; + lexer->recordlen = grub_max (len, lexer->recordlen) * 2; lexer->recording = grub_realloc (lexer->recording, lexer->recordlen); if (!lexer->recording) { grub_free (old); - lexer->record = 0; lexer->recordpos = 0; - lexer->recordlen /= 2; + lexer->recordlen = 0; grub_script_yyerror (parser, 0); return; } @@ -131,85 +119,92 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str) lexer->recordpos += len; } -/* Append '\n' to SRC, before '\0' */ -static char * -append_newline (const char *src) -{ - char *line; - grub_size_t len; - - len = grub_strlen (src); - line = grub_malloc (len + 2); - if (!line) - return 0; - - grub_strcpy (line, src); - - line[len] = '\n'; - line[len + 1] = '\0'; - return line; -} - /* Read next line of input if necessary, and set yyscanner buffers. */ int -grub_script_lexer_yywrap (struct grub_parser_param *parserstate) +grub_script_lexer_yywrap (struct grub_parser_param *parserstate, + const char *input) { int len; - char *line; - char *line2; + char *p = 0; + char *line = 0; YY_BUFFER_STATE buffer; struct grub_lexer_param *lexerstate = parserstate->lexerstate; - if (!lexerstate->refs) - return 0; + if (! lexerstate->refs && ! lexerstate->prefix && ! input) + return 1; - if (!lexerstate->getline) + if (! lexerstate->getline && ! input) { grub_script_yyerror (parserstate, "unexpected end of file"); - return 0; + return 1; } line = 0; - buffer = 0; - lexerstate->getline (&line, 1); - if (!line) - { - grub_script_yyerror (parserstate, 0); /* XXX this could be for ^C case? */ - return 0; - } - - len = grub_strlen (line); - if (line[len - 1] == '\n') - { - buffer = yy_scan_string (line, lexerstate->yyscanner); - } + if (! input) + lexerstate->getline (&line, 1); else + line = grub_strdup (input); + + /* Ensure '\n' at the end. */ + if (line && line[0] == '\0') { - line2 = append_newline (line); - if (line2) - { - buffer = yy_scan_string (line2, lexerstate->yyscanner); - grub_free (line2); - } + grub_free (line); + line = grub_strdup ("\n"); } + if (line && (len = grub_strlen(line)) && line[len - 1] != '\n') + { + p = grub_realloc (line, len + 2); + if (p) + { + p[len++] = '\n'; + p[len] = '\0'; + } + line = p; + } + + if (! line) + { + grub_script_yyerror (parserstate, "out of memory"); + return 1; + } + + /* Prepend any left over unput-text. */ + if (lexerstate->prefix) + { + int plen = grub_strlen (lexerstate->prefix); + + p = grub_malloc (len + plen + 1); + if (! p) + { + grub_free (line); + return 1; + } + grub_strcpy (p, lexerstate->prefix); + lexerstate->prefix = 0; + + grub_strcpy (p + plen, line); + grub_free (line); + + line = p; + len = len + plen; + } + + buffer = yy_scan_string (line, lexerstate->yyscanner); grub_free (line); - if (!buffer) + + if (! buffer) { grub_script_yyerror (parserstate, 0); - return 0; + return 1; } - - return 1; + return 0; } struct grub_lexer_param * grub_script_lexer_init (struct grub_parser_param *parser, char *script, grub_reader_getline_t getline) { - int len; - char *script2; - YY_BUFFER_STATE buffer; struct grub_lexer_param *lexerstate; lexerstate = grub_zalloc (sizeof (*lexerstate)); @@ -232,34 +227,18 @@ grub_script_lexer_init (struct grub_parser_param *parser, char *script, return 0; } - buffer = 0; - script = script ? : "\n"; - len = grub_strlen (script); + yyset_extra (parser, lexerstate->yyscanner); + parser->lexerstate = lexerstate; - if (len != 0 && script[len - 1] == '\n') - { - buffer = yy_scan_string (script, lexerstate->yyscanner); - } - else - { - script2 = append_newline (script); - if (script2) - { - buffer = yy_scan_string (script2, lexerstate->yyscanner); - grub_free (script2); - } - } - - if (!buffer) + if (grub_script_lexer_yywrap (parser, script ?: "\n")) { + parser->lexerstate = 0; yylex_destroy (lexerstate->yyscanner); grub_free (lexerstate->yyscanner); - grub_free (lexerstate->text); grub_free (lexerstate); return 0; } - yyset_extra (parser, lexerstate->yyscanner); return lexerstate; } diff --git a/grub-core/script/main.c b/grub-core/script/main.c index ff714d060..482bb3fef 100644 --- a/grub-core/script/main.c +++ b/grub-core/script/main.c @@ -35,7 +35,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline) grub_script_execute (parsed_script); /* The parsed script was executed, throw it away. */ - grub_script_free (parsed_script); + grub_script_unref (parsed_script); } return grub_errno; @@ -44,6 +44,8 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline) static grub_command_t cmd_break; static grub_command_t cmd_continue; static grub_command_t cmd_shift; +static grub_command_t cmd_setparams; +static grub_command_t cmd_return; void grub_script_init (void) @@ -54,6 +56,11 @@ grub_script_init (void) N_("[n]"), N_("Continue loops")); cmd_shift = grub_register_command ("shift", grub_script_shift, N_("[n]"), N_("Shift positional parameters.")); + cmd_setparams = grub_register_command ("setparams", grub_script_setparams, + N_("[VALUE]..."), + N_("Set positional parameters.")); + cmd_return = grub_register_command ("return", grub_script_return, + N_("[n]"), N_("Return from a function.")); } void @@ -70,4 +77,12 @@ grub_script_fini (void) if (cmd_shift) grub_unregister_command (cmd_shift); cmd_shift = 0; + + if (cmd_setparams) + grub_unregister_command (cmd_setparams); + cmd_setparams = 0; + + if (cmd_return) + grub_unregister_command (cmd_return); + cmd_return = 0; } diff --git a/grub-core/script/parser.y b/grub-core/script/parser.y index 99cd2ee31..88c7fe9e3 100644 --- a/grub-core/script/parser.y +++ b/grub-core/script/parser.y @@ -20,6 +20,7 @@ %{ #include #include +#include #define YYFREE grub_free #define YYMALLOC grub_malloc @@ -34,6 +35,11 @@ struct grub_script_arglist *arglist; struct grub_script_arg *arg; char *string; + struct { + unsigned offset; + struct grub_script_mem *memory; + struct grub_script *scripts; + }; } %token GRUB_PARSER_TOKEN_BAD @@ -70,15 +76,15 @@ %token GRUB_PARSER_TOKEN_WHILE "while" %token GRUB_PARSER_TOKEN_TIME "time" %token GRUB_PARSER_TOKEN_FUNCTION "function" -%token GRUB_PARSER_TOKEN_MENUENTRY "menuentry" %token GRUB_PARSER_TOKEN_NAME "name" %token GRUB_PARSER_TOKEN_WORD "word" +%type block block0 %type word argument arguments0 arguments1 %type script_init script %type grubcmd ifclause ifcmd forcmd whilecmd untilcmd -%type command commands1 menuentry statement +%type command commands1 statement %pure-parser %lex-param { struct grub_parser_param *state }; @@ -124,7 +130,6 @@ word: GRUB_PARSER_TOKEN_NAME { $$ = grub_script_add_arglist (state, 0, $1); } statement: command { $$ = $1; } | function { $$ = 0; } - | menuentry { $$ = $1; } ; argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } @@ -142,10 +147,77 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } | "until" { $$ = grub_script_add_arglist (state, 0, $1); } | "while" { $$ = grub_script_add_arglist (state, 0, $1); } | "function" { $$ = grub_script_add_arglist (state, 0, $1); } - | "menuentry" { $$ = grub_script_add_arglist (state, 0, $1); } | word { $$ = $1; } ; +/* + Block parameter is passed to commands in two forms: as unparsed + string and as pre-parsed grub_script object. Passing as grub_script + object makes memory management difficult, because: + + (1) Command may want to keep a reference to grub_script objects for + later use, so script framework may not free the grub_script + object after command completes. + + (2) Command may get called multiple times with same grub_script + object under loops, so we should not let command implementation + to free the grub_script object. + + To solve above problems, we rely on reference counting for + grub_script objects. Commands that want to keep the grub_script + object must take a reference to it. + + Other complexity comes with arbitrary nesting of grub_script + objects: a grub_script object may have commands with several block + parameters, and each block parameter may further contain multiple + block parameters nested. We use temporary variable, state->scripts + to collect nested child scripts (that are linked by siblings and + children members), and will build grub_scripts tree from bottom. + */ +block: "{" + { + grub_script_lexer_ref (state->lexerstate); + $$ = grub_script_lexer_record_start (state); + $$ = grub_script_mem_record (state); + + /* save currently known scripts. */ + $$ = state->scripts; + state->scripts = 0; + } + commands1 delimiters0 "}" + { + char *p; + struct grub_script_mem *memory; + struct grub_script *s = $2; + + memory = grub_script_mem_record_stop (state, $2); + if ((p = grub_script_lexer_record_stop (state, $2))) + *grub_strrchr (p, '}') = '\0'; + + $$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p); + if (! $$ || ! ($$->script = grub_script_create ($3, memory))) + grub_script_mem_free (memory); + + else { + /* attach nested scripts to $$->script as children */ + $$->script->children = state->scripts; + + /* restore old scripts; append $$->script to siblings. */ + state->scripts = $2 ?: $$->script; + if (s) { + while (s->next_siblings) + s = s->next_siblings; + s->next_siblings = $$->script; + } + } + + grub_script_lexer_deref (state->lexerstate); + } +; +block0: /* Empty */ { $$ = 0; } + | block { $$ = $1; } +; + arguments0: /* Empty */ { $$ = 0; } | arguments1 { $$ = $1; } ; @@ -161,12 +233,17 @@ arguments1: argument arguments0 } ; -grubcmd: word arguments0 +grubcmd: word arguments0 block0 { - if ($1 && $2) { - $1->next = $2; - $1->argcount += $2->argcount; - $2->argcount = 0; + struct grub_script_arglist *x = $2; + + if ($3) + x = grub_script_add_arglist (state, $2, $3); + + if ($1 && x) { + $1->next = x; + $1->argcount += x->argcount; + x->argcount = 0; } $$ = grub_script_create_cmdline (state, $1); } @@ -191,10 +268,13 @@ commands1: newlines0 command } ; -function: "function" "name" +function: "function" "name" { grub_script_lexer_ref (state->lexerstate); state->func_mem = grub_script_mem_record (state); + + $$ = state->scripts; + state->scripts = 0; } delimiters0 "{" commands1 delimiters1 "}" { @@ -202,30 +282,18 @@ function: "function" "name" state->func_mem = grub_script_mem_record_stop (state, state->func_mem); script = grub_script_create ($6, state->func_mem); - if (script) - grub_script_function_create ($2, script); + if (! script) + grub_script_mem_free (state->func_mem); + else { + script->children = state->scripts; + grub_script_function_create ($2, script); + } + state->scripts = $3; grub_script_lexer_deref (state->lexerstate); } ; -menuentry: "menuentry" - { - grub_script_lexer_ref (state->lexerstate); - } - arguments1 - { - grub_script_lexer_record_start (state); - } - delimiters0 "{" commands1 delimiters1 "}" - { - char *menu_entry; - menu_entry = grub_script_lexer_record_stop (state); - grub_script_lexer_deref (state->lexerstate); - $$ = grub_script_create_cmdmenu (state, $3, menu_entry, 0); - } -; - ifcmd: "if" { grub_script_lexer_ref (state->lexerstate); diff --git a/grub-core/script/script.c b/grub-core/script/script.c index 448bdf775..ad3018357 100644 --- a/grub-core/script/script.c +++ b/grub-core/script/script.c @@ -54,7 +54,7 @@ grub_script_malloc (struct grub_parser_param *state, grub_size_t size) } /* Free all memory described by MEM. */ -static void +void grub_script_mem_free (struct grub_script_mem *mem) { struct grub_script_mem *memfree; @@ -94,9 +94,21 @@ grub_script_mem_record_stop (struct grub_parser_param *state, void grub_script_free (struct grub_script *script) { - if (!script) + struct grub_script *s; + struct grub_script *t; + + if (! script) return; - grub_script_mem_free (script->mem); + + if (script->mem) + grub_script_mem_free (script->mem); + + s = script->children; + while (s) { + t = s->next_siblings; + grub_script_unref (s); + s = t; + } grub_free (script); } @@ -119,6 +131,8 @@ grub_script_arg_add (struct grub_parser_param *state, return arg; argpart->type = type; + argpart->script = 0; + len = grub_strlen (str) + 1; argpart->str = grub_script_malloc (state, len); if (!argpart->str) @@ -267,30 +281,6 @@ grub_script_create_cmdwhile (struct grub_parser_param *state, return (struct grub_script_cmd *) cmd; } -/* Create a command that adds a menu entry to the menu. Title is an - argument that is parsed to generate a string that can be used as - the title. The sourcecode for this entry is passed in SOURCECODE. - The options for this entry are passed in OPTIONS. */ -struct grub_script_cmd * -grub_script_create_cmdmenu (struct grub_parser_param *state, - struct grub_script_arglist *arglist, - char *sourcecode, int options) -{ - struct grub_script_cmd_menuentry *cmd; - - cmd = grub_script_malloc (state, sizeof (*cmd)); - if (!cmd) - return 0; - - cmd->cmd.exec = grub_script_execute_menuentry; - cmd->cmd.next = 0; - cmd->sourcecode = sourcecode; - cmd->arglist = arglist; - cmd->options = options; - - return (struct grub_script_cmd *) cmd; -} - /* Create a chain of commands. LAST contains the command that should be added at the end of LIST's list. If LIST is zero, a new list will be created. */ @@ -335,16 +325,14 @@ grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem) struct grub_script *parsed; parsed = grub_malloc (sizeof (*parsed)); - if (!parsed) - { - grub_script_mem_free (mem); - grub_free (cmd); - - return 0; - } + if (! parsed) + return 0; parsed->mem = mem; parsed->cmd = cmd; + parsed->refcnt = 0; + parsed->children = 0; + parsed->next_siblings = 0; return parsed; } @@ -359,7 +347,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline) struct grub_lexer_param *lexstate; struct grub_parser_param *parsestate; - parsed = grub_malloc (sizeof (*parsed)); + parsed = grub_script_create (0, 0); if (!parsed) return 0; @@ -397,6 +385,7 @@ grub_script_parse (char *script, grub_reader_getline_t getline) parsed->mem = grub_script_mem_record_stop (parsestate, membackup); parsed->cmd = parsestate->parsed; + parsed->children = parsestate->scripts; grub_script_lexer_fini (lexstate); grub_free (parsestate); diff --git a/grub-core/script/yylex.l b/grub-core/script/yylex.l index 45760c158..55620b6bd 100644 --- a/grub-core/script/yylex.l +++ b/grub-core/script/yylex.l @@ -58,6 +58,9 @@ #define YY_INPUT(buf,res,max) do { res = 0; } while (0) /* forward declarations */ +static int grub_lexer_unput (const char *input, yyscan_t yyscanner); +static int grub_lexer_resplit (const char *input, yyscan_t yyscanner); + static void grub_lexer_yyfree (void *, yyscan_t yyscanner); static void* grub_lexer_yyalloc (yy_size_t, yyscan_t yyscanner); static void* grub_lexer_yyrealloc (void*, yy_size_t, yyscan_t yyscanner); @@ -99,7 +102,7 @@ typedef size_t yy_size_t; %option never-interactive %option noyyfree noyyalloc noyyrealloc -%option nounistd nostdinit nodefault noyylineno noyywrap +%option nounistd nostdinit nodefault noyylineno /* Reduce lexer size, by not defining these. */ %option noyy_top_state @@ -118,13 +121,17 @@ CHAR [^{}|&$;<> \t\n\'\"\\] DIGITS [[:digit:]]+ NAME [[:alpha:]_][[:alnum:]_]* -ESC \\. +ESC \\(.|\n) +SQCHR [^\'] +DQCHR {ESC}|[^\\\"] +DQSTR \"{DQCHR}*\" +SQSTR \'{SQCHR}*\' SPECIAL \?|\#|\*|\@ VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\} -DQSTR \"([^\\\"]|{ESC})*\" -SQSTR \'[^\']*\' WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ +MULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*)|(\\\n)) + %x SPLIT %x DQUOTE %x SQUOTE @@ -148,7 +155,6 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ ">" { RECORD; return GRUB_PARSER_TOKEN_GT; } /* Reserved words */ -"!" { RECORD; return GRUB_PARSER_TOKEN_NOT; } "{" { RECORD; return GRUB_PARSER_TOKEN_LBR; } "}" { RECORD; return GRUB_PARSER_TOKEN_RBR; } "[[" { RECORD; return GRUB_PARSER_TOKEN_RSQBR2; } @@ -169,36 +175,33 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ "until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; } "while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; } "function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; } -"menuentry" { RECORD; return GRUB_PARSER_TOKEN_MENUENTRY; } + +{MULTILINE} { + if (grub_lexer_unput (yytext, yyscanner)) + return GRUB_PARSER_TOKEN_BAD; + } {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; } {WORD} { RECORD; - /* resplit yytext */ - grub_dprintf ("lexer", "word: [%s]\n", yytext); - yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); - if (yy_scan_string (yytext, yyscanner)) - { - yyextra->lexerstate->merge_start = 1; - yy_push_state (SPLIT, yyscanner); - } - else - { - grub_script_yyerror (yyextra, 0); - yypop_buffer_state (yyscanner); - return GRUB_PARSER_TOKEN_WORD; - } + yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); + if (grub_lexer_resplit (yytext, yyscanner)) + { + yypop_buffer_state (yyscanner); + return GRUB_PARSER_TOKEN_WORD; + } + yyextra->lexerstate->resplit = 1; } - -.|\n { - grub_script_yyerror (yyextra, "unrecognized token"); - return GRUB_PARSER_TOKEN_BAD; +. { + grub_script_yyerror (yyextra, yytext); + return GRUB_PARSER_TOKEN_BAD; } /* Split word into multiple args */ { \\. { COPY (yytext + 1, yyleng - 1); } + \\\n { /* ignore */ } \" { yy_push_state (DQUOTE, yyscanner); ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); @@ -216,6 +219,7 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ <> { yy_pop_state (yyscanner); yypop_buffer_state (yyscanner); + yyextra->lexerstate->resplit = 0; yyextra->lexerstate->merge_end = 1; ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); } @@ -273,15 +277,20 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ <> { yypop_buffer_state (yyscanner); - if (! grub_script_lexer_yywrap (yyextra)) - { - yyextra->lexerstate->eof = 1; - return GRUB_PARSER_TOKEN_EOF; - } + yyextra->lexerstate->eof = 1; + return GRUB_PARSER_TOKEN_EOF; } - %% +int +yywrap (yyscan_t yyscanner) +{ + if (yyget_extra (yyscanner)->lexerstate->resplit) + return 1; + + return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0); +} + static void grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused))) { @@ -301,8 +310,6 @@ grub_lexer_yyrealloc (void *ptr, yy_size_t size, return grub_realloc (ptr, size); } -#define MAX(a,b) ((a) < (b) ? (b) : (a)) - static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint) { int size; @@ -312,7 +319,7 @@ static void copy_string (struct grub_parser_param *parser, const char *str, unsi len = hint ? hint : grub_strlen (str); if (parser->lexerstate->used + len >= parser->lexerstate->size) { - size = MAX (len, parser->lexerstate->size) * 2; + size = grub_max (len, parser->lexerstate->size) * 2; ptr = grub_realloc (parser->lexerstate->text, size); if (!ptr) { @@ -326,3 +333,34 @@ static void copy_string (struct grub_parser_param *parser, const char *str, unsi grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str); parser->lexerstate->used += len; } + +static int +grub_lexer_resplit (const char *text, yyscan_t yyscanner) +{ + /* resplit text */ + if (yy_scan_string (text, yyscanner)) + { + yyget_extra (yyscanner)->lexerstate->merge_start = 1; + yy_push_state (SPLIT, yyscanner); + return 0; + } + grub_script_yyerror (yyget_extra (yyscanner), 0); + return 1; +} + +static int +grub_lexer_unput (const char *text, yyscan_t yyscanner) +{ + struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate; + + if (lexerstate->prefix) + grub_free (lexerstate->prefix); + + lexerstate->prefix = grub_strdup (text); + if (! lexerstate->prefix) + { + grub_script_yyerror (yyget_extra (yyscanner), "out of memory"); + return 1; + } + return 0; +} diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c index 25f32a0a5..1b130bd62 100644 --- a/grub-core/term/at_keyboard.c +++ b/grub-core/term/at_keyboard.c @@ -22,18 +22,13 @@ #include #include #include +#include +#include +#include static short at_keyboard_status = 0; -static int pending_key = -1; - -#define KEYBOARD_STATUS_SHIFT_L (1 << 0) -#define KEYBOARD_STATUS_SHIFT_R (1 << 1) -#define KEYBOARD_STATUS_ALT_L (1 << 2) -#define KEYBOARD_STATUS_ALT_R (1 << 3) -#define KEYBOARD_STATUS_CTRL_L (1 << 4) -#define KEYBOARD_STATUS_CTRL_R (1 << 5) -#define KEYBOARD_STATUS_CAPS_LOCK (1 << 6) -#define KEYBOARD_STATUS_NUM_LOCK (1 << 7) +static int e0_received = 0; +static int f0_received = 0; static grub_uint8_t led_status; @@ -41,36 +36,179 @@ static grub_uint8_t led_status; #define KEYBOARD_LED_NUM (1 << 1) #define KEYBOARD_LED_CAPS (1 << 2) -static char keyboard_map[128] = -{ - '\0', GRUB_TERM_ESC, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '-', '=', GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', '\n', '\0', 'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - '\'', '`', '\0', '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', '\0', '*', - '\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', GRUB_TERM_HOME, - GRUB_TERM_UP, GRUB_TERM_NPAGE, '-', GRUB_TERM_LEFT, '\0', GRUB_TERM_RIGHT, '+', GRUB_TERM_END, - GRUB_TERM_DOWN, GRUB_TERM_PPAGE, '\0', GRUB_TERM_DC, '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', OLPC_UP, OLPC_DOWN, OLPC_LEFT, - OLPC_RIGHT -}; - -static char keyboard_map_shift[128] = -{ - '\0', '\0', '!', '@', '#', '$', '%', '^', - '&', '*', '(', ')', '_', '+', '\0', '\0', - 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', - 'O', 'P', '{', '}', '\n', '\0', 'A', 'S', - 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', - '\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', '<', '>', '?' -}; - static grub_uint8_t grub_keyboard_controller_orig; +static grub_uint8_t grub_keyboard_orig_set; +static grub_uint8_t current_set; + +static const grub_uint8_t set1_mapping[128] = + { + /* 0x00 */ 0 /* Unused */, GRUB_KEYBOARD_KEY_ESCAPE, + /* 0x02 */ GRUB_KEYBOARD_KEY_1, GRUB_KEYBOARD_KEY_2, + /* 0x04 */ GRUB_KEYBOARD_KEY_3, GRUB_KEYBOARD_KEY_4, + /* 0x06 */ GRUB_KEYBOARD_KEY_5, GRUB_KEYBOARD_KEY_6, + /* 0x08 */ GRUB_KEYBOARD_KEY_7, GRUB_KEYBOARD_KEY_8, + /* 0x0a */ GRUB_KEYBOARD_KEY_9, GRUB_KEYBOARD_KEY_0, + /* 0x0c */ GRUB_KEYBOARD_KEY_DASH, GRUB_KEYBOARD_KEY_EQUAL, + /* 0x0e */ GRUB_KEYBOARD_KEY_BACKSPACE, GRUB_KEYBOARD_KEY_TAB, + /* 0x10 */ GRUB_KEYBOARD_KEY_Q, GRUB_KEYBOARD_KEY_W, + /* 0x12 */ GRUB_KEYBOARD_KEY_E, GRUB_KEYBOARD_KEY_R, + /* 0x14 */ GRUB_KEYBOARD_KEY_T, GRUB_KEYBOARD_KEY_Y, + /* 0x16 */ GRUB_KEYBOARD_KEY_U, GRUB_KEYBOARD_KEY_I, + /* 0x18 */ GRUB_KEYBOARD_KEY_O, GRUB_KEYBOARD_KEY_P, + /* 0x1a */ GRUB_KEYBOARD_KEY_LBRACKET, GRUB_KEYBOARD_KEY_RBRACKET, + /* 0x1c */ GRUB_KEYBOARD_KEY_ENTER, GRUB_KEYBOARD_KEY_LEFT_CTRL, + /* 0x1e */ GRUB_KEYBOARD_KEY_A, GRUB_KEYBOARD_KEY_S, + /* 0x20 */ GRUB_KEYBOARD_KEY_D, GRUB_KEYBOARD_KEY_F, + /* 0x22 */ GRUB_KEYBOARD_KEY_G, GRUB_KEYBOARD_KEY_H, + /* 0x24 */ GRUB_KEYBOARD_KEY_J, GRUB_KEYBOARD_KEY_K, + /* 0x26 */ GRUB_KEYBOARD_KEY_L, GRUB_KEYBOARD_KEY_SEMICOLON, + /* 0x28 */ GRUB_KEYBOARD_KEY_DQUOTE, GRUB_KEYBOARD_KEY_RQUOTE, + /* 0x2a */ GRUB_KEYBOARD_KEY_LEFT_SHIFT, GRUB_KEYBOARD_KEY_BACKSLASH, + /* 0x2c */ GRUB_KEYBOARD_KEY_Z, GRUB_KEYBOARD_KEY_X, + /* 0x2e */ GRUB_KEYBOARD_KEY_C, GRUB_KEYBOARD_KEY_V, + /* 0x30 */ GRUB_KEYBOARD_KEY_B, GRUB_KEYBOARD_KEY_N, + /* 0x32 */ GRUB_KEYBOARD_KEY_M, GRUB_KEYBOARD_KEY_COMMA, + /* 0x34 */ GRUB_KEYBOARD_KEY_DOT, GRUB_KEYBOARD_KEY_SLASH, + /* 0x36 */ GRUB_KEYBOARD_KEY_RIGHT_SHIFT, GRUB_KEYBOARD_KEY_NUMMUL, + /* 0x38 */ GRUB_KEYBOARD_KEY_LEFT_ALT, GRUB_KEYBOARD_KEY_SPACE, + /* 0x3a */ GRUB_KEYBOARD_KEY_CAPS_LOCK, GRUB_KEYBOARD_KEY_F1, + /* 0x3c */ GRUB_KEYBOARD_KEY_F2, GRUB_KEYBOARD_KEY_F3, + /* 0x3e */ GRUB_KEYBOARD_KEY_F4, GRUB_KEYBOARD_KEY_F5, + /* 0x40 */ GRUB_KEYBOARD_KEY_F6, GRUB_KEYBOARD_KEY_F7, + /* 0x42 */ GRUB_KEYBOARD_KEY_F8, GRUB_KEYBOARD_KEY_F9, + /* 0x44 */ GRUB_KEYBOARD_KEY_F10, GRUB_KEYBOARD_KEY_NUM_LOCK, + /* 0x46 */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, GRUB_KEYBOARD_KEY_NUM7, + /* 0x48 */ GRUB_KEYBOARD_KEY_NUM8, GRUB_KEYBOARD_KEY_NUM9, + /* 0x4a */ GRUB_KEYBOARD_KEY_NUMMINUS, GRUB_KEYBOARD_KEY_NUM4, + /* 0x4c */ GRUB_KEYBOARD_KEY_NUM5, GRUB_KEYBOARD_KEY_NUM6, + /* 0x4e */ GRUB_KEYBOARD_KEY_NUMPLUS, GRUB_KEYBOARD_KEY_NUM1, + /* 0x50 */ GRUB_KEYBOARD_KEY_NUM2, GRUB_KEYBOARD_KEY_NUM3, + /* 0x52 */ GRUB_KEYBOARD_KEY_NUMDOT, GRUB_KEYBOARD_KEY_NUMDOT, + /* 0x54 */ 0, 0, + /* 0x56 */ GRUB_KEYBOARD_KEY_102ND, GRUB_KEYBOARD_KEY_F11, + /* 0x58 */ GRUB_KEYBOARD_KEY_F12, 0, + /* 0x5a */ 0, 0, + /* 0x5c */ 0, 0, + /* 0x5e */ 0, 0, + /* 0x60 */ 0, 0, + /* 0x62 */ 0, 0, + /* OLPC keys. Just mapped to normal keys. */ + /* 0x64 */ 0, GRUB_KEYBOARD_KEY_UP, + /* 0x66 */ GRUB_KEYBOARD_KEY_DOWN, GRUB_KEYBOARD_KEY_LEFT, + /* 0x68 */ GRUB_KEYBOARD_KEY_RIGHT + }; + +static const struct +{ + grub_uint8_t from, to; +} set1_e0_mapping[] = + { + {0x1c, GRUB_KEYBOARD_KEY_NUMENTER}, + {0x1d, GRUB_KEYBOARD_KEY_RIGHT_CTRL}, + {0x35, GRUB_KEYBOARD_KEY_NUMSLASH }, + {0x38, GRUB_KEYBOARD_KEY_RIGHT_ALT}, + {0x47, GRUB_KEYBOARD_KEY_HOME}, + {0x48, GRUB_KEYBOARD_KEY_UP}, + {0x49, GRUB_KEYBOARD_KEY_NPAGE}, + {0x4b, GRUB_KEYBOARD_KEY_LEFT}, + {0x4d, GRUB_KEYBOARD_KEY_RIGHT}, + {0x4f, GRUB_KEYBOARD_KEY_END}, + {0x50, GRUB_KEYBOARD_KEY_DOWN}, + {0x51, GRUB_KEYBOARD_KEY_PPAGE}, + {0x52, GRUB_KEYBOARD_KEY_INSERT}, + {0x53, GRUB_KEYBOARD_KEY_DELETE}, + }; + +static const grub_uint8_t set2_mapping[256] = + { + /* 0x00 */ 0, GRUB_KEYBOARD_KEY_F9, + /* 0x02 */ 0, GRUB_KEYBOARD_KEY_F5, + /* 0x04 */ GRUB_KEYBOARD_KEY_F3, GRUB_KEYBOARD_KEY_F1, + /* 0x06 */ GRUB_KEYBOARD_KEY_F2, GRUB_KEYBOARD_KEY_F12, + /* 0x08 */ 0, GRUB_KEYBOARD_KEY_F10, + /* 0x0a */ GRUB_KEYBOARD_KEY_F8, GRUB_KEYBOARD_KEY_F6, + /* 0x0c */ GRUB_KEYBOARD_KEY_F4, GRUB_KEYBOARD_KEY_TAB, + /* 0x0e */ GRUB_KEYBOARD_KEY_RQUOTE, 0, + /* 0x10 */ 0, GRUB_KEYBOARD_KEY_LEFT_ALT, + /* 0x12 */ GRUB_KEYBOARD_KEY_LEFT_SHIFT, 0, + /* 0x14 */ GRUB_KEYBOARD_KEY_LEFT_CTRL, GRUB_KEYBOARD_KEY_Q, + /* 0x16 */ GRUB_KEYBOARD_KEY_1, 0, + /* 0x18 */ 0, 0, + /* 0x1a */ GRUB_KEYBOARD_KEY_Z, GRUB_KEYBOARD_KEY_S, + /* 0x1c */ GRUB_KEYBOARD_KEY_A, GRUB_KEYBOARD_KEY_W, + /* 0x1e */ GRUB_KEYBOARD_KEY_2, 0, + /* 0x20 */ 0, GRUB_KEYBOARD_KEY_C, + /* 0x22 */ GRUB_KEYBOARD_KEY_X, GRUB_KEYBOARD_KEY_D, + /* 0x24 */ GRUB_KEYBOARD_KEY_E, GRUB_KEYBOARD_KEY_4, + /* 0x26 */ GRUB_KEYBOARD_KEY_3, 0, + /* 0x28 */ 0, GRUB_KEYBOARD_KEY_SPACE, + /* 0x2a */ GRUB_KEYBOARD_KEY_V, GRUB_KEYBOARD_KEY_F, + /* 0x2c */ GRUB_KEYBOARD_KEY_T, GRUB_KEYBOARD_KEY_R, + /* 0x2e */ GRUB_KEYBOARD_KEY_5, 0, + /* 0x30 */ 0, GRUB_KEYBOARD_KEY_N, + /* 0x32 */ GRUB_KEYBOARD_KEY_B, GRUB_KEYBOARD_KEY_H, + /* 0x34 */ GRUB_KEYBOARD_KEY_G, GRUB_KEYBOARD_KEY_Y, + /* 0x36 */ GRUB_KEYBOARD_KEY_6, 0, + /* 0x38 */ 0, 0, + /* 0x3a */ GRUB_KEYBOARD_KEY_M, GRUB_KEYBOARD_KEY_J, + /* 0x3c */ GRUB_KEYBOARD_KEY_U, GRUB_KEYBOARD_KEY_7, + /* 0x3e */ GRUB_KEYBOARD_KEY_8, 0, + /* 0x40 */ 0, GRUB_KEYBOARD_KEY_COMMA, + /* 0x42 */ GRUB_KEYBOARD_KEY_K, GRUB_KEYBOARD_KEY_I, + /* 0x44 */ GRUB_KEYBOARD_KEY_O, GRUB_KEYBOARD_KEY_0, + /* 0x46 */ GRUB_KEYBOARD_KEY_9, 0, + /* 0x48 */ 0, GRUB_KEYBOARD_KEY_DOT, + /* 0x4a */ GRUB_KEYBOARD_KEY_SLASH, GRUB_KEYBOARD_KEY_L, + /* 0x4c */ GRUB_KEYBOARD_KEY_SEMICOLON, GRUB_KEYBOARD_KEY_P, + /* 0x4e */ GRUB_KEYBOARD_KEY_DASH, 0, + /* 0x50 */ 0, 0, + /* 0x52 */ GRUB_KEYBOARD_KEY_DQUOTE, 0, + /* 0x54 */ GRUB_KEYBOARD_KEY_LBRACKET, GRUB_KEYBOARD_KEY_EQUAL, + /* 0x56 */ 0, 0, + /* 0x58 */ GRUB_KEYBOARD_KEY_CAPS_LOCK, GRUB_KEYBOARD_KEY_RIGHT_SHIFT, + /* 0x5a */ GRUB_KEYBOARD_KEY_ENTER, GRUB_KEYBOARD_KEY_RBRACKET, + /* 0x5c */ 0, GRUB_KEYBOARD_KEY_BACKSLASH, + /* 0x5e */ 0, 0, + /* 0x60 */ 0, GRUB_KEYBOARD_KEY_102ND, + /* 0x62 */ 0, 0, + /* 0x64 */ 0, 0, + /* 0x66 */ GRUB_KEYBOARD_KEY_BACKSPACE, 0, + /* 0x68 */ 0, GRUB_KEYBOARD_KEY_NUM1, + /* 0x6a */ 0, GRUB_KEYBOARD_KEY_NUM4, + /* 0x6c */ GRUB_KEYBOARD_KEY_NUM7, 0, + /* 0x6e */ 0, 0, + /* 0x70 */ GRUB_KEYBOARD_KEY_NUMDOT, GRUB_KEYBOARD_KEY_NUM0, + /* 0x72 */ GRUB_KEYBOARD_KEY_NUM2, GRUB_KEYBOARD_KEY_NUM5, + /* 0x74 */ GRUB_KEYBOARD_KEY_NUM6, GRUB_KEYBOARD_KEY_NUM8, + /* 0x76 */ GRUB_KEYBOARD_KEY_ESCAPE, GRUB_KEYBOARD_KEY_NUM_LOCK, + /* 0x78 */ GRUB_KEYBOARD_KEY_F11, GRUB_KEYBOARD_KEY_NUMPLUS, + /* 0x7a */ GRUB_KEYBOARD_KEY_NUM3, GRUB_KEYBOARD_KEY_NUMMINUS, + /* 0x7c */ GRUB_KEYBOARD_KEY_NUMMUL, GRUB_KEYBOARD_KEY_NUM9, + /* 0x7e */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, 0, + /* 0x80 */ 0, 0, + /* 0x82 */ 0, GRUB_KEYBOARD_KEY_F7, + }; + +static const struct +{ + grub_uint8_t from, to; +} set2_e0_mapping[] = + { + {0x11, GRUB_KEYBOARD_KEY_RIGHT_ALT}, + {0x14, GRUB_KEYBOARD_KEY_RIGHT_CTRL}, + {0x4a, GRUB_KEYBOARD_KEY_NUMSLASH}, + {0x5a, GRUB_KEYBOARD_KEY_NUMENTER}, + {0x69, GRUB_KEYBOARD_KEY_END}, + {0x6b, GRUB_KEYBOARD_KEY_LEFT}, + {0x6c, GRUB_KEYBOARD_KEY_HOME}, + {0x70, GRUB_KEYBOARD_KEY_INSERT}, + {0x71, GRUB_KEYBOARD_KEY_DELETE}, + {0x72, GRUB_KEYBOARD_KEY_DOWN}, + {0x74, GRUB_KEYBOARD_KEY_RIGHT}, + {0x75, GRUB_KEYBOARD_KEY_UP}, + {0x7a, GRUB_KEYBOARD_KEY_NPAGE}, + {0x7d, GRUB_KEYBOARD_KEY_PPAGE}, + }; static void keyboard_controller_wait_until_ready (void) @@ -78,22 +216,133 @@ keyboard_controller_wait_until_ready (void) while (! KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS))); } +static grub_uint8_t +wait_ack (void) +{ + grub_uint64_t endtime; + grub_uint8_t ack; + + endtime = grub_get_time_ms () + 20; + do + ack = grub_inb (KEYBOARD_REG_DATA); + while (ack != GRUB_AT_ACK && ack != GRUB_AT_NACK + && grub_get_time_ms () < endtime); + return ack; +} + +static int +at_command (grub_uint8_t data) +{ + unsigned i; + for (i = 0; i < GRUB_AT_TRIES; i++) + { + grub_uint8_t ack; + keyboard_controller_wait_until_ready (); + grub_outb (data, KEYBOARD_REG_STATUS); + ack = wait_ack (); + if (ack == GRUB_AT_NACK) + continue; + if (ack == GRUB_AT_ACK) + break; + return 0; + } + return (i != GRUB_AT_TRIES); +} + static void grub_keyboard_controller_write (grub_uint8_t c) { + at_command (KEYBOARD_COMMAND_WRITE); keyboard_controller_wait_until_ready (); - grub_outb (KEYBOARD_COMMAND_WRITE, KEYBOARD_REG_STATUS); grub_outb (c, KEYBOARD_REG_DATA); } static grub_uint8_t grub_keyboard_controller_read (void) { + at_command (KEYBOARD_COMMAND_READ); keyboard_controller_wait_until_ready (); - grub_outb (KEYBOARD_COMMAND_READ, KEYBOARD_REG_STATUS); return grub_inb (KEYBOARD_REG_DATA); } +static int +write_mode (int mode) +{ + unsigned i; + for (i = 0; i < GRUB_AT_TRIES; i++) + { + grub_uint8_t ack; + keyboard_controller_wait_until_ready (); + grub_outb (0xf0, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + grub_outb (mode, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + ack = wait_ack (); + if (ack == GRUB_AT_NACK) + continue; + if (ack == GRUB_AT_ACK) + break; + return 0; + } + + return (i != GRUB_AT_TRIES); +} + +static int +query_mode (void) +{ + grub_uint8_t ret; + int e; + + e = write_mode (0); + if (!e) + return 0; + + keyboard_controller_wait_until_ready (); + + do + ret = grub_inb (KEYBOARD_REG_DATA); + while (ret == GRUB_AT_ACK); + + /* QEMU translates the set even in no-translate mode. */ + if (ret == 0x43 || ret == 1) + return 1; + if (ret == 0x41 || ret == 2) + return 2; + if (ret == 0x3f || ret == 3) + return 3; + return 0; +} + +static void +set_scancodes (void) +{ + /* You must have visited computer museum. Keyboard without scancode set + knowledge. Assume XT. */ + if (!grub_keyboard_orig_set) + { + grub_dprintf ("atkeyb", "No sets support assumed\n"); + current_set = 1; + return; + } + + grub_keyboard_controller_write (grub_keyboard_controller_orig + & ~KEYBOARD_AT_TRANSLATE); + + write_mode (2); + current_set = query_mode (); + grub_dprintf ("atkeyb", "returned set %d\n", current_set); + if (current_set == 2) + return; + + write_mode (1); + current_set = query_mode (); + grub_dprintf ("atkeyb", "returned set %d\n", current_set); + if (current_set == 1) + return; + grub_printf ("No supported scancode set found\n"); +} + static void keyboard_controller_led (grub_uint8_t leds) { @@ -103,195 +352,271 @@ keyboard_controller_led (grub_uint8_t leds) grub_outb (leds & 0x7, KEYBOARD_REG_DATA); } +static int +fetch_key (int *is_break) +{ + int was_ext = 0; + grub_uint8_t at_key; + int ret = 0; + + if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) + return -1; + at_key = grub_inb (KEYBOARD_REG_DATA); + if (at_key == 0xe0) + { + e0_received = 1; + return -1; + } + + if ((current_set == 2 || current_set == 3) && at_key == 0xf0) + { + f0_received = 1; + return -1; + } + + /* Setting LEDs may generate ACKs. */ + if (at_key == GRUB_AT_ACK) + return -1; + + was_ext = e0_received; + e0_received = 0; + + switch (current_set) + { + case 1: + *is_break = !!(at_key & 0x80); + if (!was_ext) + ret = set1_mapping[at_key & 0x7f]; + else + { + unsigned i; + for (i = 0; i < ARRAY_SIZE (set1_e0_mapping); i++) + if (set1_e0_mapping[i].from == (at_key & 0x7f)) + { + ret = set1_e0_mapping[i].to; + break; + } + } + break; + case 2: + *is_break = f0_received; + f0_received = 0; + if (!was_ext) + ret = set2_mapping[at_key]; + else + { + unsigned i; + for (i = 0; i < ARRAY_SIZE (set2_e0_mapping); i++) + if (set2_e0_mapping[i].from == at_key) + { + ret = set2_e0_mapping[i].to; + break; + } + } + break; + default: + return -1; + } + if (!ret) + { + if (was_ext) + grub_printf ("Unknown key 0xe0+0x%02x from set %d\n", + at_key, current_set); + else + grub_printf ("Unknown key 0x%02x from set %d\n", + at_key, current_set); + return -1; + } + return ret; +} + /* FIXME: This should become an interrupt service routine. For now it's just used to catch events from control keys. */ -static void -grub_keyboard_isr (char key) +static int +grub_keyboard_isr (grub_keyboard_key_t key, int is_break) { - char is_make = KEYBOARD_ISMAKE (key); - key = KEYBOARD_SCANCODE (key); - if (is_make) + if (!is_break) switch (key) { - case SHIFT_L: - at_keyboard_status |= KEYBOARD_STATUS_SHIFT_L; - break; - case SHIFT_R: - at_keyboard_status |= KEYBOARD_STATUS_SHIFT_R; - break; - case CTRL: - at_keyboard_status |= KEYBOARD_STATUS_CTRL_L; - break; - case ALT: - at_keyboard_status |= KEYBOARD_STATUS_ALT_L; - break; - default: - /* Skip grub_dprintf. */ - return; + case GRUB_KEYBOARD_KEY_LEFT_SHIFT: + at_keyboard_status |= GRUB_TERM_STATUS_LSHIFT; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_SHIFT: + at_keyboard_status |= GRUB_TERM_STATUS_RSHIFT; + return 1; + case GRUB_KEYBOARD_KEY_LEFT_CTRL: + at_keyboard_status |= GRUB_TERM_STATUS_LCTRL; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_CTRL: + at_keyboard_status |= GRUB_TERM_STATUS_RCTRL; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_ALT: + at_keyboard_status |= GRUB_TERM_STATUS_RALT; + return 1; + case GRUB_KEYBOARD_KEY_LEFT_ALT: + at_keyboard_status |= GRUB_TERM_STATUS_LALT; + return 1; + default: + return 0; } else switch (key) { - case SHIFT_L: - at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_L; - break; - case SHIFT_R: - at_keyboard_status &= ~KEYBOARD_STATUS_SHIFT_R; - break; - case CTRL: - at_keyboard_status &= ~KEYBOARD_STATUS_CTRL_L; - break; - case ALT: - at_keyboard_status &= ~KEYBOARD_STATUS_ALT_L; - break; - default: - /* Skip grub_dprintf. */ - return; + case GRUB_KEYBOARD_KEY_LEFT_SHIFT: + at_keyboard_status &= ~GRUB_TERM_STATUS_LSHIFT; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_SHIFT: + at_keyboard_status &= ~GRUB_TERM_STATUS_RSHIFT; + return 1; + case GRUB_KEYBOARD_KEY_LEFT_CTRL: + at_keyboard_status &= ~GRUB_TERM_STATUS_LCTRL; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_CTRL: + at_keyboard_status &= ~GRUB_TERM_STATUS_RCTRL; + return 1; + case GRUB_KEYBOARD_KEY_RIGHT_ALT: + at_keyboard_status &= ~GRUB_TERM_STATUS_RALT; + return 1; + case GRUB_KEYBOARD_KEY_LEFT_ALT: + at_keyboard_status &= ~GRUB_TERM_STATUS_LALT; + return 1; + default: + return 0; } -#ifdef DEBUG_AT_KEYBOARD - grub_dprintf ("atkeyb", "Control key 0x%0x was %s\n", key, is_make ? "pressed" : "unpressed"); -#endif } /* If there is a raw key pending, return it; otherwise return -1. */ static int grub_keyboard_getkey (void) { - grub_uint8_t key; - if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) + int key; + int is_break; + + key = fetch_key (&is_break); + if (key == -1) return -1; - key = grub_inb (KEYBOARD_REG_DATA); - /* FIXME */ grub_keyboard_isr (key); - if (! KEYBOARD_ISMAKE (key)) + + if (grub_keyboard_isr (key, is_break)) return -1; - return (KEYBOARD_SCANCODE (key)); + if (is_break) + return -1; + return key; } -/* If there is a character pending, return it; otherwise return -1. */ +/* If there is a character pending, return it; + otherwise return GRUB_TERM_NO_KEY. */ static int -grub_at_keyboard_getkey_noblock (void) +grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) { - int code, key; + int code; code = grub_keyboard_getkey (); if (code == -1) - return -1; + return GRUB_TERM_NO_KEY; #ifdef DEBUG_AT_KEYBOARD grub_dprintf ("atkeyb", "Detected key 0x%x\n", key); #endif switch (code) { - case CAPS_LOCK: - at_keyboard_status ^= KEYBOARD_STATUS_CAPS_LOCK; + case GRUB_KEYBOARD_KEY_CAPS_LOCK: + at_keyboard_status ^= GRUB_TERM_STATUS_CAPS; led_status ^= KEYBOARD_LED_CAPS; keyboard_controller_led (led_status); #ifdef DEBUG_AT_KEYBOARD grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK)); #endif - key = -1; - break; - case NUM_LOCK: - at_keyboard_status ^= KEYBOARD_STATUS_NUM_LOCK; + return GRUB_TERM_NO_KEY; + case GRUB_KEYBOARD_KEY_NUM_LOCK: + at_keyboard_status ^= GRUB_TERM_STATUS_NUM; led_status ^= KEYBOARD_LED_NUM; keyboard_controller_led (led_status); #ifdef DEBUG_AT_KEYBOARD grub_dprintf ("atkeyb", "num_lock = %d\n", !!(at_keyboard_status & KEYBOARD_STATUS_NUM_LOCK)); #endif - key = -1; - break; - case SCROLL_LOCK: - /* For scroll lock we don't keep track of status. Only update its led. */ + return GRUB_TERM_NO_KEY; + case GRUB_KEYBOARD_KEY_SCROLL_LOCK: + at_keyboard_status ^= GRUB_TERM_STATUS_SCROLL; led_status ^= KEYBOARD_LED_SCROLL; keyboard_controller_led (led_status); - key = -1; - break; + return GRUB_TERM_NO_KEY; default: - if (at_keyboard_status & (KEYBOARD_STATUS_CTRL_L | KEYBOARD_STATUS_CTRL_R)) - key = keyboard_map[code] - 'a' + 1; - else if ((at_keyboard_status & (KEYBOARD_STATUS_SHIFT_L | KEYBOARD_STATUS_SHIFT_R)) - && keyboard_map_shift[code]) - key = keyboard_map_shift[code]; - else - key = keyboard_map[code]; - - if (key == 0) - grub_dprintf ("atkeyb", "Unknown key 0x%x detected\n", code); - - if (at_keyboard_status & KEYBOARD_STATUS_CAPS_LOCK) - { - if ((key >= 'a') && (key <= 'z')) - key += 'A' - 'a'; - else if ((key >= 'A') && (key <= 'Z')) - key += 'a' - 'A'; - } + return grub_term_map_key (code, at_keyboard_status); } - return key; -} - -static int -grub_at_keyboard_checkkey (struct grub_term_input *term __attribute__ ((unused))) -{ - if (pending_key != -1) - return 1; - - pending_key = grub_at_keyboard_getkey_noblock (); - - if (pending_key != -1) - return 1; - - return -1; -} - -static int -grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) -{ - int key; - if (pending_key != -1) - { - key = pending_key; - pending_key = -1; - return key; - } - do - { - key = grub_at_keyboard_getkey_noblock (); - } while (key == -1); - return key; } static grub_err_t grub_keyboard_controller_init (struct grub_term_input *term __attribute__ ((unused))) { - pending_key = -1; at_keyboard_status = 0; + /* Drain input buffer. */ + while (1) + { + keyboard_controller_wait_until_ready (); + if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) + break; + keyboard_controller_wait_until_ready (); + grub_inb (KEYBOARD_REG_DATA); + } grub_keyboard_controller_orig = grub_keyboard_controller_read (); - grub_keyboard_controller_write (grub_keyboard_controller_orig | KEYBOARD_SCANCODE_SET1); + grub_keyboard_orig_set = query_mode (); + set_scancodes (); + keyboard_controller_led (led_status); + return GRUB_ERR_NONE; } static grub_err_t grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused))) { + if (grub_keyboard_orig_set) + write_mode (grub_keyboard_orig_set); grub_keyboard_controller_write (grub_keyboard_controller_orig); return GRUB_ERR_NONE; } +static grub_err_t +grub_at_fini_hw (int noreturn __attribute__ ((unused))) +{ + return grub_keyboard_controller_fini (NULL); +} + +static grub_err_t +grub_at_restore_hw (void) +{ + /* Drain input buffer. */ + while (1) + { + keyboard_controller_wait_until_ready (); + if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS))) + break; + keyboard_controller_wait_until_ready (); + grub_inb (KEYBOARD_REG_DATA); + } + set_scancodes (); + keyboard_controller_led (led_status); + + return GRUB_ERR_NONE; +} + + static struct grub_term_input grub_at_keyboard_term = { .name = "at_keyboard", .init = grub_keyboard_controller_init, .fini = grub_keyboard_controller_fini, - .checkkey = grub_at_keyboard_checkkey, - .getkey = grub_at_keyboard_getkey, + .getkey = grub_at_keyboard_getkey }; GRUB_MOD_INIT(at_keyboard) { grub_term_register_input ("at_keyboard", &grub_at_keyboard_term); + grub_loader_register_preboot_hook (grub_at_fini_hw, grub_at_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_CONSOLE); } GRUB_MOD_FINI(at_keyboard) { + grub_keyboard_controller_fini (NULL); grub_term_unregister_input (&grub_at_keyboard_term); } diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c index 6027d0ab3..4872a9a3f 100644 --- a/grub-core/term/efi/console.c +++ b/grub-core/term/efi/console.c @@ -28,8 +28,6 @@ static const grub_uint8_t grub_console_standard_color = GRUB_EFI_TEXT_ATTR (GRUB_EFI_YELLOW, GRUB_EFI_BACKGROUND_BLACK); -static int read_key = -1; - static grub_uint32_t map_char (grub_uint32_t c) { @@ -103,8 +101,19 @@ grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)), efi_call_2 (o->output_string, o, str); } +const unsigned efi_codes[] = + { + 0, GRUB_TERM_KEY_UP, GRUB_TERM_KEY_DOWN, GRUB_TERM_KEY_RIGHT, + GRUB_TERM_KEY_LEFT, GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_END, GRUB_TERM_KEY_INSERT, + GRUB_TERM_KEY_DC, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_F1, + GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5, + GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9, + GRUB_TERM_KEY_F10, 0, 0, '\e' + }; + + static int -grub_console_checkkey (struct grub_term_input *term __attribute__ ((unused))) +grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) { grub_efi_simple_input_interface_t *i; grub_efi_input_key_t key; @@ -113,129 +122,18 @@ grub_console_checkkey (struct grub_term_input *term __attribute__ ((unused))) if (grub_efi_is_finished) return 0; - if (read_key >= 0) - return 1; - i = grub_efi_system_table->con_in; status = efi_call_2 (i->read_key_stroke, i, &key); -#if 0 - switch (status) - { - case GRUB_EFI_SUCCESS: - { - grub_uint16_t xy; - xy = grub_getxy (); - grub_gotoxy (0, 0); - grub_printf ("scan_code=%x,unicode_char=%x ", - (unsigned) key.scan_code, - (unsigned) key.unicode_char); - grub_gotoxy (xy >> 8, xy & 0xff); - } - break; + if (status != GRUB_EFI_SUCCESS) + return GRUB_TERM_NO_KEY; - case GRUB_EFI_NOT_READY: - //grub_printf ("not ready "); - break; + if (key.scan_code == 0) + return key.unicode_char; + else if (key.scan_code < ARRAY_SIZE (efi_codes)) + return efi_codes[key.scan_code]; - default: - //grub_printf ("device error "); - break; - } -#endif - - if (status == GRUB_EFI_SUCCESS) - { - switch (key.scan_code) - { - case 0x00: - read_key = key.unicode_char; - break; - case 0x01: - read_key = GRUB_TERM_UP; - break; - case 0x02: - read_key = GRUB_TERM_DOWN; - break; - case 0x03: - read_key = GRUB_TERM_RIGHT; - break; - case 0x04: - read_key = GRUB_TERM_LEFT; - break; - case 0x05: - read_key = GRUB_TERM_HOME; - break; - case 0x06: - read_key = GRUB_TERM_END; - break; - case 0x07: - break; - case 0x08: - read_key = GRUB_TERM_DC; - break; - case 0x09: - break; - case 0x0a: - break; - case 0x0b: - read_key = 24; - break; - case 0x0c: - read_key = 1; - break; - case 0x0d: - read_key = 5; - break; - case 0x0e: - read_key = 3; - break; - case 0x17: - read_key = '\e'; - break; - default: - break; - } - } - - return read_key; -} - -static int -grub_console_getkey (struct grub_term_input *term) -{ - grub_efi_simple_input_interface_t *i; - grub_efi_boot_services_t *b; - grub_efi_uintn_t index; - grub_efi_status_t status; - int key; - - if (grub_efi_is_finished) - return 0; - - if (read_key >= 0) - { - key = read_key; - read_key = -1; - return key; - } - - i = grub_efi_system_table->con_in; - b = grub_efi_system_table->boot_services; - - do - { - status = efi_call_3 (b->wait_for_event, 1, &(i->wait_for_key), &index); - if (status != GRUB_EFI_SUCCESS) - return -1; - - grub_console_checkkey (term); - } - while (read_key < 0); - - key = read_key; - read_key = -1; - return key; + return GRUB_TERM_NO_KEY; } static grub_uint16_t @@ -353,7 +251,6 @@ grub_efi_console_fini (struct grub_term_output *term) static struct grub_term_input grub_console_term_input = { .name = "console", - .checkkey = grub_console_checkkey, .getkey = grub_console_getkey, }; diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c index 5f88f91ed..9a10d47b0 100644 --- a/grub-core/term/gfxterm.c +++ b/grub-core/term/gfxterm.c @@ -1113,11 +1113,10 @@ static const struct grub_arg_option background_image_cmd_options[] = }; static grub_err_t -grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), - int argc, - char **args) +grub_gfxterm_background_image_cmd (grub_extcmd_context_t ctxt, + int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; /* Check that we have video adapter active. */ if (grub_video_get_info(NULL) != GRUB_ERR_NONE) @@ -1208,8 +1207,7 @@ GRUB_MOD_INIT(gfxterm) grub_term_register_output ("gfxterm", &grub_video_term); background_image_cmd_handle = grub_register_extcmd ("background_image", - grub_gfxterm_background_image_cmd, - GRUB_COMMAND_FLAG_BOTH, + grub_gfxterm_background_image_cmd, 0, N_("[-m (stretch|normal)] FILE"), N_("Load background image for active terminal."), background_image_cmd_options); diff --git a/grub-core/term/i386/pc/console.c b/grub-core/term/i386/pc/console.c index 19a8e3814..0efeafe4e 100644 --- a/grub-core/term/i386/pc/console.c +++ b/grub-core/term/i386/pc/console.c @@ -24,33 +24,18 @@ static const struct grub_machine_bios_data_area *bios_data_area = (struct grub_machine_bios_data_area *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR; -#define KEYBOARD_LEFT_SHIFT (1 << 0) -#define KEYBOARD_RIGHT_SHIFT (1 << 1) -#define KEYBOARD_CTRL (1 << 2) -#define KEYBOARD_ALT (1 << 3) - static int grub_console_getkeystatus (struct grub_term_input *term __attribute__ ((unused))) { - grub_uint8_t status = bios_data_area->keyboard_flag_lower; - int mods = 0; - - if (status & (KEYBOARD_LEFT_SHIFT | KEYBOARD_RIGHT_SHIFT)) - mods |= GRUB_TERM_STATUS_SHIFT; - if (status & KEYBOARD_CTRL) - mods |= GRUB_TERM_STATUS_CTRL; - if (status & KEYBOARD_ALT) - mods |= GRUB_TERM_STATUS_ALT; - - return mods; + /* conveniently GRUB keystatus is modelled after BIOS one. */ + return bios_data_area->keyboard_flag_lower & ~0x80; } static struct grub_term_input grub_console_term_input = { .name = "console", - .checkkey = grub_console_checkkey, .getkey = grub_console_getkey, - .getkeystatus = grub_console_getkeystatus, + .getkeystatus = grub_console_getkeystatus }; static struct grub_term_output grub_console_term_output = diff --git a/grub-core/term/ieee1275/ofconsole.c b/grub-core/term/ieee1275/ofconsole.c index 9ec85631b..226b78b71 100644 --- a/grub-core/term/ieee1275/ofconsole.c +++ b/grub-core/term/ieee1275/ofconsole.c @@ -117,9 +117,14 @@ grub_ofconsole_getwh (struct grub_term_output *term __attribute__ ((unused))) } static void -grub_ofconsole_setcursor (struct grub_term_output *term __attribute__ ((unused)), +grub_ofconsole_setcursor (struct grub_term_output *term, int on) { + grub_terminfo_setcursor (term, on); + + if (!grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF)) + return; + /* Understood by the Open Firmware flavour in OLPC. */ if (on) grub_ieee1275_interpret ("cursor-on", 0); @@ -189,7 +194,6 @@ static struct grub_term_input grub_ofconsole_term_input = { .name = "ofconsole", .init = grub_ofconsole_init_input, - .checkkey = grub_terminfo_checkkey, .getkey = grub_terminfo_getkey, .data = &grub_ofconsole_terminfo_input }; diff --git a/grub-core/term/ns8250.c b/grub-core/term/ns8250.c index f3a804d53..550ee6341 100644 --- a/grub-core/term/ns8250.c +++ b/grub-core/term/ns8250.c @@ -16,7 +16,6 @@ * along with GRUB. If not, see . */ -#include #include #include #include @@ -26,6 +25,7 @@ #include #ifdef GRUB_MACHINE_PCBIOS +#include static const unsigned short *serial_hw_io_addr = (const unsigned short *) GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR; #define GRUB_SERIAL_PORT_NUM 4 #else diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c index 2268788af..e318e4b43 100644 --- a/grub-core/term/serial.c +++ b/grub-core/term/serial.c @@ -99,7 +99,6 @@ static struct grub_term_input grub_serial_term_input = { .name = "serial", .init = grub_terminfo_input_init, - .checkkey = grub_terminfo_checkkey, .getkey = grub_terminfo_getkey, .data = &grub_serial_terminfo_input }; @@ -150,9 +149,9 @@ grub_serial_find (char *name) } static grub_err_t -grub_cmd_serial (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; char pname[40]; char *name = NULL; struct grub_serial_port *port; @@ -341,8 +340,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT(serial) { - cmd = grub_register_extcmd ("serial", grub_cmd_serial, - GRUB_COMMAND_FLAG_BOTH, + cmd = grub_register_extcmd ("serial", grub_cmd_serial, 0, N_("[OPTIONS...]"), N_("Configure serial port."), options); #ifndef GRUB_MACHINE_EMU diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c index 5691b9cc6..8dea7aea1 100644 --- a/grub-core/term/terminfo.c +++ b/grub-core/term/terminfo.c @@ -403,34 +403,34 @@ grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len, static struct { char key; - char ascii; + unsigned ascii; } three_code_table[] = { - {'4', GRUB_TERM_DC}, - {'A', GRUB_TERM_UP}, - {'B', GRUB_TERM_DOWN}, - {'C', GRUB_TERM_RIGHT}, - {'D', GRUB_TERM_LEFT}, - {'F', GRUB_TERM_END}, - {'H', GRUB_TERM_HOME}, - {'K', GRUB_TERM_END}, - {'P', GRUB_TERM_DC}, - {'?', GRUB_TERM_PPAGE}, - {'/', GRUB_TERM_NPAGE} + {'4', GRUB_TERM_KEY_DC}, + {'A', GRUB_TERM_KEY_UP}, + {'B', GRUB_TERM_KEY_DOWN}, + {'C', GRUB_TERM_KEY_RIGHT}, + {'D', GRUB_TERM_KEY_LEFT}, + {'F', GRUB_TERM_KEY_END}, + {'H', GRUB_TERM_KEY_HOME}, + {'K', GRUB_TERM_KEY_END}, + {'P', GRUB_TERM_KEY_DC}, + {'?', GRUB_TERM_KEY_PPAGE}, + {'/', GRUB_TERM_KEY_NPAGE} }; static struct { char key; - char ascii; + unsigned ascii; } four_code_table[] = { - {'1', GRUB_TERM_HOME}, - {'3', GRUB_TERM_DC}, - {'5', GRUB_TERM_PPAGE}, - {'6', GRUB_TERM_NPAGE} + {'1', GRUB_TERM_KEY_HOME}, + {'3', GRUB_TERM_KEY_DC}, + {'5', GRUB_TERM_KEY_PPAGE}, + {'6', GRUB_TERM_KEY_NPAGE} }; unsigned i; @@ -467,39 +467,30 @@ grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len, #undef CONTINUE_READ } -/* The terminfo version of checkkey. */ -int -grub_terminfo_checkkey (struct grub_term_input *termi) -{ - struct grub_terminfo_input_state *data - = (struct grub_terminfo_input_state *) (termi->data); - if (data->npending) - return data->input_buf[0]; - - grub_terminfo_readkey (termi, data->input_buf, - &data->npending, data->readkey); - - if (data->npending) - return data->input_buf[0]; - - return -1; -} - /* The terminfo version of getkey. */ int grub_terminfo_getkey (struct grub_term_input *termi) { struct grub_terminfo_input_state *data = (struct grub_terminfo_input_state *) (termi->data); - int ret; - while (! data->npending) - grub_terminfo_readkey (termi, data->input_buf, &data->npending, - data->readkey); + if (data->npending) + { + data->npending--; + grub_memmove (data->input_buf, data->input_buf + 1, data->npending); + return data->input_buf[0]; + } - ret = data->input_buf[0]; - data->npending--; - grub_memmove (data->input_buf, data->input_buf + 1, data->npending); - return ret; + grub_terminfo_readkey (termi, data->input_buf, + &data->npending, data->readkey); + + if (data->npending) + { + data->npending--; + grub_memmove (data->input_buf, data->input_buf + 1, data->npending); + return data->input_buf[0]; + } + + return GRUB_TERM_NO_KEY; } grub_err_t diff --git a/grub-core/term/usb_keyboard.c b/grub-core/term/usb_keyboard.c index d875ac00a..30ed8f9c2 100644 --- a/grub-core/term/usb_keyboard.c +++ b/grub-core/term/usb_keyboard.c @@ -25,36 +25,26 @@ #include #include #include +#include -static char keyboard_map[128] = + +enum { - '\0', '\0', '\0', '\0', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', - 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', - '3', '4', '5', '6', '7', '8', '9', '0', - '\n', GRUB_TERM_ESC, GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, ' ', '-', '=', '[', - ']', '\\', '#', ';', '\'', '`', ',', '.', - '/', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', - '\0', '\0', GRUB_TERM_HOME, GRUB_TERM_PPAGE, GRUB_TERM_DC, GRUB_TERM_END, GRUB_TERM_NPAGE, GRUB_TERM_RIGHT, - GRUB_TERM_LEFT, GRUB_TERM_DOWN, GRUB_TERM_UP + KEY_NO_KEY = 0x00, + KEY_ERR_BUFFER = 0x01, + KEY_ERR_POST = 0x02, + KEY_ERR_UNDEF = 0x03, + KEY_CAPS_LOCK = 0x39, + KEY_NUM_LOCK = 0x53, }; -static char keyboard_map_shift[128] = +enum { - '\0', '\0', '\0', '\0', 'A', 'B', 'C', 'D', - 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', - 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', - 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', - '#', '$', '%', '^', '&', '*', '(', ')', - '\n', '\0', '\0', '\0', ' ', '_', '+', '{', - '}', '|', '#', ':', '"', '`', '<', '>', - '?' + LED_NUM_LOCK = 0x01, + LED_CAPS_LOCK = 0x02 }; - /* Valid values for bRequest. See HID definition version 1.11 section 7.2. */ #define USB_HID_GET_REPORT 0x01 #define USB_HID_GET_IDLE 0x02 @@ -66,28 +56,65 @@ static char keyboard_map_shift[128] = #define USB_HID_BOOT_SUBCLASS 0x01 #define USB_HID_KBD_PROTOCOL 0x01 -static int grub_usb_keyboard_checkkey (struct grub_term_input *term); -static int grub_usb_keyboard_getkey (struct grub_term_input *term); -static int grub_usb_keyboard_getkeystatus (struct grub_term_input *term); - -static struct grub_term_input grub_usb_keyboard_term = - { - .checkkey = grub_usb_keyboard_checkkey, - .getkey = grub_usb_keyboard_getkey, - .getkeystatus = grub_usb_keyboard_getkeystatus, - .next = 0 - }; +#define GRUB_USB_KEYBOARD_LEFT_CTRL 0x01 +#define GRUB_USB_KEYBOARD_LEFT_SHIFT 0x02 +#define GRUB_USB_KEYBOARD_LEFT_ALT 0x04 +#define GRUB_USB_KEYBOARD_RIGHT_CTRL 0x10 +#define GRUB_USB_KEYBOARD_RIGHT_SHIFT 0x20 +#define GRUB_USB_KEYBOARD_RIGHT_ALT 0x40 struct grub_usb_keyboard_data { grub_usb_device_t usbdev; grub_uint8_t status; - int key; + grub_uint16_t mods; + int interfno; struct grub_usb_desc_endp *endp; + grub_usb_transfer_t transfer; + grub_uint8_t report[8]; + int dead; + int last_key; + grub_uint64_t repeat_time; + grub_uint8_t current_report[8]; + grub_uint8_t last_report[8]; + int index; + int max_index; }; +static int grub_usb_keyboard_getkey (struct grub_term_input *term); +static int grub_usb_keyboard_getkeystatus (struct grub_term_input *term); + +static struct grub_term_input grub_usb_keyboard_term = + { + .getkey = grub_usb_keyboard_getkey, + .getkeystatus = grub_usb_keyboard_getkeystatus, + .next = 0 + }; + static struct grub_term_input grub_usb_keyboards[16]; +static int +interpret_status (grub_uint8_t data0) +{ + int mods = 0; + + /* Check Shift, Control, and Alt status. */ + if (data0 & GRUB_USB_KEYBOARD_LEFT_SHIFT) + mods |= GRUB_TERM_STATUS_LSHIFT; + if (data0 & GRUB_USB_KEYBOARD_RIGHT_SHIFT) + mods |= GRUB_TERM_STATUS_RSHIFT; + if (data0 & GRUB_USB_KEYBOARD_LEFT_CTRL) + mods |= GRUB_TERM_STATUS_LCTRL; + if (data0 & GRUB_USB_KEYBOARD_RIGHT_CTRL) + mods |= GRUB_TERM_STATUS_RCTRL; + if (data0 & GRUB_USB_KEYBOARD_LEFT_ALT) + mods |= GRUB_TERM_STATUS_LALT; + if (data0 & GRUB_USB_KEYBOARD_RIGHT_ALT) + mods |= GRUB_TERM_STATUS_RALT; + + return mods; +} + static void grub_usb_keyboard_detach (grub_usb_device_t usbdev, int config __attribute__ ((unused)), @@ -104,6 +131,9 @@ grub_usb_keyboard_detach (grub_usb_device_t usbdev, if (data->usbdev != usbdev) continue; + if (data->transfer) + grub_usb_cancel_transfer (data->transfer); + grub_term_unregister_input (&grub_usb_keyboards[i]); grub_free ((char *) grub_usb_keyboards[i].name); grub_usb_keyboards[i].name = NULL; @@ -163,15 +193,19 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) } data->usbdev = usbdev; + data->interfno = interfno; data->endp = endp; + /* Configure device */ + grub_usb_set_configuration (usbdev, configno + 1); + /* Place the device in boot mode. */ grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, - USB_HID_SET_PROTOCOL, 0, 0, 0, 0); + USB_HID_SET_PROTOCOL, 0, interfno, 0, 0); /* Reports every time an event occurs and not more often than that. */ grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, - USB_HID_SET_IDLE, 0<<8, 0, 0, 0); + USB_HID_SET_IDLE, 0<<8, interfno, 0, 0); grub_memcpy (&grub_usb_keyboards[curnum], &grub_usb_keyboard_term, sizeof (grub_usb_keyboards[curnum])); @@ -185,24 +219,41 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) return 0; } + /* Test showed that getting report may make the keyboard go nuts. + Moreover since we're reattaching keyboard it usually sends + an initial message on interrupt pipe and so we retrieve + the same keystatus. + */ +#if 0 { grub_uint8_t report[8]; grub_usb_err_t err; grub_memset (report, 0, sizeof (report)); err = grub_usb_control_msg (usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_IN, - USB_HID_GET_REPORT, 0x0000, interfno, + USB_HID_GET_REPORT, 0x0100, interfno, sizeof (report), (char *) report); if (err) - { - data->status = 0; - data->key = -1; - } + data->status = 0; else - { - data->status = report[0]; - data->key = report[2] ? : -1; - } + data->status = report[0]; } +#else + data->status = 0; +#endif + + data->transfer = grub_usb_bulk_read_background (usbdev, + data->endp->endp_addr, + sizeof (data->report), + (char *) data->report); + if (!data->transfer) + { + grub_print_error (); + return 0; + } + + data->last_key = -1; + data->mods = 0; + data->dead = 0; grub_term_register_input_active ("usb_keyboard", &grub_usb_keyboards[curnum]); @@ -211,83 +262,177 @@ grub_usb_keyboard_attach (grub_usb_device_t usbdev, int configno, int interfno) -static int -grub_usb_keyboard_checkkey (struct grub_term_input *term) +static void +send_leds (struct grub_usb_keyboard_data *termdata) { - grub_uint8_t data[8]; - grub_usb_err_t err; - struct grub_usb_keyboard_data *termdata = term->data; - grub_size_t actual; - - if (termdata->key != -1) - return termdata->key; - - data[2] = 0; - /* Poll interrupt pipe. */ - err = grub_usb_bulk_read_extended (termdata->usbdev, - termdata->endp->endp_addr, sizeof (data), - (char *) data, 10, &actual); - if (err || actual < 1) - return -1; - - termdata->status = data[0]; - - if (actual < 3 || !data[2]) - return -1; - - grub_dprintf ("usb_keyboard", - "report: 0x%02x 0x%02x 0x%02x 0x%02x" - " 0x%02x 0x%02x 0x%02x 0x%02x\n", - data[0], data[1], data[2], data[3], - data[4], data[5], data[6], data[7]); - - /* Check if the Control or Shift key was pressed. */ - if (data[0] & 0x01 || data[0] & 0x10) - termdata->key = keyboard_map[data[2]] - 'a' + 1; - else if (data[0] & 0x02 || data[0] & 0x20) - termdata->key = keyboard_map_shift[data[2]]; - else - termdata->key = keyboard_map[data[2]]; - - if (termdata->key == 0) - grub_printf ("Unknown key 0x%x detected\n", data[2]); - + char report[1]; + report[0] = 0; + if (termdata->mods & GRUB_TERM_STATUS_CAPS) + report[0] |= LED_CAPS_LOCK; + if (termdata->mods & GRUB_TERM_STATUS_NUM) + report[0] |= LED_NUM_LOCK; + grub_usb_control_msg (termdata->usbdev, GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT, + USB_HID_SET_REPORT, 0x0200, termdata->interfno, + sizeof (report), (char *) report); grub_errno = GRUB_ERR_NONE; +} - return termdata->key; +static int +parse_keycode (struct grub_usb_keyboard_data *termdata) +{ + int index = termdata->index; + int i, keycode; + + /* Sanity check */ + if (index < 2) + index = 2; + + for ( ; index < termdata->max_index; index++) + { + keycode = termdata->current_report[index]; + + if (keycode == KEY_NO_KEY + || keycode == KEY_ERR_BUFFER + || keycode == KEY_ERR_POST + || keycode == KEY_ERR_UNDEF) + { + /* Don't parse (rest of) this report */ + termdata->index = 0; + if (keycode != KEY_NO_KEY) + /* Don't replace last report with current faulty report + * in future ! */ + grub_memcpy (termdata->current_report, + termdata->last_report, + sizeof (termdata->report)); + return GRUB_TERM_NO_KEY; + } + + /* Try to find current keycode in last report. */ + for (i = 2; i < 8; i++) + if (keycode == termdata->last_report[i]) + break; + if (i < 8) + /* Keycode is in last report, it means it was not released, + * ignore it. */ + continue; + + if (keycode == KEY_CAPS_LOCK) + { + termdata->mods ^= GRUB_TERM_STATUS_CAPS; + send_leds (termdata); + continue; + } + + if (keycode == KEY_NUM_LOCK) + { + termdata->mods ^= GRUB_TERM_STATUS_NUM; + send_leds (termdata); + continue; + } + + termdata->last_key = grub_term_map_key (keycode, + interpret_status (termdata->current_report[0]) + | termdata->mods); + termdata->repeat_time = grub_get_time_ms () + GRUB_TERM_REPEAT_PRE_INTERVAL; + + grub_errno = GRUB_ERR_NONE; + + index++; + if (index >= termdata->max_index) + termdata->index = 0; + else + termdata->index = index; + + return termdata->last_key; + } + + /* All keycodes parsed */ + termdata->index = 0; + return GRUB_TERM_NO_KEY; } static int grub_usb_keyboard_getkey (struct grub_term_input *term) { - int ret; + grub_usb_err_t err; struct grub_usb_keyboard_data *termdata = term->data; + grub_size_t actual; + int keycode = GRUB_TERM_NO_KEY; - while (termdata->key == -1) - grub_usb_keyboard_checkkey (term); + if (termdata->dead) + return GRUB_TERM_NO_KEY; - ret = termdata->key; + if (termdata->index) + keycode = parse_keycode (termdata); + if (keycode != GRUB_TERM_NO_KEY) + return keycode; + + /* Poll interrupt pipe. */ + err = grub_usb_check_transfer (termdata->transfer, &actual); - termdata->key = -1; + if (err == GRUB_USB_ERR_WAIT) + { + if (termdata->last_key != -1 + && grub_get_time_ms () > termdata->repeat_time) + { + termdata->repeat_time = grub_get_time_ms () + + GRUB_TERM_REPEAT_INTERVAL; + return termdata->last_key; + } + return GRUB_TERM_NO_KEY; + } - return ret; + if (!err && (actual >= 3)) + grub_memcpy (termdata->last_report, + termdata->current_report, + sizeof (termdata->report)); + + grub_memcpy (termdata->current_report, + termdata->report, + sizeof (termdata->report)); + + termdata->transfer = grub_usb_bulk_read_background (termdata->usbdev, + termdata->endp->endp_addr, + sizeof (termdata->report), + (char *) termdata->report); + if (!termdata->transfer) + { + grub_printf ("%s failed. Stopped\n", term->name); + termdata->dead = 1; + } + + termdata->last_key = -1; + + grub_dprintf ("usb_keyboard", + "err = %d, actual = %" PRIuGRUB_SIZE + " report: 0x%02x 0x%02x 0x%02x 0x%02x" + " 0x%02x 0x%02x 0x%02x 0x%02x\n", + err, actual, + termdata->current_report[0], termdata->current_report[1], + termdata->current_report[2], termdata->current_report[3], + termdata->current_report[4], termdata->current_report[5], + termdata->current_report[6], termdata->current_report[7]); + + if (err || actual < 1) + return GRUB_TERM_NO_KEY; + + termdata->status = termdata->current_report[0]; + + if (actual < 3) + return GRUB_TERM_NO_KEY; + + termdata->index = 2; /* New data received. */ + termdata->max_index = actual; + + return parse_keycode (termdata); } static int grub_usb_keyboard_getkeystatus (struct grub_term_input *term) { struct grub_usb_keyboard_data *termdata = term->data; - int mods = 0; - /* Check Shift, Control, and Alt status. */ - if (termdata->status & 0x02 || termdata->status & 0x20) - mods |= GRUB_TERM_STATUS_SHIFT; - if (termdata->status & 0x01 || termdata->status & 0x10) - mods |= GRUB_TERM_STATUS_CTRL; - if (termdata->status & 0x04 || termdata->status & 0x40) - mods |= GRUB_TERM_STATUS_ALT; - - return mods; + return interpret_status (termdata->status) | termdata->mods; } struct grub_usb_attach_desc attach_hook = @@ -307,9 +452,18 @@ GRUB_MOD_FINI(usb_keyboard) for (i = 0; i < ARRAY_SIZE (grub_usb_keyboards); i++) if (grub_usb_keyboards[i].data) { + struct grub_usb_keyboard_data *data = grub_usb_keyboards[i].data; + + if (!data) + continue; + + if (data->transfer) + grub_usb_cancel_transfer (data->transfer); + grub_term_unregister_input (&grub_usb_keyboards[i]); grub_free ((char *) grub_usb_keyboards[i].name); grub_usb_keyboards[i].name = NULL; + grub_free (grub_usb_keyboards[i].data); grub_usb_keyboards[i].data = 0; } grub_usb_unregister_attach_hook_class (&attach_hook); diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c index 6aafe4dbb..521f4ad22 100644 --- a/grub-core/tests/lib/functional_test.c +++ b/grub-core/tests/lib/functional_test.c @@ -22,7 +22,7 @@ #include static grub_err_t -grub_functional_test (struct grub_extcmd *cmd __attribute__ ((unused)), +grub_functional_test (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { @@ -37,8 +37,7 @@ static grub_extcmd_t cmd; GRUB_MOD_INIT (functional_test) { - cmd = grub_register_extcmd ("functional_test", grub_functional_test, - GRUB_COMMAND_FLAG_CMDLINE, 0, + cmd = grub_register_extcmd ("functional_test", grub_functional_test, 0, 0, "Run all functional tests.", 0); } diff --git a/grub-core/tests/test_blockarg.c b/grub-core/tests/test_blockarg.c new file mode 100644 index 000000000..41460fb7e --- /dev/null +++ b/grub-core/tests/test_blockarg.c @@ -0,0 +1,51 @@ +/* test_blockarg.c - print and execute block argument */ +/* + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +static grub_err_t +test_blockarg (grub_extcmd_context_t ctxt, int argc, char **args) +{ + if (! ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no block parameter"); + + grub_printf ("%s\n", args[argc - 1]); + grub_script_execute (ctxt->script); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(test_blockarg) +{ + cmd = grub_register_extcmd ("test_blockarg", test_blockarg, + GRUB_COMMAND_FLAG_BLOCKS, + N_("BLOCK"), + N_("Print and execute block argument."), 0); +} + +GRUB_MOD_FINI(test_blockarg) +{ + grub_unregister_extcmd (cmd); +} diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c index 4e79b8521..f02dc9cb6 100644 --- a/grub-core/video/efi_gop.c +++ b/grub-core/video/efi_gop.c @@ -127,9 +127,11 @@ grub_video_gop_get_bitmask (grub_uint32_t mask, unsigned int *mask_size, } static grub_err_t -grub_video_gop_fill_mode_info (struct grub_efi_gop_mode_info *in, +grub_video_gop_fill_mode_info (unsigned mode, + struct grub_efi_gop_mode_info *in, struct grub_video_mode_info *out) { + out->mode_number = mode; out->number_of_colors = 256; out->width = in->width; out->height = in->height; @@ -183,9 +185,43 @@ grub_video_gop_fill_mode_info (struct grub_efi_gop_mode_info *in, return GRUB_ERR_NONE; } +static int +grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info)) +{ + unsigned mode; + + for (mode = 0; mode < gop->mode->max_mode; mode++) + { + grub_efi_uintn_t size; + grub_efi_status_t status; + struct grub_efi_gop_mode_info *info = NULL; + grub_err_t err; + struct grub_video_mode_info mode_info; + + status = efi_call_4 (gop->query_mode, gop, mode, &size, &info); + + if (status) + { + info = 0; + continue; + } + + err = grub_video_gop_fill_mode_info (mode, info, &mode_info); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + if (hook (&mode_info)) + return 1; + } + return 0; +} + static grub_err_t grub_video_gop_setup (unsigned int width, unsigned int height, - unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) + unsigned int mode_type, + unsigned int mode_mask __attribute__ ((unused))) { unsigned int depth; struct grub_efi_gop_mode_info *info = NULL; @@ -226,7 +262,7 @@ grub_video_gop_setup (unsigned int width, unsigned int height, if (status) { info = 0; - break; + continue; } grub_dprintf ("video", "GOP: mode %d: %dx%d\n", mode, info->width, @@ -281,7 +317,8 @@ grub_video_gop_setup (unsigned int width, unsigned int height, info = gop->mode->info; - err = grub_video_gop_fill_mode_info (info, &framebuffer.mode_info); + err = grub_video_gop_fill_mode_info (gop->mode->mode, info, + &framebuffer.mode_info); if (err) { grub_dprintf ("video", "GOP: couldn't fill mode info\n"); @@ -379,6 +416,7 @@ static struct grub_video_adapter grub_video_gop_adapter = .delete_render_target = grub_video_fb_delete_render_target, .set_active_render_target = grub_video_gop_set_active_render_target, .get_active_render_target = grub_video_fb_get_active_render_target, + .iterate = grub_video_gop_iterate, .next = 0 }; diff --git a/grub-core/video/efi_uga.c b/grub-core/video/efi_uga.c index 6352d4342..a8f70edea 100644 --- a/grub-core/video/efi_uga.c +++ b/grub-core/video/efi_uga.c @@ -198,7 +198,8 @@ grub_video_uga_fini (void) static grub_err_t grub_video_uga_setup (unsigned int width, unsigned int height, - unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) + unsigned int mode_type, + unsigned int mode_mask __attribute__ ((unused))) { unsigned int depth; int found = 0; diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c index 3817b3f68..4bb46e4cd 100644 --- a/grub-core/video/i386/pc/vbe.c +++ b/grub-core/video/i386/pc/vbe.c @@ -33,7 +33,6 @@ static int vbe_detected = -1; static struct grub_vbe_info_block controller_info; -static struct grub_vbe_mode_info_block active_vbe_mode_info; /* Track last mode to support cards which fail on get_mode. */ static grub_uint32_t last_set_mode = 3; @@ -42,11 +41,7 @@ static struct { struct grub_video_mode_info mode_info; - unsigned int bytes_per_scan_line; - unsigned int bytes_per_pixel; - grub_uint32_t active_vbe_mode; grub_uint8_t *ptr; - int index_color_mode; } framebuffer; static grub_uint32_t initial_vbe_mode; @@ -332,21 +327,12 @@ grub_vbe_set_video_mode (grub_uint32_t vbe_mode, vbe_mode |= 1 << 14; /* Determine frame buffer pixel format. */ - switch (new_vbe_mode_info.memory_model) - { - case GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL: - framebuffer.index_color_mode = 1; - break; - - case GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR: - framebuffer.index_color_mode = 0; - break; - - default: - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported pixel format 0x%x", - new_vbe_mode_info.memory_model); - } + if (new_vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL + && new_vbe_mode_info.memory_model + != GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported pixel format 0x%x", + new_vbe_mode_info.memory_model); } /* Get current mode. */ @@ -360,24 +346,14 @@ grub_vbe_set_video_mode (grub_uint32_t vbe_mode, return grub_error (GRUB_ERR_BAD_DEVICE, "cannot set VBE mode %x", vbe_mode); last_set_mode = vbe_mode; - /* Save information for later usage. */ - framebuffer.active_vbe_mode = vbe_mode; - grub_memcpy (&active_vbe_mode_info, &new_vbe_mode_info, sizeof (active_vbe_mode_info)); - if (vbe_mode < 0x100) { /* If this is not a VESA mode, guess address. */ framebuffer.ptr = (grub_uint8_t *) GRUB_MEMORY_MACHINE_VGA_ADDR; - framebuffer.index_color_mode = 1; } else { framebuffer.ptr = (grub_uint8_t *) new_vbe_mode_info.phys_base_addr; - - if (controller_info.version >= 0x300) - framebuffer.bytes_per_scan_line = new_vbe_mode_info.lin_bytes_per_scan_line; - else - framebuffer.bytes_per_scan_line = new_vbe_mode_info.bytes_per_scan_line; } /* Check whether mode is text mode or graphics mode. */ @@ -392,25 +368,9 @@ grub_vbe_set_video_mode (grub_uint32_t vbe_mode, { /* Graphics mode. */ - /* Calculate bytes_per_pixel value. */ - switch(new_vbe_mode_info.bits_per_pixel) - { - case 32: framebuffer.bytes_per_pixel = 4; break; - case 24: framebuffer.bytes_per_pixel = 3; break; - case 16: framebuffer.bytes_per_pixel = 2; break; - case 15: framebuffer.bytes_per_pixel = 2; break; - case 8: framebuffer.bytes_per_pixel = 1; break; - default: - grub_vbe_bios_set_mode (old_vbe_mode, 0); - last_set_mode = old_vbe_mode; - return grub_error (GRUB_ERR_BAD_DEVICE, - "cannot set VBE mode %x", - vbe_mode); - break; - } - /* If video mode is in indexed color, setup default VGA palette. */ - if (framebuffer.index_color_mode) + if (vbe_mode < 0x100 || new_vbe_mode_info.memory_model + == GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL) { struct grub_vbe_palette_data *palette = (struct grub_vbe_palette_data *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; @@ -548,10 +508,13 @@ grub_video_vbe_fini (void) grub_err_t err; /* Restore old video mode. */ - status = grub_vbe_bios_set_mode (initial_vbe_mode, 0); - if (status != GRUB_VBE_STATUS_OK) - /* TODO: Decide, is this something we want to do. */ - return grub_errno; + if (last_set_mode != initial_vbe_mode) + { + status = grub_vbe_bios_set_mode (initial_vbe_mode, 0); + if (status != GRUB_VBE_STATUS_OK) + /* TODO: Decide, is this something we want to do. */ + return grub_errno; + } last_set_mode = initial_vbe_mode; /* TODO: Free any resources allocated by driver. */ @@ -583,6 +546,120 @@ doublebuf_pageflipping_set_page (int page) return 0; } +static void +vbe2videoinfo (grub_uint32_t mode, + const struct grub_vbe_mode_info_block *vbeinfo, + struct grub_video_mode_info *mode_info) +{ + mode_info->mode_number = mode; + + mode_info->width = vbeinfo->x_resolution; + mode_info->height = vbeinfo->y_resolution; + mode_info->mode_type = 0; + switch (vbeinfo->memory_model) + { + case GRUB_VBE_MEMORY_MODEL_TEXT: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_PURE_TEXT; + break; + + /* CGA is basically 4-bit packed pixel. */ + case GRUB_VBE_MEMORY_MODEL_CGA: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_CGA; + case GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + break; + + case GRUB_VBE_MEMORY_MODEL_HERCULES: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_HERCULES + | GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP; + break; + + /* Non chain 4 is a special case of planar. */ + case GRUB_VBE_MEMORY_MODEL_NONCHAIN4_256: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_NONCHAIN4; + case GRUB_VBE_MEMORY_MODEL_PLANAR: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_PLANAR + | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + break; + + case GRUB_VBE_MEMORY_MODEL_YUV: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_YUV; + break; + + case GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_RGB; + break; + default: + mode_info->mode_type |= GRUB_VIDEO_MODE_TYPE_UNKNOWN; + break; + } + + mode_info->bpp = vbeinfo->bits_per_pixel; + /* Calculate bytes_per_pixel value. */ + switch(vbeinfo->bits_per_pixel) + { + case 32: + mode_info->bytes_per_pixel = 4; + break; + case 24: + mode_info->bytes_per_pixel = 3; + break; + case 16: + mode_info->bytes_per_pixel = 2; + break; + case 15: + mode_info->bytes_per_pixel = 2; + break; + case 8: + mode_info->bytes_per_pixel = 1; + break; + case 4: + mode_info->bytes_per_pixel = 0; + break; + } + + if (controller_info.version >= 0x300) + mode_info->pitch = vbeinfo->lin_bytes_per_scan_line; + else + mode_info->pitch = vbeinfo->bytes_per_scan_line; + + mode_info->number_of_colors = 256; /* TODO: fix me. */ + mode_info->red_mask_size = vbeinfo->red_mask_size; + mode_info->red_field_pos = vbeinfo->red_field_position; + mode_info->green_mask_size = vbeinfo->green_mask_size; + mode_info->green_field_pos = vbeinfo->green_field_position; + mode_info->blue_mask_size = vbeinfo->blue_mask_size; + mode_info->blue_field_pos = vbeinfo->blue_field_position; + mode_info->reserved_mask_size = vbeinfo->rsvd_mask_size; + mode_info->reserved_field_pos = vbeinfo->rsvd_field_position; + + mode_info->blit_format = grub_video_get_blit_format (mode_info); +} + +static int +grub_video_vbe_iterate (int (*hook) (const struct grub_video_mode_info *info)) +{ + grub_uint16_t *p; + struct grub_vbe_mode_info_block vbe_mode_info; + struct grub_video_mode_info mode_info; + + for (p = vbe_mode_list; *p != 0xFFFF; p++) + { + grub_vbe_get_video_mode_info (*p, &vbe_mode_info); + if (grub_errno != GRUB_ERR_NONE) + { + /* Could not retrieve mode info, retreat. */ + grub_errno = GRUB_ERR_NONE; + break; + } + + vbe2videoinfo (*p, &vbe_mode_info, &mode_info); + if (hook (&mode_info)) + return 1; + } + return 0; +} + static grub_err_t grub_video_vbe_setup (unsigned int width, unsigned int height, unsigned int mode_type, unsigned int mode_mask) @@ -631,6 +708,14 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, /* Not compatible memory model. */ continue; + if (vbe_mode_info.bits_per_pixel != 8 + && vbe_mode_info.bits_per_pixel != 15 + && vbe_mode_info.bits_per_pixel != 16 + && vbe_mode_info.bits_per_pixel != 24 + && vbe_mode_info.bits_per_pixel != 32) + /* Unsupported bitdepth . */ + continue; + if (((vbe_mode_info.x_resolution != width) || (vbe_mode_info.y_resolution != height)) && width != 0 && height != 0) /* Non matching resolution. */ @@ -676,36 +761,16 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, if (best_vbe_mode != 0) { grub_err_t err; + static struct grub_vbe_mode_info_block active_vbe_mode_info; /* If this fails, then we have mode selection heuristics problem, or adapter failure. */ - /* grub_vbe_set_video_mode already sets active_vbe_mode_info. */ - grub_vbe_set_video_mode (best_vbe_mode, NULL); + grub_vbe_set_video_mode (best_vbe_mode, &active_vbe_mode_info); if (grub_errno != GRUB_ERR_NONE) return grub_errno; /* Fill mode info details. */ - framebuffer.mode_info.width = active_vbe_mode_info.x_resolution; - framebuffer.mode_info.height = active_vbe_mode_info.y_resolution; - - if (framebuffer.index_color_mode) - framebuffer.mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; - else - framebuffer.mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_RGB; - - framebuffer.mode_info.bpp = active_vbe_mode_info.bits_per_pixel; - framebuffer.mode_info.bytes_per_pixel = framebuffer.bytes_per_pixel; - framebuffer.mode_info.pitch = framebuffer.bytes_per_scan_line; - framebuffer.mode_info.number_of_colors = 256; /* TODO: fix me. */ - framebuffer.mode_info.red_mask_size = active_vbe_mode_info.red_mask_size; - framebuffer.mode_info.red_field_pos = active_vbe_mode_info.red_field_position; - framebuffer.mode_info.green_mask_size = active_vbe_mode_info.green_mask_size; - framebuffer.mode_info.green_field_pos = active_vbe_mode_info.green_field_position; - framebuffer.mode_info.blue_mask_size = active_vbe_mode_info.blue_mask_size; - framebuffer.mode_info.blue_field_pos = active_vbe_mode_info.blue_field_position; - framebuffer.mode_info.reserved_mask_size = active_vbe_mode_info.rsvd_mask_size; - framebuffer.mode_info.reserved_field_pos = active_vbe_mode_info.rsvd_field_position; - - framebuffer.mode_info.blit_format = grub_video_get_blit_format (&framebuffer.mode_info); + vbe2videoinfo (best_vbe_mode, &active_vbe_mode_info, + &framebuffer.mode_info); { /* Get video RAM size in bytes. */ @@ -740,7 +805,7 @@ static grub_err_t grub_video_vbe_set_palette (unsigned int start, unsigned int count, struct grub_video_palette_data *palette_data) { - if (framebuffer.index_color_mode) + if (framebuffer.mode_info.mode_type == GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) { /* TODO: Implement setting indexed color mode palette to hardware. */ //status = grub_vbe_bios_set_palette_data (sizeof (vga_colors) @@ -764,6 +829,20 @@ grub_video_vbe_get_info_and_fini (struct grub_video_mode_info *mode_info, return grub_video_fb_get_info_and_fini (mode_info, framebuf); } +static void +grub_video_vbe_print_adapter_specific_info (void) +{ + grub_printf (" VBE info: version: %d.%d OEM software rev: %d.%d\n", + controller_info.version >> 8, + controller_info.version & 0xFF, + controller_info.oem_software_rev >> 8, + controller_info.oem_software_rev & 0xFF); + + /* The total_memory field is in 64 KiB units. */ + grub_printf (" total memory: %d KiB\n", + (controller_info.total_memory << 16) / 1024); +} + static struct grub_video_adapter grub_video_vbe_adapter = { .name = "VESA BIOS Extension Video Driver", @@ -793,6 +872,8 @@ static struct grub_video_adapter grub_video_vbe_adapter = .delete_render_target = grub_video_fb_delete_render_target, .set_active_render_target = grub_video_fb_set_active_render_target, .get_active_render_target = grub_video_fb_get_active_render_target, + .iterate = grub_video_vbe_iterate, + .print_adapter_specific_info = grub_video_vbe_print_adapter_specific_info, .next = 0 }; diff --git a/grub-core/video/ieee1275.c b/grub-core/video/ieee1275.c index 9c9477c2b..501ba7c2f 100644 --- a/grub-core/video/ieee1275.c +++ b/grub-core/video/ieee1275.c @@ -32,6 +32,8 @@ static unsigned old_width, old_height; static int restore_needed; static char *display; +static grub_ieee1275_ihandle_t stdout_ihandle; +static int have_setcolors = 0; static struct { @@ -72,7 +74,17 @@ find_display (void) static grub_err_t grub_video_ieee1275_init (void) { + grub_ssize_t actual; + grub_memset (&framebuffer, 0, sizeof(framebuffer)); + + if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_SET_COLORS) + && !grub_ieee1275_get_integer_property (grub_ieee1275_chosen, + "stdout", &stdout_ihandle, + sizeof (stdout_ihandle), &actual) + && actual == sizeof (stdout_ihandle)) + have_setcolors = 1; + return grub_video_fb_init (); } @@ -169,9 +181,6 @@ grub_video_ieee1275_setup (unsigned int width, unsigned int height, /* For some reason sparc64 uses 32-bit pointer too. */ framebuffer.ptr = (void *) (grub_addr_t) address; - grub_video_ieee1275_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, - grub_video_fbstd_colors); - grub_dprintf ("video", "IEEE1275: initialising FB @ %p %dx%dx%d\n", framebuffer.ptr, framebuffer.mode_info.width, framebuffer.mode_info.height, framebuffer.mode_info.bpp); @@ -192,15 +201,10 @@ grub_video_ieee1275_setup (unsigned int width, unsigned int height, grub_dprintf ("video", "IEEE1275: Couldn't set FB target\n"); return err; } - - err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, - grub_video_fbstd_colors); - if (err) - grub_dprintf ("video", "IEEE1275: Couldn't set palette\n"); - else - grub_dprintf ("video", "IEEE1275: Success\n"); - + grub_video_ieee1275_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, + grub_video_fbstd_colors); + return err; } @@ -243,9 +247,17 @@ grub_video_ieee1275_set_palette (unsigned int start, unsigned int count, if (err) return err; - grub_video_fb_get_palette (0, 256, fb_palette_data); + grub_video_fb_get_palette (0, ARRAY_SIZE (fb_palette_data), fb_palette_data); - /* TODO. */ + /* Set colors. */ + if (have_setcolors) + { + unsigned col; + for (col = 0; col < ARRAY_SIZE (fb_palette_data); col++) + grub_ieee1275_set_color (stdout_ihandle, col, fb_palette_data[col].r, + fb_palette_data[col].g, + fb_palette_data[col].b); + } return GRUB_ERR_NONE; } diff --git a/include/grub/acpi.h b/include/grub/acpi.h index 17ffd7686..aebc8dd4f 100644 --- a/include/grub/acpi.h +++ b/include/grub/acpi.h @@ -60,10 +60,12 @@ struct grub_acpi_fadt struct grub_acpi_table_header hdr; grub_uint32_t facs_addr; grub_uint32_t dsdt_addr; - grub_uint8_t somefields1[88]; + grub_uint8_t somefields1[20]; + grub_uint32_t pm1a; + grub_uint8_t somefields2[64]; grub_uint64_t facs_xaddr; grub_uint64_t dsdt_xaddr; - grub_uint8_t somefields2[96]; + grub_uint8_t somefields3[96]; } __attribute__ ((packed)); #define GRUB_ACPI_MADT_SIGNATURE "APIC" @@ -145,4 +147,25 @@ grub_uint8_t grub_byte_checksum (void *base, grub_size_t size); grub_err_t grub_acpi_create_ebda (void); +void grub_acpi_halt (void); + +#define GRUB_ACPI_SLP_EN (1 << 13) +#define GRUB_ACPI_SLP_TYP_OFFSET 10 + +enum + { + GRUB_ACPI_OPCODE_ZERO = 0, GRUB_ACPI_OPCODE_ONE = 1, + GRUB_ACPI_OPCODE_NAME = 8, GRUB_ACPI_OPCODE_BYTE_CONST = 0x0a, + GRUB_ACPI_OPCODE_WORD_CONST = 0x0b, GRUB_ACPI_OPCODE_DWORD_CONST = 0x0c, + GRUB_ACPI_OPCODE_SCOPE = 0x10, GRUB_ACPI_OPCODE_PACKAGE = 0x12, + GRUB_ACPI_OPCODE_METHOD = 0x14, GRUB_ACPI_OPCODE_EXTOP = 0x5b, + GRUB_ACPI_OPCODE_IF = 0xa0, GRUB_ACPI_OPCODE_ONES = 0xff + }; +enum + { + GRUB_ACPI_EXTOPCODE_MUTEX = 0x01, + GRUB_ACPI_EXTOPCODE_OPERATION_REGION = 0x80, + GRUB_ACPI_EXTOPCODE_FIELD_OP = 0x81 + }; + #endif /* ! GRUB_ACPI_HEADER */ diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h index 10421540a..65cf8a2a2 100644 --- a/include/grub/at_keyboard.h +++ b/include/grub/at_keyboard.h @@ -19,36 +19,20 @@ #ifndef GRUB_AT_KEYBOARD_HEADER #define GRUB_AT_KEYBOARD_HEADER 1 -#define SHIFT_L 0x2a -#define SHIFT_R 0x36 -#define CTRL 0x1d -#define ALT 0x38 -#define CAPS_LOCK 0x3a -#define NUM_LOCK 0x45 -#define SCROLL_LOCK 0x46 - /* Used for sending commands to the controller. */ #define KEYBOARD_COMMAND_ISREADY(x) !((x) & 0x02) #define KEYBOARD_COMMAND_READ 0x20 #define KEYBOARD_COMMAND_WRITE 0x60 #define KEYBOARD_COMMAND_REBOOT 0xfe -#define KEYBOARD_SCANCODE_SET1 0x40 +#define KEYBOARD_AT_TRANSLATE 0x40 + +#define GRUB_AT_ACK 0xfa +#define GRUB_AT_NACK 0xfe +#define GRUB_AT_TRIES 5 #define KEYBOARD_ISMAKE(x) !((x) & 0x80) #define KEYBOARD_ISREADY(x) ((x) & 0x01) #define KEYBOARD_SCANCODE(x) ((x) & 0x7f) -#ifdef GRUB_MACHINE_IEEE1275 -#define OLPC_UP GRUB_TERM_UP -#define OLPC_DOWN GRUB_TERM_DOWN -#define OLPC_LEFT GRUB_TERM_LEFT -#define OLPC_RIGHT GRUB_TERM_RIGHT -#else -#define OLPC_UP '\0' -#define OLPC_DOWN '\0' -#define OLPC_LEFT '\0' -#define OLPC_RIGHT '\0' -#endif - #endif diff --git a/include/grub/autoefi.h b/include/grub/autoefi.h index 740be3249..b75591176 100644 --- a/include/grub/autoefi.h +++ b/include/grub/autoefi.h @@ -34,17 +34,6 @@ static inline grub_err_t grub_autoefi_prepare (void) { return GRUB_ERR_NONE; }; -# define GRUB_AUTOEFI_MEMORY_AVAILABLE GRUB_MACHINE_MEMORY_AVAILABLE -# define GRUB_AUTOEFI_MEMORY_RESERVED GRUB_MACHINE_MEMORY_RESERVED -# ifdef GRUB_MACHINE_MEMORY_ACPI -# define GRUB_AUTOEFI_MEMORY_ACPI GRUB_MACHINE_MEMORY_ACPI -# endif -# ifdef GRUB_MACHINE_MEMORY_NVS -# define GRUB_AUTOEFI_MEMORY_NVS GRUB_MACHINE_MEMORY_NVS -# endif -# ifdef GRUB_MACHINE_MEMORY_CODE -# define GRUB_AUTOEFI_MEMORY_CODE GRUB_MACHINE_MEMORY_CODE -# endif # define SYSTEM_TABLE_SIZEOF(x) (sizeof(grub_efi_system_table->x)) # define SYSTEM_TABLE_VAR(x) ((void *)&(grub_efi_system_table->x)) # define SYSTEM_TABLE_PTR(x) ((void *)(grub_efi_system_table->x)) @@ -61,11 +50,6 @@ static inline grub_err_t grub_autoefi_prepare (void) # define grub_autoefi_mmap_iterate grub_efiemu_mmap_iterate # define grub_autoefi_prepare grub_efiemu_prepare # define grub_autoefi_set_virtual_address_map grub_efiemu_set_virtual_address_map -# define GRUB_AUTOEFI_MEMORY_AVAILABLE GRUB_EFIEMU_MEMORY_AVAILABLE -# define GRUB_AUTOEFI_MEMORY_RESERVED GRUB_EFIEMU_MEMORY_RESERVED -# define GRUB_AUTOEFI_MEMORY_ACPI GRUB_EFIEMU_MEMORY_ACPI -# define GRUB_AUTOEFI_MEMORY_NVS GRUB_EFIEMU_MEMORY_NVS -# define GRUB_AUTOEFI_MEMORY_CODE GRUB_EFIEMU_MEMORY_CODE # define SYSTEM_TABLE_SIZEOF GRUB_EFIEMU_SYSTEM_TABLE_SIZEOF # define SYSTEM_TABLE_VAR GRUB_EFIEMU_SYSTEM_TABLE_VAR # define SYSTEM_TABLE_PTR GRUB_EFIEMU_SYSTEM_TABLE_PTR diff --git a/include/grub/cache.h b/include/grub/cache.h index 27e44f0a2..4f913f5c8 100644 --- a/include/grub/cache.h +++ b/include/grub/cache.h @@ -23,6 +23,10 @@ #include #include +#ifdef _mips +#include +#endif + #if defined (__i386__) || defined (__x86_64__) static inline void grub_arch_sync_caches (void *address __attribute__ ((unused)), diff --git a/include/grub/command.h b/include/grub/command.h index 6bd3d07c9..3b7bf0a10 100644 --- a/include/grub/command.h +++ b/include/grub/command.h @@ -23,20 +23,19 @@ #include #include -/* Can be run in the command-line. */ -#define GRUB_COMMAND_FLAG_CMDLINE 0x1 -/* Can be run in the menu. */ -#define GRUB_COMMAND_FLAG_MENU 0x2 -/* Can be run in both interfaces. */ -#define GRUB_COMMAND_FLAG_BOTH 0x3 -/* Only for the command title. */ -#define GRUB_COMMAND_FLAG_TITLE 0x4 -/* Don't print the command on booting. */ -#define GRUB_COMMAND_FLAG_NO_ECHO 0x8 -/* This is an extended command. */ -#define GRUB_COMMAND_FLAG_EXTCMD 0x10 -/* This is an dynamic command. */ -#define GRUB_COMMAND_FLAG_DYNCMD 0x20 +typedef enum grub_command_flags + { + /* This is an extended command. */ + GRUB_COMMAND_FLAG_EXTCMD = 0x10, + /* This is an dynamic command. */ + GRUB_COMMAND_FLAG_DYNCMD = 0x20, + /* This command accepts block arguments. */ + GRUB_COMMAND_FLAG_BLOCKS = 0x40, + /* This command accepts unknown arguments as direct parameters. */ + GRUB_COMMAND_ACCEPT_DASH = 0x80, + /* This command accepts only options preceding direct arguments. */ + GRUB_COMMAND_OPTIONS_AT_START = 0x100, + } grub_command_flags_t; struct grub_command; @@ -59,7 +58,7 @@ struct grub_command grub_command_func_t func; /* The flags. */ - unsigned flags; + grub_command_flags_t flags; /* The summary of the command usage. */ const char *summary; diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 48b52ee65..ebe78e7a1 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -243,10 +243,12 @@ extern gcry_md_spec_t _gcry_digest_spec_md5; extern gcry_md_spec_t _gcry_digest_spec_sha1; extern gcry_md_spec_t _gcry_digest_spec_sha256; extern gcry_md_spec_t _gcry_digest_spec_sha512; +extern gcry_md_spec_t _gcry_digest_spec_crc32; #define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) #define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1) #define GRUB_MD_SHA256 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha256) #define GRUB_MD_SHA512 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha512) +#define GRUB_MD_CRC32 ((const gcry_md_spec_t *) &_gcry_digest_spec_crc32) /* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant of digest supplied by MD. Inputs are the password P of length PLEN, diff --git a/include/grub/disk.h b/include/grub/disk.h index e7f807e0e..e3a0160c4 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -99,9 +99,6 @@ struct grub_disk /* The total number of sectors. */ grub_uint64_t total_sectors; - /* If partitions can be stored. */ - int has_partitions; - /* The id used by the disk cache manager. */ unsigned long id; @@ -177,4 +174,13 @@ struct grub_disk_ata_pass_through_parms extern grub_err_t (* EXPORT_VAR(grub_disk_ata_pass_through)) (grub_disk_t, struct grub_disk_ata_pass_through_parms *); +#if defined (GRUB_UTIL) || defined (GRUB_MACHINE_EMU) +void grub_lvm_init (void); +void grub_mdraid_init (void); +void grub_raid_init (void); +void grub_lvm_fini (void); +void grub_mdraid_fini (void); +void grub_raid_fini (void); +#endif + #endif /* ! GRUB_DISK_HEADER */ diff --git a/include/grub/efi/memory.h b/include/grub/efi/memory.h index 285be8359..133f9504c 100644 --- a/include/grub/efi/memory.h +++ b/include/grub/efi/memory.h @@ -24,16 +24,6 @@ #define GRUB_MMAP_REGISTER_BY_FIRMWARE 1 -#define GRUB_MACHINE_MEMORY_AVAILABLE 1 -#define GRUB_MACHINE_MEMORY_RESERVED 2 -#define GRUB_MACHINE_MEMORY_ACPI 3 -#define GRUB_MACHINE_MEMORY_NVS 4 -#define GRUB_MACHINE_MEMORY_CODE 5 -#define GRUB_MACHINE_MEMORY_MAX_TYPE 5 - /* This one is special: it's used internally but is never reported - by firmware. */ -#define GRUB_MACHINE_MEMORY_HOLE 6 - grub_err_t grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); diff --git a/include/grub/efiemu/efiemu.h b/include/grub/efiemu/efiemu.h index 56d4ea8ee..8eee98b61 100644 --- a/include/grub/efiemu/efiemu.h +++ b/include/grub/efiemu/efiemu.h @@ -233,11 +233,6 @@ grub_efiemu_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, int grub_efiemu_sizeof_uintn_t (void); grub_err_t grub_efiemu_get_lower_upper_memory (grub_uint64_t *lower, grub_uint64_t *upper); -#define GRUB_EFIEMU_MEMORY_AVAILABLE 1 -#define GRUB_EFIEMU_MEMORY_RESERVED 2 -#define GRUB_EFIEMU_MEMORY_ACPI 3 -#define GRUB_EFIEMU_MEMORY_NVS 4 -#define GRUB_EFIEMU_MEMORY_CODE 5 /* efiemu main control definitions and functions*/ typedef enum {GRUB_EFIEMU_NOTLOADED, diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h index 04a2805c8..581ea8056 100644 --- a/include/grub/emu/getroot.h +++ b/include/grub/emu/getroot.h @@ -19,12 +19,15 @@ #ifndef GRUB_UTIL_GETROOT_HEADER #define GRUB_UTIL_GETROOT_HEADER 1 +#include + enum grub_dev_abstraction_types { GRUB_DEV_ABSTRACTION_NONE, GRUB_DEV_ABSTRACTION_LVM, GRUB_DEV_ABSTRACTION_RAID, }; +char *grub_find_device (const char *dir, dev_t dev); char *grub_guess_root_device (const char *dir); int grub_util_get_dev_abstraction (const char *os_dev); char *grub_util_get_grub_dev (const char *os_dev); diff --git a/include/grub/emu/hostdisk.h b/include/grub/emu/hostdisk.h index 246046ee0..d8cc02e14 100644 --- a/include/grub/emu/hostdisk.h +++ b/include/grub/emu/hostdisk.h @@ -26,5 +26,7 @@ void grub_util_biosdisk_init (const char *dev_map); void grub_util_biosdisk_fini (void); char *grub_util_biosdisk_get_grub_dev (const char *os_dev); const char *grub_util_biosdisk_get_osdev (grub_disk_t disk); +int grub_util_biosdisk_is_present (const char *name); +int grub_util_biosdisk_is_floppy (grub_disk_t disk); #endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */ diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h index e9038c916..51cad596a 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h @@ -19,6 +19,9 @@ #ifndef GRUB_EMU_MISC_H #define GRUB_EMU_MISC_H 1 +#include +#include + #include #include #include @@ -45,6 +48,7 @@ extern const char *program_name; void grub_emu_init (void); void grub_init_all (void); void grub_fini_all (void); +void grub_emu_post_init (void); void grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs); diff --git a/include/grub/err.h b/include/grub/err.h index e44705389..d35bba474 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -50,7 +50,7 @@ typedef enum GRUB_ERR_BAD_FONT, GRUB_ERR_NOT_IMPLEMENTED_YET, GRUB_ERR_SYMLINK_LOOP, - GRUB_ERR_BAD_GZIP_DATA, + GRUB_ERR_BAD_COMPRESSED_DATA, GRUB_ERR_MENU, GRUB_ERR_TIMEOUT, GRUB_ERR_IO, diff --git a/include/grub/extcmd.h b/include/grub/extcmd.h index 03eaba8f8..c34a1df66 100644 --- a/include/grub/extcmd.h +++ b/include/grub/extcmd.h @@ -21,10 +21,12 @@ #include #include +#include struct grub_extcmd; +struct grub_extcmd_context; -typedef grub_err_t (*grub_extcmd_func_t) (struct grub_extcmd *cmd, +typedef grub_err_t (*grub_extcmd_func_t) (struct grub_extcmd_context *ctxt, int argc, char **args); /* The argcmd description. */ @@ -38,18 +40,40 @@ struct grub_extcmd const struct grub_arg_option *options; void *data; - - struct grub_arg_list *state; }; typedef struct grub_extcmd *grub_extcmd_t; +/* Command context for each instance of execution. */ +struct grub_extcmd_context +{ + struct grub_extcmd *extcmd; + + struct grub_arg_list *state; + + /* Script parameter, if any. */ + struct grub_script *script; +}; +typedef struct grub_extcmd_context *grub_extcmd_context_t; + grub_extcmd_t grub_register_extcmd (const char *name, grub_extcmd_func_t func, - unsigned flags, + grub_command_flags_t flags, const char *summary, const char *description, const struct grub_arg_option *parser); +grub_extcmd_t grub_register_extcmd_prio (const char *name, + grub_extcmd_func_t func, + grub_command_flags_t flags, + const char *summary, + const char *description, + const struct grub_arg_option *parser, + int prio); + void grub_unregister_extcmd (grub_extcmd_t cmd); +grub_err_t +grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, + struct grub_script *script); + #endif /* ! GRUB_EXTCMD_HEADER */ diff --git a/include/grub/file.h b/include/grub/file.h index 2aacf936f..72cd45468 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -39,6 +39,9 @@ struct grub_file /* The file size. */ grub_off_t size; + /* If file is not easly seekable. Should be set by underlying layer. */ + int not_easly_seekable; + /* Filesystem-specific data. */ void *data; @@ -48,6 +51,51 @@ struct grub_file }; typedef struct grub_file *grub_file_t; +/* Filters with lower ID are executed first. */ +typedef enum grub_file_filter_id + { + GRUB_FILE_FILTER_GZIO, + GRUB_FILE_FILTER_XZIO, + GRUB_FILE_FILTER_MAX, + GRUB_FILE_FILTER_COMPRESSION_FIRST = GRUB_FILE_FILTER_GZIO, + GRUB_FILE_FILTER_COMPRESSION_LAST = GRUB_FILE_FILTER_XZIO, + } grub_file_filter_id_t; + +typedef grub_file_t (*grub_file_filter_t) (grub_file_t in); + +extern grub_file_filter_t EXPORT_VAR(grub_file_filters_all)[GRUB_FILE_FILTER_MAX]; +extern grub_file_filter_t EXPORT_VAR(grub_file_filters_enabled)[GRUB_FILE_FILTER_MAX]; + +static inline void +grub_file_filter_register (grub_file_filter_id_t id, grub_file_filter_t filter) +{ + grub_file_filters_all[id] = filter; + grub_file_filters_enabled[id] = filter; +}; + +static inline void +grub_file_filter_unregister (grub_file_filter_id_t id) +{ + grub_file_filters_all[id] = 0; + grub_file_filters_enabled[id] = 0; +}; + +static inline void +grub_file_filter_disable (grub_file_filter_id_t id) +{ + grub_file_filters_enabled[id] = 0; +}; + +static inline void +grub_file_filter_disable_compression (void) +{ + grub_file_filter_id_t id; + + for (id = GRUB_FILE_FILTER_COMPRESSION_FIRST; + id <= GRUB_FILE_FILTER_COMPRESSION_LAST; id++) + grub_file_filters_enabled[id] = 0; +}; + /* Get a device name from NAME. */ char *EXPORT_FUNC(grub_file_get_device_name) (const char *name); @@ -57,6 +105,9 @@ grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf, grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset); grub_err_t EXPORT_FUNC(grub_file_close) (grub_file_t file); +/* Return value of grub_file_size() in case file size is unknown. */ +#define GRUB_FILE_SIZE_UNKNOWN 0xffffffffffffffffULL + static inline grub_off_t grub_file_size (const grub_file_t file) { @@ -69,4 +120,10 @@ grub_file_tell (const grub_file_t file) return file->offset; } +static inline int +grub_file_seekable (const grub_file_t file) +{ + return !file->not_easly_seekable; +} + #endif /* ! GRUB_FILE_HEADER */ diff --git a/include/grub/gzio.h b/include/grub/gzio.h deleted file mode 100644 index cd7f39793..000000000 --- a/include/grub/gzio.h +++ /dev/null @@ -1,28 +0,0 @@ -/* gzio.h - prototypes for gzio */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_GZIO_H -#define GRUB_GZIO_H 1 - -#include - -grub_file_t grub_gzio_open (grub_file_t io, int transparent); -grub_file_t grub_gzfile_open (const char *name, int transparent); - -#endif /* ! GRUB_GZIO_H */ diff --git a/include/grub/i386/coreboot/lbio.h b/include/grub/i386/coreboot/lbio.h new file mode 100644 index 000000000..aa1853933 --- /dev/null +++ b/include/grub/i386/coreboot/lbio.h @@ -0,0 +1,49 @@ +/* memory.h - describe the memory map */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2007,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 . + */ + +#ifndef _GRUB_MACHINE_LBIO_HEADER +#define _GRUB_MACHINE_LBIO_HEADER 1 + +struct grub_linuxbios_table_header +{ + char signature[4]; + grub_uint32_t size; +}; +typedef struct grub_linuxbios_table_header *grub_linuxbios_table_header_t; + +struct grub_linuxbios_table_item +{ +#define GRUB_LINUXBIOS_MEMBER_UNUSED 0x00 +#define GRUB_LINUXBIOS_MEMBER_MEMORY 0x01 +#define GRUB_LINUXBIOS_MEMBER_LINK 0x11 + grub_uint32_t tag; + grub_uint32_t size; +}; +typedef struct grub_linuxbios_table_item *grub_linuxbios_table_item_t; + +struct grub_linuxbios_mem_region +{ + grub_uint64_t addr; + grub_uint64_t size; +#define GRUB_MACHINE_MEMORY_AVAILABLE 1 + grub_uint32_t type; +}; +typedef struct grub_linuxbios_mem_region *mem_region_t; + +#endif diff --git a/include/grub/i386/coreboot/memory.h b/include/grub/i386/coreboot/memory.h index 664086a81..0642280b9 100644 --- a/include/grub/i386/coreboot/memory.h +++ b/include/grub/i386/coreboot/memory.h @@ -21,11 +21,11 @@ #define _GRUB_MEMORY_MACHINE_LB_HEADER 1 #include -#include #ifndef ASM_FILE #include #include +#include #endif #define GRUB_MEMORY_MACHINE_LOWER_USABLE 0x9fc00 /* 640 kiB - 1 kiB */ @@ -35,36 +35,21 @@ #ifndef ASM_FILE -struct grub_linuxbios_table_header -{ - char signature[4]; - grub_uint32_t size; -}; -typedef struct grub_linuxbios_table_header *grub_linuxbios_table_header_t; - -struct grub_linuxbios_table_item -{ -#define GRUB_LINUXBIOS_MEMBER_UNUSED 0x00 -#define GRUB_LINUXBIOS_MEMBER_MEMORY 0x01 -#define GRUB_LINUXBIOS_MEMBER_LINK 0x11 - grub_uint32_t tag; - grub_uint32_t size; -}; -typedef struct grub_linuxbios_table_item *grub_linuxbios_table_item_t; - -struct grub_linuxbios_mem_region -{ - grub_uint64_t addr; - grub_uint64_t size; -#define GRUB_MACHINE_MEMORY_AVAILABLE 1 - grub_uint32_t type; -}; -typedef struct grub_linuxbios_mem_region *mem_region_t; - void grub_machine_mmap_init (void); -grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) - (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); +static inline grub_err_t +grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), + grub_uint64_t size __attribute__ ((unused)), + int type __attribute__ ((unused)), + int handle __attribute__ ((unused))) +{ + return GRUB_ERR_NONE; +} +static inline grub_err_t +grub_machine_mmap_unregister (int handle __attribute__ ((unused))) +{ + return GRUB_ERR_NONE; +} #endif diff --git a/include/grub/i386/ieee1275/memory.h b/include/grub/i386/ieee1275/memory.h index 386ee4a05..8dd6f7c8c 100644 --- a/include/grub/i386/ieee1275/memory.h +++ b/include/grub/i386/ieee1275/memory.h @@ -1 +1 @@ -#include +#include diff --git a/include/grub/i386/memory.h b/include/grub/i386/memory.h index 4f9a3c916..582226eed 100644 --- a/include/grub/i386/memory.h +++ b/include/grub/i386/memory.h @@ -30,6 +30,14 @@ #ifndef ASM_FILE +#define GRUB_MMAP_MALLOC_LOW 1 + +#include + +grub_uint64_t grub_mmap_get_upper (void); +grub_uint64_t grub_mmap_get_lower (void); +grub_uint64_t grub_mmap_get_post64 (void); + typedef grub_addr_t grub_phys_addr_t; static inline grub_phys_addr_t diff --git a/include/grub/i386/pc/init.h b/include/grub/i386/pc/apm.h similarity index 52% rename from include/grub/i386/pc/init.h rename to include/grub/i386/pc/apm.h index 4005a1772..6d9e8c61d 100644 --- a/include/grub/i386/pc/init.h +++ b/include/grub/i386/pc/apm.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2004,2005,2007,2008 Free Software Foundation, Inc. + * 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 @@ -16,15 +16,33 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_INIT_MACHINE_HEADER -#define GRUB_INIT_MACHINE_HEADER 1 +#ifndef GRUB_APM_MACHINE_HEADER +#define GRUB_APM_MACHINE_HEADER 1 #include -#include -#include -#include -/* Turn on/off Gate A20. */ -void grub_gate_a20 (int on); +struct grub_apm_info +{ + grub_uint16_t cseg; + grub_uint32_t offset; + grub_uint16_t cseg_16; + grub_uint16_t dseg; + grub_uint16_t flags; + grub_uint16_t cseg_len; + grub_uint16_t cseg_16_len; + grub_uint16_t dseg_len; + grub_uint16_t version; +}; -#endif /* ! GRUB_INIT_MACHINE_HEADER */ +enum + { + GRUB_APM_FLAGS_16BITPROTECTED_SUPPORTED = 1, + GRUB_APM_FLAGS_32BITPROTECTED_SUPPORTED = 2, + GRUB_APM_FLAGS_CPUIDLE_SLOWS_DOWN = 4, + GRUB_APM_FLAGS_DISABLED = 8, + GRUB_APM_FLAGS_DISENGAGED = 16, + }; + +int grub_apm_get_info (struct grub_apm_info *info); + +#endif diff --git a/include/grub/i386/pc/console.h b/include/grub/i386/pc/console.h index 7f58344ec..1631a40ad 100644 --- a/include/grub/i386/pc/console.h +++ b/include/grub/i386/pc/console.h @@ -19,19 +19,6 @@ #ifndef GRUB_CONSOLE_MACHINE_HEADER #define GRUB_CONSOLE_MACHINE_HEADER 1 -/* Define scan codes. */ -#define GRUB_CONSOLE_KEY_LEFT 0x4B00 -#define GRUB_CONSOLE_KEY_RIGHT 0x4D00 -#define GRUB_CONSOLE_KEY_UP 0x4800 -#define GRUB_CONSOLE_KEY_DOWN 0x5000 -#define GRUB_CONSOLE_KEY_IC 0x5200 -#define GRUB_CONSOLE_KEY_DC 0x5300 -#define GRUB_CONSOLE_KEY_BACKSPACE 0x0008 -#define GRUB_CONSOLE_KEY_HOME 0x4700 -#define GRUB_CONSOLE_KEY_END 0x4F00 -#define GRUB_CONSOLE_KEY_NPAGE 0x5100 -#define GRUB_CONSOLE_KEY_PPAGE 0x4900 - #ifndef ASM_FILE #include @@ -40,7 +27,6 @@ #include /* These are global to share code between C and asm. */ -int grub_console_checkkey (struct grub_term_input *term); int grub_console_getkey (struct grub_term_input *term); grub_uint16_t grub_console_getxy (struct grub_term_output *term); void grub_console_gotoxy (struct grub_term_output *term, diff --git a/include/grub/i386/pc/int.h b/include/grub/i386/pc/int.h index e1c463925..de23775d0 100644 --- a/include/grub/i386/pc/int.h +++ b/include/grub/i386/pc/int.h @@ -20,6 +20,7 @@ #define GRUB_INTERRUPT_MACHINE_HEADER 1 #include +#include struct grub_bios_int_registers { diff --git a/include/grub/i386/pc/memory.h b/include/grub/i386/pc/memory.h index 68f5e8bc9..401c837fa 100644 --- a/include/grub/i386/pc/memory.h +++ b/include/grub/i386/pc/memory.h @@ -88,51 +88,9 @@ struct grub_machine_bios_data_area grub_uint8_t unused2[0xf0 - 0x18]; }; -struct grub_machine_mmap_entry -{ - grub_uint32_t size; - grub_uint64_t addr; - grub_uint64_t len; -#define GRUB_MACHINE_MEMORY_AVAILABLE 1 -#define GRUB_MACHINE_MEMORY_RESERVED 2 -#define GRUB_MACHINE_MEMORY_ACPI 3 -#define GRUB_MACHINE_MEMORY_NVS 4 -#define GRUB_MACHINE_MEMORY_MAX_TYPE 4 - /* This one is special: it's used internally but is never reported - by firmware. */ -#define GRUB_MACHINE_MEMORY_HOLE 5 - - grub_uint32_t type; -} __attribute__((packed)); - -grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) - (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); - -grub_uint64_t grub_mmap_get_post64 (void); -grub_uint64_t grub_mmap_get_upper (void); -grub_uint64_t grub_mmap_get_lower (void); - -#define GRUB_MMAP_MALLOC_LOW 1 - -#ifdef GRUB_MACHINE_PCBIOS grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size, int type, int handle); grub_err_t grub_machine_mmap_unregister (int handle); -#else -static inline grub_err_t -grub_machine_mmap_register (grub_uint64_t start __attribute__ ((unused)), - grub_uint64_t size __attribute__ ((unused)), - int type __attribute__ ((unused)), - int handle __attribute__ ((unused))) -{ - return GRUB_ERR_NONE; -} -static inline grub_err_t -grub_machine_mmap_unregister (int handle __attribute__ ((unused))) -{ - return GRUB_ERR_NONE; -} -#endif #endif diff --git a/include/grub/i386/pc/pxe.h b/include/grub/i386/pc/pxe.h index 049dd1950..62ece21b0 100644 --- a/include/grub/i386/pc/pxe.h +++ b/include/grub/i386/pc/pxe.h @@ -192,6 +192,19 @@ struct grub_pxenv grub_uint32_t pxe_ptr; /* SEG:OFF to !PXE struct. */ } __attribute__ ((packed)); +struct grub_pxe_bangpxe +{ + grub_uint8_t signature[4]; +#define GRUB_PXE_BANGPXE_SIGNATURE "!PXE" + grub_uint8_t length; + grub_uint8_t chksum; + grub_uint8_t rev; + grub_uint8_t reserved; + grub_uint32_t undiromid; + grub_uint32_t baseromid; + grub_uint32_t rm_entry; +} __attribute__ ((packed)); + struct grub_pxenv_get_cached_info { grub_uint16_t status; @@ -306,7 +319,7 @@ struct grub_pxenv_unload_stack int EXPORT_FUNC(grub_pxe_call) (int func, void * data, grub_uint32_t pxe_rm_entry); -extern struct grub_pxenv *grub_pxe_pxenv; +extern struct grub_pxe_bangpxe *grub_pxe_pxenv; void grub_pxe_unload (void); diff --git a/include/grub/i386/pc/vesa_modes_table.h b/include/grub/i386/pc/vesa_modes_table.h new file mode 100644 index 000000000..376ca376b --- /dev/null +++ b/include/grub/i386/pc/vesa_modes_table.h @@ -0,0 +1,19 @@ +#ifndef GRUB_VESA_MODE_TABLE_HEADER +#define GRUB_VESA_MODE_TABLE_HEADER 1 + +#include + +#define GRUB_VESA_MODE_TABLE_START 0x300 +#define GRUB_VESA_MODE_TABLE_END 0x373 + +struct grub_vesa_mode_table_entry { + grub_uint16_t width; + grub_uint16_t height; + grub_uint8_t depth; +}; + +extern struct grub_vesa_mode_table_entry +grub_vesa_mode_table[GRUB_VESA_MODE_TABLE_END + - GRUB_VESA_MODE_TABLE_START + 1]; + +#endif diff --git a/include/grub/i386/qemu/memory.h b/include/grub/i386/qemu/memory.h index de559443d..2003e4934 100644 --- a/include/grub/i386/qemu/memory.h +++ b/include/grub/i386/qemu/memory.h @@ -21,7 +21,7 @@ #define _GRUB_MEMORY_MACHINE_HEADER 1 #include -#include +#include #ifndef ASM_FILE #include @@ -37,9 +37,6 @@ void grub_machine_mmap_init (void); -grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) - (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); - #endif #endif /* ! _GRUB_MEMORY_MACHINE_HEADER */ diff --git a/include/grub/i386/relocator.h b/include/grub/i386/relocator.h index 891235f9b..6ff5c6631 100644 --- a/include/grub/i386/relocator.h +++ b/include/grub/i386/relocator.h @@ -26,12 +26,14 @@ struct grub_relocator32_state { grub_uint32_t esp; + grub_uint32_t ebp; grub_uint32_t eax; grub_uint32_t ebx; grub_uint32_t ecx; grub_uint32_t edx; grub_uint32_t eip; grub_uint32_t esi; + grub_uint32_t edi; }; struct grub_relocator16_state diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h index b30909c68..2592dd348 100644 --- a/include/grub/ieee1275/ieee1275.h +++ b/include/grub/ieee1275/ieee1275.h @@ -103,6 +103,9 @@ enum grub_ieee1275_flag /* OpenFirmware hangs on qemu if one requests any memory below 1.5 MiB. */ GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM, + + /* OLPC / XO firmware has the cursor ON/OFF routines. */ + GRUB_IEEE1275_FLAG_HAS_CURSORONOFF, }; extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); @@ -187,4 +190,6 @@ int EXPORT_FUNC(grub_ieee1275_devices_iterate) (int (*hook) (struct grub_ieee1275_devalias * alias)); +char *EXPORT_FUNC(grub_ieee1275_canonicalise_devname) (const char *path); + #endif /* ! GRUB_IEEE1275_HEADER */ diff --git a/include/grub/keyboard_layouts.h b/include/grub/keyboard_layouts.h new file mode 100644 index 000000000..24d4880af --- /dev/null +++ b/include/grub/keyboard_layouts.h @@ -0,0 +1,142 @@ +/* + * 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 . + */ + +#ifndef GRUB_KEYBOARD_LAYOUTS_H +#define GRUB_KEYBOARD_LAYOUTS_H 1 + +#define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC "GRUBLAYO" +#define GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE (sizeof(GRUB_KEYBOARD_LAYOUTS_FILEMAGIC) - 1) +#define GRUB_KEYBOARD_LAYOUTS_VERSION 8 + +#define GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE 128 + +struct grub_keyboard_layout +{ + grub_uint32_t keyboard_map[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_shift[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; + grub_uint32_t keyboard_map_shift_l3[GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE]; +}; + +typedef enum grub_keyboard_key + { + GRUB_KEYBOARD_KEY_A = 0x04, + GRUB_KEYBOARD_KEY_B = 0x05, + GRUB_KEYBOARD_KEY_C = 0x06, + GRUB_KEYBOARD_KEY_D = 0x07, + GRUB_KEYBOARD_KEY_E = 0x08, + GRUB_KEYBOARD_KEY_F = 0x09, + GRUB_KEYBOARD_KEY_G = 0x0a, + GRUB_KEYBOARD_KEY_H = 0x0b, + GRUB_KEYBOARD_KEY_I = 0x0c, + GRUB_KEYBOARD_KEY_J = 0x0d, + GRUB_KEYBOARD_KEY_K = 0x0e, + GRUB_KEYBOARD_KEY_L = 0x0f, + GRUB_KEYBOARD_KEY_M = 0x10, + GRUB_KEYBOARD_KEY_N = 0x11, + GRUB_KEYBOARD_KEY_O = 0x12, + GRUB_KEYBOARD_KEY_P = 0x13, + GRUB_KEYBOARD_KEY_Q = 0x14, + GRUB_KEYBOARD_KEY_R = 0x15, + GRUB_KEYBOARD_KEY_S = 0x16, + GRUB_KEYBOARD_KEY_T = 0x17, + GRUB_KEYBOARD_KEY_U = 0x18, + GRUB_KEYBOARD_KEY_V = 0x19, + GRUB_KEYBOARD_KEY_W = 0x1a, + GRUB_KEYBOARD_KEY_X = 0x1b, + GRUB_KEYBOARD_KEY_Y = 0x1c, + GRUB_KEYBOARD_KEY_Z = 0x1d, + GRUB_KEYBOARD_KEY_1 = 0x1e, + GRUB_KEYBOARD_KEY_2 = 0x1f, + GRUB_KEYBOARD_KEY_3 = 0x20, + GRUB_KEYBOARD_KEY_4 = 0x21, + GRUB_KEYBOARD_KEY_5 = 0x22, + GRUB_KEYBOARD_KEY_6 = 0x23, + GRUB_KEYBOARD_KEY_7 = 0x24, + GRUB_KEYBOARD_KEY_8 = 0x25, + GRUB_KEYBOARD_KEY_9 = 0x26, + GRUB_KEYBOARD_KEY_0 = 0x27, + GRUB_KEYBOARD_KEY_ENTER = 0x28, + GRUB_KEYBOARD_KEY_ESCAPE = 0x29, + GRUB_KEYBOARD_KEY_BACKSPACE = 0x2a, + GRUB_KEYBOARD_KEY_TAB = 0x2b, + GRUB_KEYBOARD_KEY_SPACE = 0x2c, + GRUB_KEYBOARD_KEY_DASH = 0x2d, + GRUB_KEYBOARD_KEY_EQUAL = 0x2e, + GRUB_KEYBOARD_KEY_LBRACKET = 0x2f, + GRUB_KEYBOARD_KEY_RBRACKET = 0x30, + GRUB_KEYBOARD_KEY_BACKSLASH = 0x32, + GRUB_KEYBOARD_KEY_SEMICOLON = 0x33, + GRUB_KEYBOARD_KEY_DQUOTE = 0x34, + GRUB_KEYBOARD_KEY_RQUOTE = 0x35, + GRUB_KEYBOARD_KEY_COMMA = 0x36, + GRUB_KEYBOARD_KEY_DOT = 0x37, + GRUB_KEYBOARD_KEY_SLASH = 0x38, + GRUB_KEYBOARD_KEY_CAPS_LOCK = 0x39, + GRUB_KEYBOARD_KEY_F1 = 0x3a, + GRUB_KEYBOARD_KEY_F2 = 0x3b, + GRUB_KEYBOARD_KEY_F3 = 0x3c, + GRUB_KEYBOARD_KEY_F4 = 0x3d, + GRUB_KEYBOARD_KEY_F5 = 0x3e, + GRUB_KEYBOARD_KEY_F6 = 0x3f, + GRUB_KEYBOARD_KEY_F7 = 0x40, + GRUB_KEYBOARD_KEY_F8 = 0x41, + GRUB_KEYBOARD_KEY_F9 = 0x42, + GRUB_KEYBOARD_KEY_F10 = 0x43, + GRUB_KEYBOARD_KEY_F11 = 0x44, + GRUB_KEYBOARD_KEY_F12 = 0x45, + GRUB_KEYBOARD_KEY_SCROLL_LOCK = 0x47, + GRUB_KEYBOARD_KEY_INSERT = 0x49, + GRUB_KEYBOARD_KEY_HOME = 0x4a, + GRUB_KEYBOARD_KEY_PPAGE = 0x4b, + GRUB_KEYBOARD_KEY_DELETE = 0x4c, + GRUB_KEYBOARD_KEY_END = 0x4d, + GRUB_KEYBOARD_KEY_NPAGE = 0x4e, + GRUB_KEYBOARD_KEY_RIGHT = 0x4f, + GRUB_KEYBOARD_KEY_LEFT = 0x50, + GRUB_KEYBOARD_KEY_DOWN = 0x51, + GRUB_KEYBOARD_KEY_UP = 0x52, + GRUB_KEYBOARD_KEY_NUM_LOCK = 0x53, + GRUB_KEYBOARD_KEY_NUMSLASH = 0x54, + GRUB_KEYBOARD_KEY_NUMMUL = 0x55, + GRUB_KEYBOARD_KEY_NUMMINUS = 0x56, + GRUB_KEYBOARD_KEY_NUMPLUS = 0x57, + GRUB_KEYBOARD_KEY_NUMENTER = 0x58, + GRUB_KEYBOARD_KEY_NUM1 = 0x59, + GRUB_KEYBOARD_KEY_NUM2 = 0x5a, + GRUB_KEYBOARD_KEY_NUM3 = 0x5b, + GRUB_KEYBOARD_KEY_NUM4 = 0x5c, + GRUB_KEYBOARD_KEY_NUM5 = 0x5d, + GRUB_KEYBOARD_KEY_NUM6 = 0x5e, + GRUB_KEYBOARD_KEY_NUM7 = 0x5f, + GRUB_KEYBOARD_KEY_NUM8 = 0x60, + GRUB_KEYBOARD_KEY_NUM9 = 0x61, + GRUB_KEYBOARD_KEY_NUM0 = 0x62, + GRUB_KEYBOARD_KEY_NUMDOT = 0x63, + GRUB_KEYBOARD_KEY_102ND = 0x64, + GRUB_KEYBOARD_KEY_LEFT_CTRL = 0xe0, + GRUB_KEYBOARD_KEY_LEFT_SHIFT = 0xe1, + GRUB_KEYBOARD_KEY_LEFT_ALT = 0xe2, + GRUB_KEYBOARD_KEY_RIGHT_CTRL = 0xe4, + GRUB_KEYBOARD_KEY_RIGHT_SHIFT = 0xe5, + GRUB_KEYBOARD_KEY_RIGHT_ALT = 0xe6, + } grub_keyboard_key_t; + +unsigned EXPORT_FUNC(grub_term_map_key) (grub_keyboard_key_t code, int status); + +#endif /* GRUB_KEYBOARD_LAYOUTS */ diff --git a/include/grub/lib/crc.h b/include/grub/legacy_parse.h similarity index 75% rename from include/grub/lib/crc.h rename to include/grub/legacy_parse.h index ff7284dc8..a5e67a071 100644 --- a/include/grub/lib/crc.h +++ b/include/grub/legacy_parse.h @@ -1,4 +1,3 @@ -/* crc.h - prototypes for crc */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2008 Free Software Foundation, Inc. @@ -17,9 +16,12 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_CRC_H -#define GRUB_CRC_H 1 +#ifndef GRUB_LEGACY_PARSE_HEADER +#define GRUB_LEGACY_PARSE_HEADER 1 -grub_uint32_t grub_getcrc32 (grub_uint32_t crc, void *buf, int size); +#include -#endif /* ! GRUB_CRC_H */ +char *grub_legacy_parse (const char *buf, char **entryname, char **suffix); +char *grub_legacy_escape (const char *in, grub_size_t len); + +#endif diff --git a/include/grub/lib/arg.h b/include/grub/lib/arg.h index e6af60cf9..3bab27781 100644 --- a/include/grub/lib/arg.h +++ b/include/grub/lib/arg.h @@ -38,6 +38,8 @@ typedef enum grub_arg_type grub_arg_type_t; /* Flags for the option field op grub_arg_option. */ #define GRUB_ARG_OPTION_OPTIONAL (1 << 1) +/* Flags for an option that can appear multiple times. */ +#define GRUB_ARG_OPTION_REPEATABLE (1 << 2) enum grub_key_type { @@ -59,7 +61,10 @@ struct grub_arg_option struct grub_arg_list { int set; - char *arg; + union { + char *arg; + char **args; + }; }; struct grub_extcmd; @@ -68,5 +73,7 @@ int grub_arg_parse (struct grub_extcmd *cmd, int argc, char **argv, struct grub_arg_list *usr, char ***args, int *argnum); void grub_arg_show_help (struct grub_extcmd *cmd); +struct grub_arg_list* grub_arg_list_alloc (struct grub_extcmd *cmd, + int argc, char *argv[]); #endif /* ! GRUB_ARG_HEADER */ diff --git a/include/grub/libgcc.h b/include/grub/libgcc.h index d0adae8c1..8c4c19d8c 100644 --- a/include/grub/libgcc.h +++ b/include/grub/libgcc.h @@ -16,7 +16,8 @@ * along with GRUB. If not, see . */ -#include +/* We need to include config-util.h.in for HAVE_*. */ +#include /* On x86 these functions aren't really needed. Save some space. */ #if !defined (__i386__) && !defined (__x86_64__) diff --git a/include/grub/loader.h b/include/grub/loader.h index 319f3c551..c71e8dd10 100644 --- a/include/grub/loader.h +++ b/include/grub/loader.h @@ -26,16 +26,16 @@ #include /* Check if a loader is loaded. */ -int grub_loader_is_loaded (void); +int EXPORT_FUNC (grub_loader_is_loaded) (void); /* Set loader functions. NORETURN must be set to true, if BOOT won't return to the original state. */ -void grub_loader_set (grub_err_t (*boot) (void), - grub_err_t (*unload) (void), - int noreturn); +void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), + grub_err_t (*unload) (void), + int noreturn); /* Unset current loader, if any. */ -void grub_loader_unset (void); +void EXPORT_FUNC (grub_loader_unset) (void); /* Call the boot hook in current loader. This may or may not return, depending on the setting by grub_loader_set. */ @@ -56,7 +56,7 @@ typedef enum { } grub_loader_preboot_hook_prio_t; /* Register a preboot hook. */ -void *grub_loader_register_preboot_hook (grub_err_t (*preboot_func) (int noret), +void *EXPORT_FUNC(grub_loader_register_preboot_hook) (grub_err_t (*preboot_func) (int noret), grub_err_t (*preboot_rest_func) (void), grub_loader_preboot_hook_prio_t prio); diff --git a/include/grub/memory.h b/include/grub/memory.h index 43f90e1dd..d98386565 100644 --- a/include/grub/memory.h +++ b/include/grub/memory.h @@ -22,11 +22,32 @@ #include #include -#include -grub_err_t grub_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, - grub_uint64_t, - grub_uint32_t)); +typedef enum grub_memory_type + { + GRUB_MEMORY_AVAILABLE = 1, + GRUB_MEMORY_RESERVED = 2, + GRUB_MEMORY_ACPI = 3, + GRUB_MEMORY_NVS = 4, + GRUB_MEMORY_BADRAM = 5, + GRUB_MEMORY_CODE = 20, + /* This one is special: it's used internally but is never reported + by firmware. */ + GRUB_MEMORY_HOLE = 21 + } grub_memory_type_t; + +typedef int NESTED_FUNC_ATTR (*grub_memory_hook_t) (grub_uint64_t, + grub_uint64_t, + grub_memory_type_t); + +grub_err_t grub_mmap_iterate (grub_memory_hook_t hook); + +#if !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_EFI) +grub_err_t EXPORT_FUNC(grub_machine_mmap_iterate) (grub_memory_hook_t hook); +#else +grub_err_t grub_machine_mmap_iterate (grub_memory_hook_t hook); +#endif + int grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type); grub_err_t grub_mmap_unregister (int handle); @@ -42,7 +63,7 @@ struct grub_mmap_region struct grub_mmap_region *next; grub_uint64_t start; grub_uint64_t end; - int type; + grub_memory_type_t type; int handle; }; diff --git a/include/grub/menu.h b/include/grub/menu.h index e5e5fb110..608253863 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -47,6 +47,10 @@ struct grub_menu_entry /* The sourcecode of the menu entry, used by the editor. */ const char *sourcecode; + /* Parameters to be passed to menu definition. */ + int argc; + char **args; + int hotkey; /* The next element. */ @@ -96,4 +100,7 @@ void grub_menu_execute_with_fallback (grub_menu_t menu, void grub_menu_entry_run (grub_menu_entry_t entry); int grub_menu_get_default_entry_index (grub_menu_t menu); +void grub_menu_init (void); +void grub_menu_fini (void); + #endif /* GRUB_MENU_HEADER */ diff --git a/include/grub/mips/qemu-mips/memory.h b/include/grub/mips/qemu-mips/memory.h index 87e68674e..99d9ef2be 100644 --- a/include/grub/mips/qemu-mips/memory.h +++ b/include/grub/mips/qemu-mips/memory.h @@ -28,8 +28,6 @@ #define GRUB_MACHINE_MEMORY_STACK_HIGH 0x80f00000 #define GRUB_MACHINE_MEMORY_USABLE 0x81000000 -#define GRUB_MACHINE_MEMORY_AVAILABLE 1 - #ifndef ASM_FILE grub_err_t EXPORT_FUNC (grub_machine_mmap_iterate) (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); diff --git a/include/grub/mips/time.h b/include/grub/mips/time.h index e69de29bb..b143a48e0 100644 --- a/include/grub/mips/time.h +++ b/include/grub/mips/time.h @@ -0,0 +1,6 @@ +#ifdef GRUB_MACHINE_EMU +static inline void +grub_cpu_idle(void) +{ +} +#endif diff --git a/include/grub/mips/yeeloong/memory.h b/include/grub/mips/yeeloong/memory.h index e7e995283..9d53b5e0e 100644 --- a/include/grub/mips/yeeloong/memory.h +++ b/include/grub/mips/yeeloong/memory.h @@ -31,13 +31,6 @@ #define GRUB_ARCH_LOWMEMMAXSIZE 0x10000000 #define GRUB_ARCH_HIGHMEMPSTART 0x10000000 -#define GRUB_MACHINE_MEMORY_AVAILABLE 1 -#define GRUB_MACHINE_MEMORY_MAX_TYPE 1 - /* This one is special: it's used internally but is never reported - by firmware. */ -#define GRUB_MACHINE_MEMORY_HOLE 2 -#define GRUB_MACHINE_MEMORY_RESERVED GRUB_MACHINE_MEMORY_HOLE - #ifndef ASM_FILE typedef grub_addr_t grub_phys_addr_t; diff --git a/include/grub/misc.h b/include/grub/misc.h index 774dc5843..27f15e44a 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -270,11 +270,11 @@ void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, grub_uint32_t d, grub_uint32_t *r); -#if defined(NEED_ENABLE_EXECUTE_STACK) && !defined(GRUB_UTIL) +#if NEED_ENABLE_EXECUTE_STACK && !defined(GRUB_UTIL) void EXPORT_FUNC(__enable_execute_stack) (void *addr); #endif -#if defined (NEED_REGISTER_FRAME_INFO) && !defined(GRUB_UTIL) +#if NEED_REGISTER_FRAME_INFO && !defined(GRUB_UTIL) void EXPORT_FUNC (__register_frame_info) (void); void EXPORT_FUNC (__deregister_frame_info) (void); #endif diff --git a/include/grub/normal.h b/include/grub/normal.h index 2a0298bc6..72912e524 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -54,8 +54,6 @@ void grub_normal_execute (const char *config, int nested, int batch); void grub_menu_init_page (int nested, int edit, struct grub_term_output *term); void grub_normal_init_page (struct grub_term_output *term); -grub_err_t grub_normal_add_menu_entry (int argc, const char **args, - const char *sourcecode); char *grub_file_getline (grub_file_t file); void grub_cmdline_run (int nested); @@ -117,4 +115,15 @@ void grub_normal_reset_more (void); void grub_xputs_normal (const char *str); +grub_err_t +grub_normal_add_menu_entry (int argc, const char **args, char **classes, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode); + +grub_err_t +grub_normal_set_password (const char *user, const char *password); + +void grub_normal_auth_init (void); +void grub_normal_auth_fini (void); + #endif /* ! GRUB_NORMAL_HEADER */ diff --git a/include/grub/offsets.h b/include/grub/offsets.h index 7763e488c..91a41ef95 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -34,14 +34,17 @@ /* The offset of GRUB_INSTALL_BSD_PART. */ #define GRUB_KERNEL_I386_PC_INSTALL_BSD_PART 0x18 -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_I386_PC_PREFIX 0x1c - -/* End of the data section. */ -#define GRUB_KERNEL_I386_PC_DATA_END 0x5c +/* The offset of multiboot signature. */ +#define GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE 0x1c /* The size of the first region which won't be compressed. */ -#define GRUB_KERNEL_I386_PC_RAW_SIZE (GRUB_KERNEL_I386_PC_DATA_END + 0x5F0) +#define GRUB_KERNEL_I386_PC_RAW_SIZE 0x5D8 + +/* The offset of GRUB_PREFIX. */ +#define GRUB_KERNEL_I386_PC_PREFIX GRUB_KERNEL_I386_PC_RAW_SIZE + +/* End of the data section. */ +#define GRUB_KERNEL_I386_PC_PREFIX_END (GRUB_KERNEL_I386_PC_PREFIX + 0x40) /* The segment where the kernel is loaded. */ #define GRUB_BOOT_I386_PC_KERNEL_SEG 0x800 @@ -65,7 +68,7 @@ #define GRUB_KERNEL_I386_QEMU_PREFIX 0x10 /* End of the data section. */ -#define GRUB_KERNEL_I386_QEMU_DATA_END 0x50 +#define GRUB_KERNEL_I386_QEMU_PREFIX_END 0x50 #define GRUB_KERNEL_I386_QEMU_LINK_ADDR 0x8200 @@ -82,7 +85,7 @@ #define GRUB_KERNEL_SPARC64_IEEE1275_PREFIX 0x14 /* End of the data section. */ -#define GRUB_KERNEL_SPARC64_IEEE1275_DATA_END 0x114 +#define GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END 0x114 #define GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE 12 @@ -91,7 +94,7 @@ #define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400 #define GRUB_KERNEL_POWERPC_IEEE1275_PREFIX 0x4 -#define GRUB_KERNEL_POWERPC_IEEE1275_DATA_END 0x44 +#define GRUB_KERNEL_POWERPC_IEEE1275_PREFIX_END 0x44 #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4 #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000 @@ -105,29 +108,29 @@ #define GRUB_KERNEL_MIPS_YEELOONG_KERNEL_IMAGE_SIZE 0x10 #define GRUB_KERNEL_MIPS_YEELOONG_PREFIX GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE -#define GRUB_KERNEL_MIPS_YEELOONG_DATA_END GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE + 0x48 +#define GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE + 0x48 /* The offset of GRUB_PREFIX. */ #define GRUB_KERNEL_I386_EFI_PREFIX 0x8 /* End of the data section. */ -#define GRUB_KERNEL_I386_EFI_DATA_END 0x50 +#define GRUB_KERNEL_I386_EFI_PREFIX_END 0x50 /* The offset of GRUB_PREFIX. */ #define GRUB_KERNEL_X86_64_EFI_PREFIX 0x8 /* End of the data section. */ -#define GRUB_KERNEL_X86_64_EFI_DATA_END 0x50 +#define GRUB_KERNEL_X86_64_EFI_PREFIX_END 0x50 #define GRUB_KERNEL_I386_COREBOOT_PREFIX 0x2 -#define GRUB_KERNEL_I386_COREBOOT_DATA_END 0x42 +#define GRUB_KERNEL_I386_COREBOOT_PREFIX_END 0x42 #define GRUB_KERNEL_I386_COREBOOT_LINK_ADDR 0x8200 #define GRUB_KERNEL_I386_MULTIBOOT_PREFIX GRUB_KERNEL_I386_COREBOOT_PREFIX -#define GRUB_KERNEL_I386_MULTIBOOT_DATA_END GRUB_KERNEL_I386_COREBOOT_DATA_END +#define GRUB_KERNEL_I386_MULTIBOOT_PREFIX_END GRUB_KERNEL_I386_COREBOOT_PREFIX_END #define GRUB_KERNEL_I386_IEEE1275_PREFIX 0x2 -#define GRUB_KERNEL_I386_IEEE1275_DATA_END 0x42 +#define GRUB_KERNEL_I386_IEEE1275_PREFIX_END 0x42 #define GRUB_KERNEL_I386_IEEE1275_LINK_ADDR 0x10000 #define GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN 0x1000 @@ -147,22 +150,22 @@ rewrite grub-mkimage to generate valid ELF files. */ #define GRUB_KERNEL_POWERPC_IEEE1275_MOD_GAP 0x8000 -#ifdef MACHINE +#ifdef GRUB_MACHINE #define GRUB_OFFSETS_CONCAT_(a,b,c) a ## b ## c #define GRUB_OFFSETS_CONCAT(a,b,c) GRUB_OFFSETS_CONCAT_(a,b,c) -#define GRUB_KERNEL_MACHINE_MOD_ALIGN GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _MOD_ALIGN) -#define GRUB_KERNEL_MACHINE_MOD_GAP GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _MOD_GAP) -#define GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _TOTAL_MODULE_SIZE) -#define GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _KERNEL_IMAGE_SIZE) -#define GRUB_KERNEL_MACHINE_COMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _COMPRESSED_SIZE) +#define GRUB_KERNEL_MACHINE_MOD_ALIGN GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _MOD_ALIGN) +#define GRUB_KERNEL_MACHINE_MOD_GAP GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _MOD_GAP) +#define GRUB_KERNEL_MACHINE_TOTAL_MODULE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _TOTAL_MODULE_SIZE) +#define GRUB_KERNEL_MACHINE_KERNEL_IMAGE_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _KERNEL_IMAGE_SIZE) +#define GRUB_KERNEL_MACHINE_COMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _COMPRESSED_SIZE) -#define GRUB_KERNEL_MACHINE_PREFIX GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _PREFIX) -#define GRUB_KERNEL_MACHINE_DATA_END GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _DATA_END) -#define GRUB_BOOT_MACHINE_KERNEL_SEG GRUB_OFFSETS_CONCAT (GRUB_BOOT_, MACHINE, _KERNEL_SEG) -#define GRUB_MEMORY_MACHINE_UPPER GRUB_OFFSETS_CONCAT (GRUB_MEMORY_, MACHINE, _UPPER) -#define GRUB_KERNEL_MACHINE_RAW_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _RAW_SIZE) -#define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _INSTALL_BSD_PART) -#define GRUB_KERNEL_MACHINE_INSTALL_DOS_PART GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _INSTALL_DOS_PART) +#define GRUB_KERNEL_MACHINE_PREFIX GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _PREFIX) +#define GRUB_KERNEL_MACHINE_PREFIX_END GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _PREFIX_END) +#define GRUB_BOOT_MACHINE_KERNEL_SEG GRUB_OFFSETS_CONCAT (GRUB_BOOT_, GRUB_MACHINE, _KERNEL_SEG) +#define GRUB_MEMORY_MACHINE_UPPER GRUB_OFFSETS_CONCAT (GRUB_MEMORY_, GRUB_MACHINE, _UPPER) +#define GRUB_KERNEL_MACHINE_RAW_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _RAW_SIZE) +#define GRUB_KERNEL_MACHINE_INSTALL_BSD_PART GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _INSTALL_BSD_PART) +#define GRUB_KERNEL_MACHINE_INSTALL_DOS_PART GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, GRUB_MACHINE, _INSTALL_DOS_PART) #endif #ifndef ASM_FILE diff --git a/include/grub/partition.h b/include/grub/partition.h index 20705c527..a29a3440d 100644 --- a/include/grub/partition.h +++ b/include/grub/partition.h @@ -26,6 +26,13 @@ struct grub_disk; typedef struct grub_partition *grub_partition_t; +#ifdef GRUB_UTIL +typedef enum +{ + GRUB_EMBED_PCBIOS +} grub_embed_type_t; +#endif + /* Partition map type. */ struct grub_partition_map { @@ -39,6 +46,11 @@ struct grub_partition_map grub_err_t (*iterate) (struct grub_disk *disk, int (*hook) (struct grub_disk *disk, const grub_partition_t partition)); +#ifdef GRUB_UTIL + /* Determine sectors available for embedding. */ + grub_err_t (*embed) (struct grub_disk *disk, unsigned int nsectors, + grub_embed_type_t embed_type, grub_disk_addr_t *sectors); +#endif }; typedef struct grub_partition_map *grub_partition_map_t; diff --git a/include/grub/powerpc/ieee1275/memory.h b/include/grub/powerpc/ieee1275/memory.h deleted file mode 100644 index f8f2ff08d..000000000 --- a/include/grub/powerpc/ieee1275/memory.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_MEMORY_MACHINE_HEADER -#define GRUB_MEMORY_MACHINE_HEADER 1 - -#include - -#define GRUB_MACHINE_MEMORY_AVAILABLE 1 - -#endif diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 77e807360..6d31fca5a 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -40,8 +40,13 @@ struct grub_script_cmd struct grub_script { + unsigned refcnt; struct grub_script_mem *mem; struct grub_script_cmd *cmd; + + /* grub_scripts from block arguments. */ + struct grub_script *next_siblings; + struct grub_script *children; }; typedef enum @@ -50,7 +55,8 @@ typedef enum GRUB_SCRIPT_ARG_TYPE_TEXT, GRUB_SCRIPT_ARG_TYPE_DQVAR, GRUB_SCRIPT_ARG_TYPE_DQSTR, - GRUB_SCRIPT_ARG_TYPE_SQSTR + GRUB_SCRIPT_ARG_TYPE_SQSTR, + GRUB_SCRIPT_ARG_TYPE_BLOCK } grub_script_arg_type_t; /* A part of an argument. */ @@ -60,6 +66,9 @@ struct grub_script_arg char *str; + /* Parsed block argument. */ + struct grub_script *script; + /* Next argument part. */ struct grub_script_arg *next; }; @@ -69,8 +78,19 @@ struct grub_script_argv { unsigned argc; char **args; + struct grub_script *script; }; +/* Pluggable wildcard translator. */ +struct grub_script_wildcard_translator +{ + char *(*escape) (const char *str); + char *(*unescape) (const char *str); + grub_err_t (*expand) (const char *str, char ***expansions); +}; +extern struct grub_script_wildcard_translator *grub_wildcard_translator; +extern struct grub_script_wildcard_translator grub_filename_translator; + /* A complete argument. It consists of a list of one or more `struct grub_script_arg's. */ struct grub_script_arglist @@ -135,21 +155,6 @@ struct grub_script_cmdwhile int until; }; -/* A menu entry generate statement. */ -struct grub_script_cmd_menuentry -{ - struct grub_script_cmd cmd; - - /* The arguments for this menu entry. */ - struct grub_script_arglist *arglist; - - /* The sourcecode the entry will be generated from. */ - const char *sourcecode; - - /* Options. XXX: Not used yet. */ - int options; -}; - /* State of the lexer as passed to the lexer. */ struct grub_lexer_param { @@ -194,6 +199,12 @@ struct grub_lexer_param /* Type of text. */ grub_script_arg_type_t type; + /* Flag to indicate resplit in progres. */ + unsigned resplit; + + /* Text that is unput. */ + char *prefix; + /* Flex scanner. */ void *yyscanner; @@ -217,6 +228,9 @@ struct grub_parser_param /* The memory that was used while parsing and scanning. */ struct grub_script_mem *memused; + /* The block argument scripts. */ + struct grub_script *scripts; + /* The result of the parser. */ struct grub_script_cmd *parsed; @@ -226,7 +240,10 @@ struct grub_parser_param void grub_script_init (void); void grub_script_fini (void); +void grub_script_mem_free (struct grub_script_mem *mem); + void grub_script_argv_free (struct grub_script_argv *argv); +int grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args); int grub_script_argv_next (struct grub_script_argv *argv); int grub_script_argv_append (struct grub_script_argv *argv, const char *s); int grub_script_argv_split_append (struct grub_script_argv *argv, char *s); @@ -260,12 +277,6 @@ grub_script_create_cmdwhile (struct grub_parser_param *state, struct grub_script_cmd *list, int is_an_until_loop); -struct grub_script_cmd * -grub_script_create_cmdmenu (struct grub_parser_param *state, - struct grub_script_arglist *arglist, - char *sourcecode, - int options); - struct grub_script_cmd * grub_script_append_cmd (struct grub_parser_param *state, struct grub_script_cmd *list, @@ -287,9 +298,9 @@ struct grub_lexer_param *grub_script_lexer_init (struct grub_parser_param *parse void grub_script_lexer_fini (struct grub_lexer_param *); void grub_script_lexer_ref (struct grub_lexer_param *); void grub_script_lexer_deref (struct grub_lexer_param *); -void grub_script_lexer_record_start (struct grub_parser_param *); -char *grub_script_lexer_record_stop (struct grub_parser_param *); -int grub_script_lexer_yywrap (struct grub_parser_param *); +unsigned grub_script_lexer_record_start (struct grub_parser_param *); +char *grub_script_lexer_record_stop (struct grub_parser_param *, unsigned); +int grub_script_lexer_yywrap (struct grub_parser_param *, const char *input); void grub_script_lexer_record (struct grub_parser_param *, char *); /* Functions to track allocated memory. */ @@ -310,10 +321,10 @@ grub_err_t grub_script_execute_cmdlist (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdfor (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdwhile (struct grub_script_cmd *cmd); -grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd); /* Execute any GRUB pre-parsed command or script. */ grub_err_t grub_script_execute (struct grub_script *script); +grub_err_t grub_script_execute_sourcecode (const char *source, int argc, char **args); /* Break command for loops. */ grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]); @@ -321,6 +332,12 @@ grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]); /* SHIFT command for GRUB script. */ grub_err_t grub_script_shift (grub_command_t cmd, int argc, char *argv[]); +/* SETPARAMS command for GRUB script functions. */ +grub_err_t grub_script_setparams (grub_command_t cmd, int argc, char *argv[]); + +/* RETURN command for functions. */ +grub_err_t grub_script_return (grub_command_t cmd, int argc, char *argv[]); + /* This variable points to the parsed command. This is used to communicate with the bison code. */ extern struct grub_script_cmd *grub_script_parsed; @@ -365,4 +382,24 @@ grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *c grub_err_t grub_normal_parse_line (char *line, grub_reader_getline_t getline); +static inline struct grub_script * +grub_script_ref (struct grub_script *script) +{ + if (script) + script->refcnt++; + return script; +} + +static inline void +grub_script_unref (struct grub_script *script) +{ + if (! script) + return; + + if (script->refcnt == 0) + grub_script_free (script); + else + script->refcnt--; +} + #endif /* ! GRUB_NORMAL_PARSER_HEADER */ diff --git a/include/grub/search.h b/include/grub/search.h index e8f9db285..d80347df3 100644 --- a/include/grub/search.h +++ b/include/grub/search.h @@ -19,8 +19,11 @@ #ifndef GRUB_SEARCH_HEADER #define GRUB_SEARCH_HEADER 1 -void grub_search_fs_file (const char *key, const char *var, int no_floppy); -void grub_search_fs_uuid (const char *key, const char *var, int no_floppy); -void grub_search_label (const char *key, const char *var, int no_floppy); +void grub_search_fs_file (const char *key, const char *var, int no_floppy, + char **hints, unsigned nhints); +void grub_search_fs_uuid (const char *key, const char *var, int no_floppy, + char **hints, unsigned nhints); +void grub_search_label (const char *key, const char *var, int no_floppy, + char **hints, unsigned nhints); #endif diff --git a/include/grub/sparc64/ieee1275/boot.h b/include/grub/sparc64/ieee1275/boot.h index bd0a7bf3c..112d19bc7 100644 --- a/include/grub/sparc64/ieee1275/boot.h +++ b/include/grub/sparc64/ieee1275/boot.h @@ -52,4 +52,13 @@ #define GRUB_BOOT_MACHINE_KERNEL_ADDR 0x4200 +#ifndef ASM_FILE +/* This is the blocklist used in the diskboot image. */ +struct grub_boot_blocklist +{ + grub_uint64_t start; + grub_uint32_t len; +} __attribute__ ((packed)); +#endif + #endif /* ! BOOT_MACHINE_HEADER */ diff --git a/include/grub/sparc64/ieee1275/memory.h b/include/grub/sparc64/ieee1275/memory.h deleted file mode 100644 index 25e31002e..000000000 --- a/include/grub/sparc64/ieee1275/memory.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_MEMORY_MACHINE_HEADER -#define GRUB_MEMORY_MACHINE_HEADER 1 - -#include - -#define GRUB_MACHINE_MEMORY_AVAILABLE 1 - -#endif diff --git a/include/grub/symbol.h b/include/grub/symbol.h index 63ed19436..c6adb7ee3 100644 --- a/include/grub/symbol.h +++ b/include/grub/symbol.h @@ -25,7 +25,7 @@ #define LOCAL(sym) L_ ## sym /* Add an underscore to a C symbol in assembler code if needed. */ -#ifdef HAVE_ASM_USCORE +#if HAVE_ASM_USCORE # define EXT_C(sym) _ ## sym #else # define EXT_C(sym) sym diff --git a/include/grub/term.h b/include/grub/term.h index 734e4ab17..dbcb2f52c 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -19,19 +19,45 @@ #ifndef GRUB_TERM_HEADER #define GRUB_TERM_HEADER 1 +#define GRUB_TERM_NO_KEY 0 + /* Internal codes used by GRUB to represent terminal input. */ -#define GRUB_TERM_LEFT 2 -#define GRUB_TERM_RIGHT 6 -#define GRUB_TERM_UP 16 -#define GRUB_TERM_DOWN 14 -#define GRUB_TERM_HOME 1 -#define GRUB_TERM_END 5 -#define GRUB_TERM_DC 4 -#define GRUB_TERM_PPAGE 7 -#define GRUB_TERM_NPAGE 3 +/* Only for keys otherwise not having shifted modification. */ +#define GRUB_TERM_SHIFT 0x01000000 +#define GRUB_TERM_CTRL 0x02000000 +#define GRUB_TERM_ALT 0x04000000 + +/* Keys without associated character. */ +#define GRUB_TERM_EXTENDED 0x00800000 +#define GRUB_TERM_KEY_MASK 0x00ffffff + +#define GRUB_TERM_KEY_LEFT (GRUB_TERM_EXTENDED | 0x4b) +#define GRUB_TERM_KEY_RIGHT (GRUB_TERM_EXTENDED | 0x4d) +#define GRUB_TERM_KEY_UP (GRUB_TERM_EXTENDED | 0x48) +#define GRUB_TERM_KEY_DOWN (GRUB_TERM_EXTENDED | 0x50) +#define GRUB_TERM_KEY_HOME (GRUB_TERM_EXTENDED | 0x47) +#define GRUB_TERM_KEY_END (GRUB_TERM_EXTENDED | 0x4f) +#define GRUB_TERM_KEY_DC (GRUB_TERM_EXTENDED | 0x53) +#define GRUB_TERM_KEY_PPAGE (GRUB_TERM_EXTENDED | 0x49) +#define GRUB_TERM_KEY_NPAGE (GRUB_TERM_EXTENDED | 0x51) +#define GRUB_TERM_KEY_F1 (GRUB_TERM_EXTENDED | 0x3b) +#define GRUB_TERM_KEY_F2 (GRUB_TERM_EXTENDED | 0x3c) +#define GRUB_TERM_KEY_F3 (GRUB_TERM_EXTENDED | 0x3d) +#define GRUB_TERM_KEY_F4 (GRUB_TERM_EXTENDED | 0x3e) +#define GRUB_TERM_KEY_F5 (GRUB_TERM_EXTENDED | 0x3f) +#define GRUB_TERM_KEY_F6 (GRUB_TERM_EXTENDED | 0x40) +#define GRUB_TERM_KEY_F7 (GRUB_TERM_EXTENDED | 0x41) +#define GRUB_TERM_KEY_F8 (GRUB_TERM_EXTENDED | 0x42) +#define GRUB_TERM_KEY_F9 (GRUB_TERM_EXTENDED | 0x43) +#define GRUB_TERM_KEY_F10 (GRUB_TERM_EXTENDED | 0x44) +#define GRUB_TERM_KEY_F11 (GRUB_TERM_EXTENDED | 0x57) +#define GRUB_TERM_KEY_F12 (GRUB_TERM_EXTENDED | 0x58) +#define GRUB_TERM_KEY_INSERT (GRUB_TERM_EXTENDED | 0x52) +#define GRUB_TERM_KEY_CENTER (GRUB_TERM_EXTENDED | 0x4c) + #define GRUB_TERM_ESC '\e' #define GRUB_TERM_TAB '\t' -#define GRUB_TERM_BACKSPACE 8 +#define GRUB_TERM_BACKSPACE '\b' #ifndef ASM_FILE @@ -86,9 +112,15 @@ grub_term_color_state; /* Bitmasks for modifier keys returned by grub_getkeystatus. */ -#define GRUB_TERM_STATUS_SHIFT (1 << 0) -#define GRUB_TERM_STATUS_CTRL (1 << 1) -#define GRUB_TERM_STATUS_ALT (1 << 2) +#define GRUB_TERM_STATUS_RSHIFT (1 << 0) +#define GRUB_TERM_STATUS_LSHIFT (1 << 1) +#define GRUB_TERM_STATUS_RCTRL (1 << 2) +#define GRUB_TERM_STATUS_RALT (1 << 3) +#define GRUB_TERM_STATUS_SCROLL (1 << 4) +#define GRUB_TERM_STATUS_NUM (1 << 5) +#define GRUB_TERM_STATUS_CAPS (1 << 6) +#define GRUB_TERM_STATUS_LCTRL (1 << 8) +#define GRUB_TERM_STATUS_LALT (1 << 9) /* Menu-related geometrical constants. */ @@ -128,10 +160,7 @@ struct grub_term_input /* Clean up the terminal. */ grub_err_t (*fini) (struct grub_term_input *term); - /* Check if any input character is available. */ - int (*checkkey) (struct grub_term_input *term); - - /* Get a character. */ + /* Get a character if any input character is available. Otherwise return -1 */ int (*getkey) (struct grub_term_input *term); /* Get keyboard modifier status. */ @@ -279,7 +308,6 @@ grub_term_unregister_output (grub_term_output_t term) void grub_putcode (grub_uint32_t code, struct grub_term_output *term); int EXPORT_FUNC(grub_getkey) (void); int EXPORT_FUNC(grub_checkkey) (void); -int EXPORT_FUNC(grub_getkeystatus) (void); void grub_cls (void); void EXPORT_FUNC(grub_refresh) (void); void grub_puts_terminal (const char *str, struct grub_term_output *term); @@ -461,8 +489,8 @@ grub_print_spaces (struct grub_term_output *term, int number_spaces) extern void (*EXPORT_VAR (grub_term_poll_usb)) (void); -/* For convenience. */ -#define GRUB_TERM_ASCII_CHAR(c) ((c) & 0xff) +#define GRUB_TERM_REPEAT_PRE_INTERVAL 400 +#define GRUB_TERM_REPEAT_INTERVAL 50 #endif /* ! ASM_FILE */ diff --git a/include/grub/terminfo.h b/include/grub/terminfo.h index 85ddb5779..1962c71b7 100644 --- a/include/grub/terminfo.h +++ b/include/grub/terminfo.h @@ -64,7 +64,6 @@ void EXPORT_FUNC (grub_terminfo_setcolorstate) (struct grub_term_output *term, const grub_term_color_state state); -int EXPORT_FUNC (grub_terminfo_checkkey) (struct grub_term_input *term); grub_err_t EXPORT_FUNC (grub_terminfo_input_init) (struct grub_term_input *term); int EXPORT_FUNC (grub_terminfo_getkey) (struct grub_term_input *term); void EXPORT_FUNC (grub_terminfo_putchar) (struct grub_term_output *term, diff --git a/include/grub/types.h b/include/grub/types.h index 766eddf07..221fef3c0 100644 --- a/include/grub/types.h +++ b/include/grub/types.h @@ -101,8 +101,10 @@ typedef grub_int64_t grub_ssize_t; # if GRUB_CPU_SIZEOF_LONG == 8 # define PRIxGRUB_SIZE "lx" +# define PRIuGRUB_SIZE "lu" # else # define PRIxGRUB_SIZE "llx" +# define PRIuGRUB_SIZE "llu" # endif #else typedef grub_uint32_t grub_addr_t; @@ -110,6 +112,7 @@ typedef grub_uint32_t grub_size_t; typedef grub_int32_t grub_ssize_t; # define PRIxGRUB_SIZE "x" +# define PRIuGRUB_SIZE "u" #endif #if GRUB_CPU_SIZEOF_LONG == 8 diff --git a/include/grub/usb.h b/include/grub/usb.h index bb3336580..6f838e4f9 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -30,6 +30,7 @@ typedef struct grub_usb_controller_dev *grub_usb_controller_dev_t; typedef enum { GRUB_USB_ERR_NONE, + GRUB_USB_ERR_WAIT, GRUB_USB_ERR_INTERNAL, GRUB_USB_ERR_STALL, GRUB_USB_ERR_DATA, @@ -48,14 +49,6 @@ typedef enum GRUB_USB_SPEED_HIGH } grub_usb_speed_t; -enum - { - GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT = 0x21, - GRUB_USB_REQTYPE_VENDOR_OUT = 0x40, - GRUB_USB_REQTYPE_CLASS_INTERFACE_IN = 0xa1, - GRUB_USB_REQTYPE_VENDOR_IN = 0xc0 - }; - /* Call HOOK with each device, until HOOK returns non-zero. */ int grub_usb_iterate (int (*hook) (grub_usb_device_t dev)); @@ -97,6 +90,7 @@ grub_usb_err_t grub_usb_root_hub (grub_usb_controller_t controller); + /* XXX: All handled by libusb for now. */ struct grub_usb_controller_dev { @@ -105,9 +99,15 @@ struct grub_usb_controller_dev int (*iterate) (int (*hook) (grub_usb_controller_t dev)); - grub_usb_err_t (*transfer) (grub_usb_controller_t dev, - grub_usb_transfer_t transfer, - int timeout, grub_size_t *actual); + grub_usb_err_t (*setup_transfer) (grub_usb_controller_t dev, + grub_usb_transfer_t transfer); + + grub_usb_err_t (*check_transfer) (grub_usb_controller_t dev, + grub_usb_transfer_t transfer, + grub_size_t *actual); + + grub_usb_err_t (*cancel_transfer) (grub_usb_controller_t dev, + grub_usb_transfer_t transfer); int (*hubports) (grub_usb_controller_t dev); @@ -116,6 +116,9 @@ struct grub_usb_controller_dev grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port, int *changed); + /* Per controller flag - port reset pending, don't do another reset */ + grub_uint64_t pending_reset; + /* The next host controller. */ struct grub_usb_controller_dev *next; }; @@ -181,11 +184,19 @@ struct grub_usb_device /* Used by libusb wrapper. Schedulded for removal. */ void *data; + /* Hub information. */ + /* Array of children for a hub. */ grub_usb_device_t *children; /* Number of hub ports. */ unsigned nports; + + grub_usb_transfer_t hub_transfer; + + grub_uint32_t statuschange; + + struct grub_usb_desc_endp *hub_endpoint; }; @@ -266,5 +277,12 @@ grub_usb_err_t grub_usb_bulk_read_extended (grub_usb_device_t dev, int endpoint, grub_size_t size, char *data, int timeout, grub_size_t *actual); +grub_usb_transfer_t +grub_usb_bulk_read_background (grub_usb_device_t dev, + int endpoint, grub_size_t size, void *data); +grub_usb_err_t +grub_usb_check_transfer (grub_usb_transfer_t trans, grub_size_t *actual); +void +grub_usb_cancel_transfer (grub_usb_transfer_t trans); #endif /* GRUB_USB_H */ diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h index a5bb2e8b2..5ee276d26 100644 --- a/include/grub/usbtrans.h +++ b/include/grub/usbtrans.h @@ -56,51 +56,89 @@ struct grub_usb_transfer grub_transaction_type_t type; + grub_transfer_type_t dir; + struct grub_usb_device *dev; struct grub_usb_transaction *transactions; int last_trans; /* Index of last processed transaction in OHCI/UHCI driver. */ + + void *controller_data; + + /* Used when finishing transfer to copy data back. */ + struct grub_pci_dma_chunk *data_chunk; + void *data; }; typedef struct grub_usb_transfer *grub_usb_transfer_t; -#define GRUB_USB_REQTYPE_IN (1 << 7) -#define GRUB_USB_REQTYPE_OUT (0 << 7) -#define GRUB_USB_REQTYPE_STANDARD (0 << 5) -#define GRUB_USB_REQTYPE_CLASS (1 << 5) -#define GRUB_USB_REQTYPE_VENDOR (2 << 5) -#define GRUB_USB_REQTYPE_TARGET_DEV (0 << 0) -#define GRUB_USB_REQTYPE_TARGET_INTERF (1 << 0) -#define GRUB_USB_REQTYPE_TARGET_ENDP (2 << 0) -#define GRUB_USB_REQTYPE_TARGET_OTHER (3 << 0) -#define GRUB_USB_REQ_GET_STATUS 0x00 -#define GRUB_USB_REQ_CLEAR_FEATURE 0x01 -#define GRUB_USB_REQ_SET_FEATURE 0x03 -#define GRUB_USB_REQ_SET_ADDRESS 0x05 -#define GRUB_USB_REQ_GET_DESCRIPTOR 0x06 -#define GRUB_USB_REQ_SET_DESCRIPTOR 0x07 -#define GRUB_USB_REQ_GET_CONFIGURATION 0x08 -#define GRUB_USB_REQ_SET_CONFIGURATION 0x09 -#define GRUB_USB_REQ_GET_INTERFACE 0x0A -#define GRUB_USB_REQ_SET_INTERFACE 0x0B -#define GRUB_USB_REQ_SYNC_FRAME 0x0C +enum + { + GRUB_USB_REQTYPE_TARGET_DEV = (0 << 0), + GRUB_USB_REQTYPE_TARGET_INTERF = (1 << 0), + GRUB_USB_REQTYPE_TARGET_ENDP = (2 << 0), + GRUB_USB_REQTYPE_TARGET_OTHER = (3 << 0), + GRUB_USB_REQTYPE_STANDARD = (0 << 5), + GRUB_USB_REQTYPE_CLASS = (1 << 5), + GRUB_USB_REQTYPE_VENDOR = (2 << 5), + GRUB_USB_REQTYPE_OUT = (0 << 7), + GRUB_USB_REQTYPE_IN = (1 << 7), + GRUB_USB_REQTYPE_CLASS_INTERFACE_OUT = GRUB_USB_REQTYPE_TARGET_INTERF + | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_OUT, + GRUB_USB_REQTYPE_VENDOR_OUT = GRUB_USB_REQTYPE_VENDOR | GRUB_USB_REQTYPE_OUT, + GRUB_USB_REQTYPE_CLASS_INTERFACE_IN = GRUB_USB_REQTYPE_TARGET_INTERF + | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_IN, + GRUB_USB_REQTYPE_VENDOR_IN = GRUB_USB_REQTYPE_VENDOR | GRUB_USB_REQTYPE_IN + }; + +enum + { + GRUB_USB_REQ_GET_STATUS = 0x00, + GRUB_USB_REQ_CLEAR_FEATURE = 0x01, + GRUB_USB_REQ_SET_FEATURE = 0x03, + GRUB_USB_REQ_SET_ADDRESS = 0x05, + GRUB_USB_REQ_GET_DESCRIPTOR = 0x06, + GRUB_USB_REQ_SET_DESCRIPTOR = 0x07, + GRUB_USB_REQ_GET_CONFIGURATION = 0x08, + GRUB_USB_REQ_SET_CONFIGURATION = 0x09, + GRUB_USB_REQ_GET_INTERFACE = 0x0A, + GRUB_USB_REQ_SET_INTERFACE = 0x0B, + GRUB_USB_REQ_SYNC_FRAME = 0x0C + }; #define GRUB_USB_FEATURE_ENDP_HALT 0x00 #define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01 #define GRUB_USB_FEATURE_TEST_MODE 0x02 -#define GRUB_USB_HUB_FEATURE_PORT_RESET 0x04 -#define GRUB_USB_HUB_FEATURE_PORT_POWER 0x08 -#define GRUB_USB_HUB_FEATURE_C_CONNECTED 0x10 +enum + { + GRUB_USB_HUB_FEATURE_PORT_RESET = 0x04, + GRUB_USB_HUB_FEATURE_PORT_POWER = 0x08, + GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED = 0x10, + GRUB_USB_HUB_FEATURE_C_PORT_ENABLED = 0x11, + GRUB_USB_HUB_FEATURE_C_PORT_SUSPEND = 0x12, + GRUB_USB_HUB_FEATURE_C_PORT_OVERCURRENT = 0x13, + GRUB_USB_HUB_FEATURE_C_PORT_RESET = 0x14 + }; -#define GRUB_USB_HUB_STATUS_CONNECTED (1 << 0) -#define GRUB_USB_HUB_STATUS_LOWSPEED (1 << 9) -#define GRUB_USB_HUB_STATUS_HIGHSPEED (1 << 10) -#define GRUB_USB_HUB_STATUS_C_CONNECTED (1 << 16) -#define GRUB_USB_HUB_STATUS_C_PORT_RESET (1 << 20) +enum + { + GRUB_USB_HUB_STATUS_PORT_CONNECTED = (1 << 0), + GRUB_USB_HUB_STATUS_PORT_ENABLED = (1 << 1), + GRUB_USB_HUB_STATUS_PORT_SUSPEND = (1 << 2), + GRUB_USB_HUB_STATUS_PORT_OVERCURRENT = (1 << 3), + GRUB_USB_HUB_STATUS_PORT_POWERED = (1 << 8), + GRUB_USB_HUB_STATUS_PORT_LOWSPEED = (1 << 9), + GRUB_USB_HUB_STATUS_PORT_HIGHSPEED = (1 << 10), + GRUB_USB_HUB_STATUS_C_PORT_CONNECTED = (1 << 16), + GRUB_USB_HUB_STATUS_C_PORT_ENABLED = (1 << 17), + GRUB_USB_HUB_STATUS_C_PORT_SUSPEND = (1 << 18), + GRUB_USB_HUB_STATUS_C_PORT_OVERCURRENT = (1 << 19), + GRUB_USB_HUB_STATUS_C_PORT_RESET = (1 << 20) + }; struct grub_usb_packet_setup { diff --git a/include/grub/video.h b/include/grub/video.h index 24167281f..5350d87eb 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -38,20 +38,33 @@ struct grub_video_bitmap; /* If following is set render target contains currenly displayed image after swapping buffers (otherwise it contains previously displayed image). */ -#define GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP 0x00000080 -#define GRUB_VIDEO_MODE_TYPE_PURE_TEXT 0x00000040 -#define GRUB_VIDEO_MODE_TYPE_ALPHA 0x00000020 -#define GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED 0x00000010 -#define GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP 0x00000004 -#define GRUB_VIDEO_MODE_TYPE_INDEX_COLOR 0x00000002 -#define GRUB_VIDEO_MODE_TYPE_RGB 0x00000001 +typedef enum grub_video_mode_type + { + GRUB_VIDEO_MODE_TYPE_RGB = 0x00000001, + GRUB_VIDEO_MODE_TYPE_INDEX_COLOR = 0x00000002, + GRUB_VIDEO_MODE_TYPE_1BIT_BITMAP = 0x00000004, + GRUB_VIDEO_MODE_TYPE_YUV = 0x00000008, -/* Defines used to mask flags. */ -#define GRUB_VIDEO_MODE_TYPE_COLOR_MASK 0x0000000F + /* Defines used to mask flags. */ + GRUB_VIDEO_MODE_TYPE_COLOR_MASK = 0x0000000F, -/* Defines used to specify requested bit depth. */ -#define GRUB_VIDEO_MODE_TYPE_DEPTH_MASK 0x0000ff00 -#define GRUB_VIDEO_MODE_TYPE_DEPTH_POS 8 + GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED = 0x00000010, + GRUB_VIDEO_MODE_TYPE_ALPHA = 0x00000020, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT = 0x00000040, + GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP = 0x00000080, + GRUB_VIDEO_MODE_TYPE_OPERATIONAL_MASK = 0x000000F0, + + /* Defines used to specify requested bit depth. */ + GRUB_VIDEO_MODE_TYPE_DEPTH_MASK = 0x0000FF00, +#define GRUB_VIDEO_MODE_TYPE_DEPTH_POS 8 + + GRUB_VIDEO_MODE_TYPE_UNKNOWN = 0x00010000, + GRUB_VIDEO_MODE_TYPE_HERCULES = 0x00020000, + GRUB_VIDEO_MODE_TYPE_PLANAR = 0x00040000, + GRUB_VIDEO_MODE_TYPE_NONCHAIN4 = 0x00080000, + GRUB_VIDEO_MODE_TYPE_CGA = 0x00100000, + GRUB_VIDEO_MODE_TYPE_INFO_MASK = 0x00FF0000, + } grub_video_mode_type_t; /* The basic render target representing the whole display. This always renders to the back buffer when double-buffering is in use. */ @@ -103,7 +116,7 @@ struct grub_video_mode_info /* Mode type bitmask. Contains information like is it Index color or RGB mode. */ - unsigned int mode_type; + grub_video_mode_type_t mode_type; /* Bits per pixel. */ unsigned int bpp; @@ -117,6 +130,9 @@ struct grub_video_mode_info /* In index color mode, number of colors. In RGB mode this is 256. */ unsigned int number_of_colors; + unsigned int mode_number; +#define GRUB_VIDEO_MODE_NUMBER_INVALID 0xffffffff + /* Optimization hint how binary data is coded. */ enum grub_video_blit_format blit_format; @@ -225,7 +241,8 @@ struct grub_video_adapter grub_err_t (*fini) (void); grub_err_t (*setup) (unsigned int width, unsigned int height, - unsigned int mode_type, unsigned int mode_mask); + grub_video_mode_type_t mode_type, + grub_video_mode_type_t mode_mask); grub_err_t (*get_info) (struct grub_video_mode_info *mode_info); @@ -282,6 +299,10 @@ struct grub_video_adapter grub_err_t (*set_active_render_target) (struct grub_video_render_target *target); grub_err_t (*get_active_render_target) (struct grub_video_render_target **target); + + int (*iterate) (int (*hook) (const struct grub_video_mode_info *info)); + + void (*print_adapter_specific_info) (void); }; typedef struct grub_video_adapter *grub_video_adapter_t; @@ -398,8 +419,9 @@ grub_err_t EXPORT_FUNC (grub_video_set_mode) (const char *modestring, unsigned int modevalue); static inline int -grub_video_check_mode_flag (unsigned int flags, unsigned int mask, - unsigned int flag, int def) +grub_video_check_mode_flag (grub_video_mode_type_t flags, + grub_video_mode_type_t mask, + grub_video_mode_type_t flag, int def) { return (flag & mask) ? !! (flags & flag) : def; } diff --git a/include/multiboot.h b/include/multiboot.h index fda863e85..ed71e6b96 100644 --- a/include/multiboot.h +++ b/include/multiboot.h @@ -254,6 +254,20 @@ struct multiboot_mod_list }; typedef struct multiboot_mod_list multiboot_module_t; +/* APM BIOS info. */ +struct multiboot_apm_info +{ + grub_uint16_t version; + grub_uint16_t cseg; + grub_uint32_t offset; + grub_uint16_t cseg_16; + grub_uint16_t dseg; + grub_uint16_t flags; + grub_uint16_t cseg_len; + grub_uint16_t cseg_16_len; + grub_uint16_t dseg_len; +}; + #endif /* ! ASM_FILE */ #endif /* ! MULTIBOOT_HEADER */ diff --git a/tests/grub_cmd_echo.in b/tests/grub_cmd_echo.in new file mode 100644 index 000000000..6ac33f55e --- /dev/null +++ b/tests/grub_cmd_echo.in @@ -0,0 +1,33 @@ +#! @builddir@/grub-shell-tester +# +# 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 . + +echo +echo -n + +echo foo +echo foo bar + +echo -n foo + +echo -e "foo\nbar" + +echo -n -e "foo\nbar" + +echo foo -n +echo foo -n -e + +echo ------- diff --git a/tests/grub_cmd_regexp.in b/tests/grub_cmd_regexp.in new file mode 100644 index 000000000..43b479fec --- /dev/null +++ b/tests/grub_cmd_regexp.in @@ -0,0 +1,41 @@ +#! /bin/bash -e + +# Run GRUB script in a Qemu instance +# 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 . + +cmd='regexp -s version "vm-(.*)" vm-1.2.3; echo $version' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != 1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 1:version "vm-(.*)" vm-1.2.3; echo $version' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != 1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 0:match "vm-(.*)" vm-1.2.3; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != vm-1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 2:match "vm-(.*)" vm-1.2.3; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test -n "$v"; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s match "\\\((.*)\\\)" (hd0,msdos1); echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != "hd0,msdos1"; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s match "hd([0-9]+)" hd0; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != "0"; then echo "error: $cmd" >&2; exit 1; fi diff --git a/tests/grub_script_blockarg.in b/tests/grub_script_blockarg.in new file mode 100644 index 000000000..783cee8e0 --- /dev/null +++ b/tests/grub_script_blockarg.in @@ -0,0 +1,41 @@ +#! /bin/bash + +# Run GRUB script in a Qemu instance +# 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 . + +error_if_not () { + if test "$1" != "$2"; then + echo "[$1]" != "[$2]" + exit 1 + fi +} + +cmd='test_blockarg { true }' +v=`echo "$cmd" | @builddir@/grub-shell` +error_if_not "$v" '{ true }' + +tmp=`mktemp` +cmd='test_blockarg { test_blockarg { true } }' +echo "$cmd" | @builddir@/grub-shell >$tmp +error_if_not "`head -n1 $tmp|tail -n1`" '{ test_blockarg { true } }' +error_if_not "`head -n2 $tmp|tail -n1`" '{ true }' + +cmd='test_blockarg { test_blockarg { test_blockarg { true } }; test_blockarg { true } }' +echo "$cmd" | @builddir@/grub-shell >$tmp +error_if_not "`head -n1 $tmp|tail -n1`" '{ test_blockarg { test_blockarg { true } }; test_blockarg { true } }' +error_if_not "`head -n2 $tmp|tail -n1`" '{ test_blockarg { true } }' +error_if_not "`head -n3 $tmp|tail -n1`" '{ true }' +error_if_not "`head -n4 $tmp|tail -n1`" '{ true }' diff --git a/tests/grub_script_echo1.in b/tests/grub_script_echo1.in index 554dd68ed..9415a3f73 100644 --- a/tests/grub_script_echo1.in +++ b/tests/grub_script_echo1.in @@ -57,3 +57,45 @@ e"$foo"${bar}o hello world foo=echo $foo 1234 + +echo "one +" +echo "one +\"" +echo "one +two" + +echo one"two +"three +echo one"two +\""three +echo one"two +\"three\" +four" + + +echo 'one +' +echo 'one +\' +echo 'one +two' +echo one'two +' +echo one'two +\' +echo one'two +\'three + +# echo "one\ +# two" +# echo 'one\ +# two' +# echo foo\ +# bar +# \ +# echo foo +# echo "one +# +# two" + diff --git a/tests/grub_script_expansion.in b/tests/grub_script_expansion.in new file mode 100644 index 000000000..d1e8d55c9 --- /dev/null +++ b/tests/grub_script_expansion.in @@ -0,0 +1,42 @@ +#! /bin/bash -e + +# Run GRUB script in a Qemu instance +# 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 . + +disks=`echo ls | @builddir@/grub-shell` +other=`echo insmod regexp\; echo \* | @builddir@/grub-shell` +for d in $disks; do + if echo "$d" |grep ',' >/dev/null; then + if echo "$other" | grep "$d" >/dev/null; then + echo "$d should not occur in * expansion" >&2 + exit 1 + fi + else + if ! echo "$other" | grep "$d" >/dev/null; then + echo "$d missing from * expansion" >&2 + exit 1 + fi + fi +done + +other=`echo insmod regexp\; echo '(*)' | @builddir@/grub-shell` +for d in $disks; do + if ! echo "$other" | grep "$d" >/dev/null; then + echo "$d missing from (*) expansion" >&2 + exit 1 + fi +done + diff --git a/tests/grub_script_not.in b/tests/grub_script_not.in new file mode 100644 index 000000000..ff71039a6 --- /dev/null +++ b/tests/grub_script_not.in @@ -0,0 +1,62 @@ +#! @builddir@/grub-shell-tester +# +# 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 . + +true +echo $? + +! true +echo $? + +false +echo $? + +! false +echo $? + +# +# Negated forms (copied from grub_script_if.in) +# + +#basic if, execute +if ! true; then echo yes; fi + +#basic if, no execution +if ! false; then echo no; fi + +#if else, execute if path +if ! true; then echo yes; else echo no; fi + +#if else, execute else path +if ! false; then echo no; else echo yes; fi + +#if elif, execute elif +if ! false; then echo no; elif ! true; then echo yes; fi + +#if elif else, execute else +if ! false; then echo no; elif ! false; then echo no; else echo yes; fi + +#if elif(1) elif(2), execute elif(2) +if false; then echo no; elif ! false; then echo no; elif ! true; then echo yes; fi + +#if elif(1) elif(2) else, execute else +if false; then echo no; elif false; then echo no; elif ! false; then echo no; else echo yes; fi + +#if {if elif else}, execute elif +if true; then if false; then echo no; elif ! true; then echo yes; else echo no; fi; fi + +#if {if elif} else, execute elif. ofcourse no dangling-else problem due to "fi" +if true; then if ! false; then echo no; elif true; then echo yes; fi; else echo no; fi diff --git a/tests/grub_script_return.in b/tests/grub_script_return.in new file mode 100644 index 000000000..712d1dfcf --- /dev/null +++ b/tests/grub_script_return.in @@ -0,0 +1,134 @@ +#! @builddir@/grub-shell-tester + +# Run GRUB script in a Qemu instance +# 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 . + +function f1 { + return + echo one +} +f1 + +function f2 { + true + return + echo one +} +if f2; then echo true; else echo false; fi + +function f3 { + false + return + echo one +} +if f3; then echo true; else echo false; fi + +function f4 { + true + return 1; + echo one +} +if f4; then echo true; else echo false; fi + +function f5 { + false + return 0; + echo one +} +if f5; then echo true; else echo false; fi + +function f6 { + echo one + if true; then + echo two + return 0 + else + echo three + return 1 + fi + echo four +} +if f6; then echo true; else echo false; fi + +function f7 { + if return 1; then + echo one + else + echo no + fi +} +if f7; then echo true; else echo false; fi + +function f8 { + echo one + for v in 1 2 3 4 5; do + echo $v + if test $v = 3; then return 1; fi + done + echo two +} +if f8; then echo true; else echo false; fi + +function f9 { + x=1 + echo one + until test x = 11111111; do + echo $x + x="1$x" + if test $x = 1111; then return 0; fi + done + echo two +} +if f9; then echo true; else echo false; fi + +function f10 { + echo one + while return 0; do + echo two + done + echo three +} +if f10; then echo true; else echo false; fi + +function f11 { + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 +} +if f11; then echo true; else echo false; fi + +function f12 { + echo one + f11 + return 1 + echo two +} +if f12; then echo true; else echo false; fi + +function f13 { + echo one + f12 + echo two + return 0 +} +if f13; then echo true; else echo false; fi diff --git a/tests/grub_script_setparams.in b/tests/grub_script_setparams.in new file mode 100644 index 000000000..82d316813 --- /dev/null +++ b/tests/grub_script_setparams.in @@ -0,0 +1,59 @@ +#! @builddir@/grub-shell-tester + +# Run GRUB script in a Qemu instance +# 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 . + +if test x$grubshell = xyes; then cmd=setparams; else cmd=set; fi + +function f1 { + echo $# + echo "$#" + + echo $@ + echo "$@" + + echo $* + echo "$*" + + echo $1 $2 + for v in "$@"; do echo $v; done + shift + echo $1 $2 + for v in "$@"; do echo $v; done + + $cmd 1 2 3 4 + + echo $# + echo "$#" + + echo $@ + echo "$@" + + echo $* + echo "$*" + + echo $1 $2 + for v in "$@"; do echo $v; done + shift + echo $1 $2 + for v in "$@"; do echo $v; done +} +# f1 +# f1 a +f1 a b +f1 a b c +f1 a b c d +f1 a b c d e diff --git a/tests/partmap_test.in b/tests/partmap_test.in new file mode 100644 index 000000000..14897e9da --- /dev/null +++ b/tests/partmap_test.in @@ -0,0 +1,274 @@ +#! /bin/sh -e +# +# 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 . + +parted=/sbin/parted +grubshell=@builddir@/grub-shell + +create_disk_image () { + name=$1 + size=$2 + qemu-img create ${name} ${size} >/dev/null +} + +check_output () { + outfile=$1 + shift + + for disk in $@; do + if ! grep "($disk)" ${outfile} >/dev/null + then + echo "($disk): disk/partiton not found" + exit 1 + fi + done +} + +list_parts () { + mod=$1; + shift; + imgfile=$1 + shift + outfile=$1 + shift + + echo ls | ${grubshell} --boot=cd --qemu-opts="-hda ${imgfile}" \ + --modules=$mod | tr -d "\n\r" > ${outfile} + cat ${outfile} + echo +} + +imgfile=`mktemp` +outfile=`mktemp` + +# +# MSDOS partition types +# + +echo "Checking MSDOS partition types..." + +# 0 primary +create_disk_image ${imgfile} 64M +${parted} -a none -s ${imgfile} mklabel msdos +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 + +# 1 primary +create_disk_image ${imgfile} 64M +${parted} -a none -s ${imgfile} mklabel msdos mkpart primary 0 10M +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,msdos1 + +# 2 primary +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel msdos mkpart primary 0 10M mkpart primary 10M 20M +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,msdos1 hd0,msdos2 + +# 3 primary +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel msdos mkpart primary 0 10M mkpart primary 10M 20M mkpart primary 20M 30M +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,msdos1 hd0,msdos2 hd0,msdos3 + +# 4 primary +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel msdos mkpart primary 0 10M mkpart primary 10M 20M mkpart primary 20M 30M mkpart primary 30M 40M +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,msdos1 hd0,msdos2 hd0,msdos3 hd0,msdos4 + +# 1 primary, 1 extended +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel msdos mkpart primary 0 10M mkpart primary 10M 20M mkpart extended 20M 100% +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,msdos1 + +# 1 primary, 1 extended, 1 logical +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel msdos mkpart primary 0 10M mkpart primary 10M 20M mkpart extended 20M 100% mkpart logical 20M 30M +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,msdos1 hd0,msdos5 + +# 1 primary, 1 extended, 2 logical +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel msdos mkpart primary 0 10M mkpart primary 10M 20M mkpart extended 20M 100% mkpart logical 20M 30M mkpart logical 30M 40M +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,msdos1 hd0,msdos5 hd0,msdos6 + +# 1 primary, 1 extended, 3 logical +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel msdos mkpart primary 0 10M mkpart primary 10M 20M mkpart extended 20M 100% mkpart logical 20M 30M mkpart logical 30M 40M mkpart logical 40M 50M +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,msdos1 hd0,msdos5 hd0,msdos6 hd0,msdos7 + +# 1 primary, 1 extended, 4 logical +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel msdos mkpart primary 0 10M mkpart primary 10M 20M mkpart extended 20M 100% mkpart logical 20M 30M mkpart logical 30M 40M mkpart logical 40M 50M mkpart logical 50M 60M +list_parts part_msdos ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,msdos1 hd0,msdos5 hd0,msdos6 hd0,msdos7 hd0,msdos8 + + +# +# GPT partition types +# + +echo "Checking GPT partition types..." + +# 0 parts +create_disk_image ${imgfile} 64M +${parted} -a none -s ${imgfile} mklabel gpt +list_parts part_gpt ${imgfile} ${outfile} +check_output ${outfile} hd0 + +# 1 parts +create_disk_image ${imgfile} 64M +${parted} -a none -s ${imgfile} mklabel gpt mkpart 1 0 10M +list_parts part_gpt ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,gpt1 + +# 2 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel gpt mkpart 1 0 10M mkpart 2 10M 20M +list_parts part_gpt ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,gpt1 hd0,gpt2 + +# 3 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel gpt mkpart 1 0 10M mkpart 2 10M 20M mkpart 3 20M 30M +list_parts part_gpt ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,gpt1 hd0,gpt2 hd0,gpt3 + +# 4 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel gpt mkpart 1 0 10M mkpart 2 10M 20M mkpart 4 20M 30M mkpart 5 30M 40M +list_parts part_gpt ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,gpt1 hd0,gpt2 hd0,gpt3 hd0,gpt4 + +# 5 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel gpt mkpart 1 0 10M mkpart 2 10M 20M mkpart 3 20M 30M mkpart 4 30M 40M mkpart 5 40M 50M +list_parts part_gpt ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,gpt1 hd0,gpt2 hd0,gpt3 hd0,gpt4 hd0,gpt5 + +# 6 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel gpt mkpart 1 0 10M mkpart 2 10M 20M mkpart 3 20M 30M mkpart 4 30M 40M mkpart 5 40M 50M mkpart 6 50M 60M +list_parts part_gpt ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,gpt1 hd0,gpt2 hd0,gpt3 hd0,gpt4 hd0,gpt5 hd0,gpt6 + + +# +# SUN partition types +# +# It seems partition #3 is reserved for whole disk by parted. +# + +echo "Checking SUN partition types..." + +# 0 parts +create_disk_image ${imgfile} 64M +${parted} -a none -s ${imgfile} mklabel sun +list_parts part_sun ${imgfile} ${outfile} +check_output ${outfile} hd0 + +# 1 parts +create_disk_image ${imgfile} 64M +${parted} -a none -s ${imgfile} mklabel sun mkpart 0 10M +list_parts part_sun ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,sun1 + +# 2 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel sun mkpart 0 10M mkpart 10M 20M +list_parts part_sun ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,sun1 hd0,sun2 + +# 3 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel sun mkpart 0 10M mkpart 10M 20M mkpart 20M 30M +list_parts part_sun ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,sun1 hd0,sun2 hd0,sun4 + +# 4 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel sun mkpart 0 10M mkpart 10M 20M mkpart 20M 30M mkpart 30M 40M +list_parts part_sun ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,sun1 hd0,sun2 hd0,sun4 hd0,sun5 + +# 5 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel sun mkpart 0 10M mkpart 10M 20M mkpart 20M 30M mkpart 30M 40M mkpart 40M 50M +list_parts part_sun ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,sun1 hd0,sun2 hd0,sun4 hd0,sun5 hd0,sun6 + +# 6 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel sun mkpart 0 10M mkpart 10M 20M mkpart 20M 30M mkpart 30M 40M mkpart 40M 50M mkpart 50M 60M +list_parts part_sun ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,sun1 hd0,sun2 hd0,sun4 hd0,sun5 hd0,sun6 hd0,sun7 + + +# +# Apple partition types +# +# Partition table itself is part of some partition, so there is always +# a partition by default. But I don't understand why GRUB displays +# two partitions by default :-( +# + +echo "Checking APPLE partition types..." + +# 0 parts +create_disk_image ${imgfile} 64M +${parted} -a none -s ${imgfile} mklabel mac +list_parts part_apple ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,apple1 hd0,apple2 + +# 1 parts +create_disk_image ${imgfile} 64M +${parted} -a none -s ${imgfile} mklabel mac mkpart a 1M 10M +list_parts part_apple ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,apple1 hd0,apple2 hd0,apple3 + +# 2 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel mac mkpart a 1M 10M mkpart b 10M 20M +list_parts part_apple ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,apple1 hd0,apple2 hd0,apple3 hd0,apple4 + +# 3 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel mac mkpart a 1M 10M mkpart b 10M 20M mkpart c 20M 30M +list_parts part_apple ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,apple1 hd0,apple2 hd0,apple4 hd0,apple5 + +# 4 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel mac mkpart a 1M 10M mkpart b 10M 20M mkpart c 20M 30M mkpart d 30M 40M +list_parts part_apple ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,apple1 hd0,apple2 hd0,apple4 hd0,apple5 hd0,apple6 + +# 5 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel mac mkpart a 1M 10M mkpart b 10M 20M mkpart c 20M 30M mkpart d 30M 40M mkpart e 40M 50M +list_parts part_apple ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,apple1 hd0,apple2 hd0,apple4 hd0,apple5 hd0,apple6 hd0,apple7 + +# 6 parts +create_disk_image ${imgfile} 128M +${parted} -a none -s ${imgfile} mklabel mac mkpart a 1M 10M mkpart b 10M 20M mkpart c 20M 30M mkpart d 30M 40M mkpart e 40M 50M mkpart f 50M 60M +list_parts part_apple ${imgfile} ${outfile} +check_output ${outfile} hd0 hd0,apple1 hd0,apple2 hd0,apple4 hd0,apple5 hd0,apple6 hd0,apple7 hd0,apple8 diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in index e21cc95f4..c8247d29d 100644 --- a/tests/util/grub-shell.in +++ b/tests/util/grub-shell.in @@ -28,6 +28,7 @@ PACKAGE_NAME=@PACKAGE_NAME@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ target_cpu=@target_cpu@ +platform=@platform@ # Force build directory components PATH=${builddir}:$PATH @@ -42,7 +43,7 @@ Run GRUB script in a Qemu instance. -h, --help print this message and exit -v, --version print the version information and exit - --boot=[fd|hd|cd] boot method for Qemu instance + --boot=[fd|hd|cd|net] boot method for Qemu instance --modules=MODULES pre-load specified modules MODULES --qemu=FILE Name of qemu binary --qemu-opts=OPTIONS extra options to pass to Qemu instance @@ -83,6 +84,7 @@ for option in "$@"; do if [ "$dev" = "fd" ] ; then boot=fd; elif [ "$dev" = "hd" ] ; then boot=hd; elif [ "$dev" = "cd" ] ; then boot=cd; + elif [ "$dev" = "net" ] ; then boot=net; elif [ "$dev" = "qemu" ] ; then boot=qemu; elif [ "$dev" = "coreboot" ] ; then boot=coreboot; else @@ -107,7 +109,7 @@ done if [ "x${source}" = x ] ; then tmpfile=`mktemp` while read REPLY; do - echo $REPLY >> ${tmpfile} + echo "$REPLY" >> ${tmpfile} done source=${tmpfile} fi @@ -134,10 +136,12 @@ halt EOF isofile=`mktemp` -sh @builddir@/grub-mkrescue --grub-mkimage=${builddir}/grub-mkimage --output=${isofile} --override-directory=${builddir}/grub-core \ - --rom-directory="${rom_directory}" \ - /boot/grub/grub.cfg=${cfgfile} /boot/grub/testcase.cfg=${source} \ - ${files} >/dev/null 2>&1 +if [ x$boot != xnet ]; then + sh @builddir@/grub-mkrescue --grub-mkimage=${builddir}/grub-mkimage --output=${isofile} --override-directory=${builddir}/grub-core \ + --rom-directory="${rom_directory}" \ + /boot/grub/grub.cfg=${cfgfile} /boot/grub/testcase.cfg=${source} \ + ${files} >/dev/null 2>&1 +fi if [ x$boot = xhd ]; then device=hda bootdev="-boot c" @@ -164,7 +168,15 @@ if [ x$boot = xcoreboot ]; then device=cdrom fi -${qemu} ${qemuopts} -nographic -serial file:/dev/stdout -monitor file:/dev/null -${device} ${isofile} ${bootdev} | cat | tr -d "\r" +if [ x$boot = xnet ]; then + netdir=`mktemp -d` + sh @builddir@/grub-mknetdir --grub-mkimage=${builddir}/grub-mkimage --override-directory=${builddir}/grub-core --net-directory=$netdir + cp ${cfgfile} $netdir/boot/grub/grub.cfg + cp ${source} $netdir/boot/grub/testcase.cfg + ${qemu} ${qemuopts} -nographic -serial file:/dev/stdout -monitor file:/dev/null -boot n -net user,tftp=$netdir,bootfile=/boot/grub/$target_cpu-$platform/core.0 -net nic | cat | tr -d "\r" +else + ${qemu} ${qemuopts} -nographic -serial file:/dev/stdout -monitor file:/dev/null -${device} ${isofile} ${bootdev} | cat | tr -d "\r" +fi rm -f "${isofile}" "${imgfile}" rm -rf "${rom_directory}" if [ x$boot = xcoreboot ]; then diff --git a/util/bash-completion.d/Makefile.am b/util/bash-completion.d/Makefile.am new file mode 100644 index 000000000..136287cf1 --- /dev/null +++ b/util/bash-completion.d/Makefile.am @@ -0,0 +1,13 @@ + +bash_completion_source = grub-completion.bash.in +bash_completion_script = grub + +EXTRA_DIST = $(bash_completion_source) + +CLEANFILES = $(bash_completion_script) config.log + +bashcompletiondir = $(sysconfdir)/bash_completion.d +bashcompletion_DATA = $(bash_completion_script) + +$(bash_completion_script): $(bash_completion_source) $(top_builddir)/config.status + $(top_builddir)/config.status --file=$@:$< diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in new file mode 100644 index 000000000..65cbb80ee --- /dev/null +++ b/util/bash-completion.d/grub-completion.bash.in @@ -0,0 +1,489 @@ +# +# Bash completion for grub +# +# 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 . +# bash completion for grub + +__grub_dir() { + local i c=1 boot_dir + + for (( c=1; c <= ${#COMP_WORDS[@]}; c++ )); do + i="${COMP_WORDS[c]}" + case "$i" in + --boot-directory) + c=$((++c)) + i="${COMP_WORDS[c]}" + boot_dir="${i##*=}"; + break + ;; + esac + done + boot_dir=${boot_dir-/@bootdirname@} + echo "${boot_dir%/}/@grubdirname@" +} + + +# This function generates completion reply with compgen +# - arg: accepts 1, 2, 3, or 4 arguments +# $1 wordlist separate by space, tab or newline +# $2 (optional) prefix to add +# $3 (optional) current word to complete +# $4 (optional) suffix to add +__grubcomp () { + local cur="${COMP_WORDS[COMP_CWORD]}" + if [ $# -gt 2 ]; then + cur="$3" + fi + case "$cur" in + --*=) + COMPREPLY=() + ;; + *) + local IFS=' '$'\t'$'\n' + COMPREPLY=($(compgen -P "${2-}" -W "${1-}" -S "${4-}" -- "$cur")) + ;; + esac +} + +# Function that return long options from the help of the command +# - arg: $1 (optional) command to get the long options from +__grub_get_options_from_help () { + local prog + + if [ $# -ge 1 ]; then + prog="$1" + else + prog="${COMP_WORDS[0]}" + fi + + local i IFS=" "$'\t'$'\n' + for i in $(LC_ALL=C $prog --help) + do + case $i in + --*) echo "${i%=*}";; + esac + done +} + +# Function that return long options from the usage of the command +# - arg: $1 (optional) command to get the long options from +__grub_get_options_from_usage () { + local prog + + if [ $# -ge 1 ]; then + prog="$1" + else + prog="${COMP_WORDS[0]}" + fi + + local i IFS=" "$'\t'$'\n' + for i in $(LC_ALL=C $prog --usage) + do + case $i in + \[--*\]) i=${i#[} # Remove leading [ + echo ${i%%?(=*)]} # Remove optional value and trailing ] + ;; + esac + done +} + +__grub_get_last_option () { + local i + for (( i=$COMP_CWORD-1; i > 0; i-- )); do + if [[ "${COMP_WORDS[i]}" == -* ]]; then + echo "${COMP_WORDS[i]}" + break; + fi + done +} + +__grub_list_menuentries () { + local cur="${COMP_WORDS[COMP_CWORD]}" + local config_file=$(__grub_dir)/grub.cfg + + if [ -f "$config_file" ];then + local IFS=$'\n' + COMPREPLY=( $(compgen \ + -W "$( awk -F "[\"']" '/menuentry/ { print $2 }' $config_file )" \ + -- "$cur" )) #'# Help emacs syntax highlighting + fi +} + +__grub_list_modules () { + local grub_dir=$(__grub_dir) + local IFS=$'\n' + COMPREPLY=( $( compgen -f -X '!*/*.mod' -- "${grub_dir}/$cur" | { + while read -r tmp; do + [ -n $tmp ] && { + tmp=${tmp##*/} + printf '%s\n' ${tmp%.mod} + } + done + } + )) +} + +# +# grub-set-default & grub-reboot +# +_grub_set_entry () { + local cur prev split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + _split_longopt && split=true + + case "$prev" in + --boot-directory) + _filedir -d + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a menuentry + __grub_list_menuentries + fi +} + +__grub_set_default_program=$( echo grub-set-default | sed "@program_transform_name@" ) +have ${__grub_set_default_program} && \ + complete -F _grub_set_entry -o filenames ${__grub_set_default_program} +unset __grub_set_default_program + +__grub_reboot_program=$( echo grub-reboot | sed "@program_transform_name@" ) +have ${__grub_reboot_program} && \ + complete -F _grub_set_entry -o filenames ${__grub_reboot_program} +unset __grub_reboot_program + + +# +# grub-editenv +# +_grub_editenv () { + local cur prev + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + case "$prev" in + create|list|set|unset) + COMPREPLY=( "" ) + return + ;; + esac + + __grubcomp "$(__grub_get_options_from_help) + create list set unset" +} + +__grub_editenv_program=$( echo grub-editenv | sed "@program_transform_name@" ) +have ${__grub_editenv_program} && \ + complete -F _grub_editenv -o filenames ${__grub_editenv_program} +unset __grub_editenv_program + + +# +# grub-mkconfig +# +_grub_mkconfig () { + local cur prev + + COMPREPLY=() + cur=`_get_cword` + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + _filedir + fi +} +__grub_mkconfig_program=$( echo grub-mkconfig | sed "@program_transform_name@" ) +have ${__grub_mkconfig_program} && \ + complete -F _grub_mkconfig -o filenames ${__grub_mkconfig_program} +unset __grub_mkconfig_program + + +# +# grub-setup +# +_grub_setup () { + local cur prev split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + _split_longopt && split=true + + case "$prev" in + -d|--directory) + _filedir -d + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_setup_program=$( echo grub-setup | sed "@program_transform_name@" ) +have ${__grub_setup_program} && \ + complete -F _grub_setup -o filenames ${__grub_setup_program} +unset __grub_setup_program + + +# +# grub-install +# +_grub_install () { + local cur prev last split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + last=$(__grub_get_last_option) + + _split_longopt && split=true + + case "$prev" in + --boot-directory) + _filedir -d + return + ;; + --disk-module) + __grubcomp "biosdisk ata" + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + case "$last" in + --modules) + __grub_list_modules + return + ;; + esac + + # Default complete with a filename + _filedir + fi +} +__grub_install_program=$( echo grub-install | sed "@program_transform_name@" ) +have ${__grub_install_program} && \ + complete -F _grub_install -o filenames ${__grub_install_program} +unset __grub_install_program + + +# +# grub-mkfont +# +_grub_mkfont () { + local cur + + COMPREPLY=() + cur=`_get_cword` + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_mkfont_program=$( echo grub-mkfont | sed "@program_transform_name@" ) +have ${__grub_mkfont_program} && \ + complete -F _grub_mkfont -o filenames ${__grub_mkfont_program} +unset __grub_mkfont_program + + +# +# grub-mkrescue +# +_grub_mkrescue () { + local cur prev last + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + last=$(__grub_get_last_option) + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + case "$last" in + --modules) + __grub_list_modules + return + ;; + esac + + # Default complete with a filename + _filedir + fi +} +__grub_mkrescue_program=$( echo grub-mkrescue | sed "@program_transform_name@" ) +have ${__grub_mkrescue_program} && \ + complete -F _grub_mkrescue -o filenames ${__grub_mkrescue_program} +unset __grub_mkrescue_program + + +# +# grub-mkimage +# +_grub_mkimage () { + local cur prev split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + _split_longopt && split=true + + case "$prev" in + -d|--directory|-p|--prefix) + _filedir -d + return + ;; + -O|--format) + # Get available format from help + local prog=${COMP_WORDS[0]} + __grubcomp "$(LC_ALL=C $prog --help | \ + awk -F ":" '/available formats/ { print $2 }' | \ + sed 's/, / /g')" + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_mkimage_program=$( echo grub-mkimage | sed "@program_transform_name@" ) +have ${__grub_mkimage_program} && \ + complete -F _grub_mkimage -o filenames ${__grub_mkimage_program} +unset __grub_mkimage_program + + +# +# grub-mkpasswd-pbkdf2 +# +_grub_mkpasswd-pbkdf2 () { + local cur + + COMPREPLY=() + cur=`_get_cword` + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_mkpasswd_pbkdf2_program=$( echo grub-mkpasswd-pbkdf2 | sed "@program_transform_name@" ) +have ${__grub_mkpasswd_pbkdf2_program} && \ + complete -F _grub_mkpasswd-pbkdf2 -o filenames ${__grub_mkpasswd_pbkdf2_program} +unset __grub_mkpasswd_pbkdf2_program + + +# +# grub-probe +# +_grub_probe () { + local cur prev split=false + + COMPREPLY=() + cur=`_get_cword` + prev=${COMP_WORDS[COMP_CWORD-1]} + + _split_longopt && split=true + + case "$prev" in + -t|--target) + # Get target type from help + local prog=${COMP_WORDS[0]} + __grubcomp "$(LC_ALL=C $prog --help | \ + awk -F "[()]" '/--target=/ { print $2 }' | \ + sed 's/|/ /g')" + return + ;; + esac + + $split && return 0 + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_probe_program=$( echo grub-probe | sed "@program_transform_name@" ) +have ${__grub_probe_program} && \ + complete -F _grub_probe -o filenames ${__grub_probe_program} +unset __grub_probe_program + + +# +# grub-script-check +# +_grub_script-check () { + local cur + + COMPREPLY=() + cur=`_get_cword` + + if [[ "$cur" == -* ]]; then + __grubcomp "$(__grub_get_options_from_help)" + else + # Default complete with a filename + _filedir + fi +} +__grub_script_check_program=$( echo grub-script-check | sed "@program_transform_name@" ) +have ${__grub_script_check_program} && \ + complete -F _grub_script-check -o filenames ${__grub_script_check_program} + + +# Local variables: +# mode: shell-script +# sh-basic-offset: 4 +# sh-indent-comment: t +# indent-tabs-mode: nil +# End: +# ex: ts=4 sw=4 et filetype=sh diff --git a/util/grub-fstest.c b/util/grub-fstest.c index 48fcbc57f..bcc9ea942 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include @@ -107,6 +107,7 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) return; } + grub_file_filter_disable_compression (); file = grub_file_open (pathname); if (!file) { @@ -238,19 +239,22 @@ cmd_hex (char *pathname) static void cmd_crc (char *pathname) { - grub_uint32_t crc = 0; + grub_uint8_t crc32_context[GRUB_MD_CRC32->contextsize]; + GRUB_MD_CRC32->init(crc32_context); auto int crc_hook (grub_off_t ofs, char *buf, int len); int crc_hook (grub_off_t ofs, char *buf, int len) { (void) ofs; - crc = grub_getcrc32 (crc, buf, len); + GRUB_MD_CRC32->write(crc32_context, buf, len); return 0; } read_file (pathname, crc_hook); - printf ("%08x\n", crc); + GRUB_MD_CRC32->final(crc32_context); + printf ("%08x\n", + grub_be_to_cpu32(*(grub_uint32_t*)GRUB_MD_CRC32->read(crc32_context))); } static void @@ -258,13 +262,11 @@ fstest (char **images, int num_disks, int cmd, int n, char **args) { char *host_file; char *loop_name; - char *argv[3]; int i; - argv[0] = "-p"; - for (i = 0; i < num_disks; i++) { + char *argv[2]; loop_name = grub_xasprintf ("loop%d", i); if (!loop_name) grub_util_error (grub_errmsg); @@ -273,10 +275,10 @@ fstest (char **images, int num_disks, int cmd, int n, char **args) if (!host_file) grub_util_error (grub_errmsg); - argv[1] = loop_name; - argv[2] = host_file; + argv[0] = loop_name; + argv[1] = host_file; - if (execute_command ("loopback", 3, argv)) + if (execute_command ("loopback", 2, argv)) grub_util_error ("loopback command fails"); grub_free (loop_name); @@ -311,15 +313,16 @@ fstest (char **images, int num_disks, int cmd, int n, char **args) execute_command ("blocklist", n, args); grub_printf ("\n"); } - - argv[0] = "-d"; - + for (i = 0; i < num_disks; i++) { + char *argv[2]; + loop_name = grub_xasprintf ("loop%d", i); if (!loop_name) grub_util_error (grub_errmsg); + argv[0] = "-d"; argv[1] = loop_name; execute_command ("loopback", 2, argv); diff --git a/util/grub-install.in b/util/grub-install.in index e6521f069..955bf0257 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -24,6 +24,7 @@ exec_prefix=@exec_prefix@ sbindir=@sbindir@ bindir=@bindir@ libdir=@libdir@ +sysconfdir=@sysconfdir@ PACKAGE_NAME=@PACKAGE_NAME@ PACKAGE_TARNAME=@PACKAGE_TARNAME@ PACKAGE_VERSION=@PACKAGE_VERSION@ @@ -40,8 +41,10 @@ grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` +grub_mkrelpath=${bindir}/`echo grub-mkrelpath | sed ${transform}` rootdir= -grub_prefix=`echo /boot/grub | sed ${transform}` +bootdir= +grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` modules= install_device= @@ -51,9 +54,27 @@ recheck=no debug=no debug_image= +update_nvram=yes + +ofpathname=`which ofpathname` +nvsetenv=`which nvsetenv` +efibootmgr=`which efibootmgr 2>/dev/null || true` +removable=no +efi_quiet= + +# Get GRUB_DISTRIBUTOR. +if test -f ${sysconfdir}/default/grub ; then + . ${sysconfdir}/default/grub +fi + +bootloader_id="$(echo "$GRUB_DISTRIBUTOR" | tr '[A-Z]' '[a-z]' | cut -d' ' -f1)" +if test -z "$bootloader_id"; then + bootloader_id=grub +fi + if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then disk_module=biosdisk -elif [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then +elif [ "${platform}" = "ieee1275" ] || [ "${platform}" = "efi" ] ; then disk_module= else disk_module=ata @@ -62,17 +83,27 @@ fi # Usage: usage # Print the usage. usage () { +if [ "${target_cpu}-${platform}" = "i386-pc" ] \ + || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ]; then cat <. EOF @@ -134,21 +173,37 @@ do --font=*) ;; +# Accept for compatibility --root-directory) rootdir=`argument $option "$@"`; shift;; --root-directory=*) rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; + --boot-directory) + bootdir=`argument $option "$@"`; shift;; + --boot-directory=*) + bootdir=`echo "$option" | sed 's/--boot-directory=//'` ;; + --grub-setup) grub_setup=`argument $option "$@"`; shift;; --grub-setup=*) grub_setup=`echo "$option" | sed 's/--grub-setup=//'` ;; + --bootloader-id) + bootloader_id=`argument $option "$@"`; shift;; + --bootloader_id=*) + bootloader_id=`echo "$option" | sed 's/--bootloader_id=//'` ;; + --grub-mkimage) grub_mkimage=`argument $option "$@"`; shift;; --grub-mkimage=*) grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; + --grub-mkrelpath) + grub_mkrelpath=`argument $option "$@"`; shift;; + --grub-mkimage=*) + grub_mkrelpath=`echo "$option" | sed 's/--grub-mkrelpath=//'` ;; + --grub-mkdevicemap) grub_mkdevicemap=`argument $option "$@"`; shift;; --grub-mkdevicemap=*) @@ -163,6 +218,8 @@ do no_floppy="--no-floppy" ;; --recheck) recheck=yes ;; + --removable) + removable=yes ;; --disk-module) if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then @@ -173,6 +230,9 @@ do disk_module=`echo "$option" | sed 's/--disk-module=//'` fi ;; + --no-nvram) + update_nvram=no ;; + # This is an undocumented feature... --debug) debug=yes ;; @@ -202,7 +262,8 @@ done # for make_system_path_relative_to_its_root() . ${libdir}/grub/grub-mkconfig_lib -if test "x$install_device" = x && test "${target_cpu}-${platform}" != "mips-yeeloong"; then +if test "x$install_device" = x && ([ "${target_cpu}-${platform}" = "i386-pc" ] \ + || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ]); then echo "install_device not specified." 1>&2 usage exit 1 @@ -213,25 +274,21 @@ setup_verbose= if test $debug = yes; then set -x setup_verbose="--verbose" + efi_quiet=-q fi -# Initialize these directories here, since ROOTDIR was initialized. -case "$host_os" in -netbsd* | openbsd*) - # Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub - # instead of /boot/grub. - grub_prefix=`echo /grub | sed ${transform}` - bootdir=${rootdir} - ;; -*) - # Use /boot/grub by default. - bootdir=${rootdir}/boot - ;; -esac +if [ -z "$bootdir" ]; then + # Default bootdir if bootdir not initialized. + bootdir=/@bootdirname@ -grubdir=${bootdir}/`echo grub | sed ${transform}` + if [ -n "$rootdir" ] ; then + # Initialize bootdir if rootdir was initialized. + bootdir=${rootdir}/@bootdirname@ + fi +fi + +grubdir=`echo "${bootdir}/@grubdirname@" | sed 's,//*,/,g'` device_map=${grubdir}/device.map - grub_probe="${grub_probe} --device-map=${device_map}" # Check if GRUB is installed. @@ -261,6 +318,87 @@ else exit 1 fi +if [ x"$platform" = xefi ]; then + # Find the EFI System Partition. + efidir= + if test -d ${bootdir}/efi; then + install_device=`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${bootdir}/efi` + # Is it a mount point? + if test "x$install_device" != "x`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${bootdir}`"; then + efidir=${bootdir}/efi + fi + elif test -n "$rootdir" && test "x$rootdir" != "x/"; then + # The EFI System Partition may have been given directly using + # --root-directory. + install_device=`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${rootdir}` + # Is it a mount point? + if test "x$install_device" != "x`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${rootdir}/..`"; then + efidir=${rootdir} + fi + fi + + if test -n "$efidir"; then + efi_fs=`$grub_probe --target=fs --device-map=${device_map} ${efidir}` + if test "x$efi_fs" = xfat; then :; else + echo "${efidir} doesn't look like an EFI partition." 1>&2 + efidir= + fi + fi + + if test -n "$efidir"; then + # The EFI specification requires that an EFI System Partition must + # contain an "EFI" subdirectory, and that OS loaders are stored in + # subdirectories below EFI. Vendors are expected to pick names that do + # not collide with other vendors. To minimise collisions, we use the + # name of our distributor if possible. + efi_distributor="$bootloader_id" + if test $removable = yes; then + # The specification makes stricter requirements of removable + # devices, in order that only one image can be automatically loaded + # from them. The image must always reside under /EFI/BOOT, and it + # must have a specific file name depending on the architecture. + efi_distributor=BOOT + case "$target_cpu" in + i386) + efi_file=BOOTIA32.EFI ;; + x86-64) + efi_file=BOOTX64.EFI ;; + # GRUB does not yet support these architectures, but they're defined + # by the specification so we include them here to ease future + # expansion. + ia64) + efi_file=BOOTIA64.EFI ;; + esac + else + # It is convenient for each architecture to have a different + # efi_file, so that different versions can be installed in parallel. + case "$target_cpu" in + i386) + efi_file=grubia32.efi ;; + x86-64) + efi_file=grubx64.efi ;; + # GRUB does not yet support these architectures, but they're defined + # by the specification so we include them here to ease future + # expansion. + ia64) + efi_file=grubia64.efi ;; + *) + efi_file=grub.efi ;; + esac + # TODO: We should also use efibootmgr, if available, to add a Boot + # entry for ourselves. + fi + efidir="$efidir/EFI/$efi_distributor" + mkdir -p "$efidir" || exit 1 + else + # We don't know what's going on. Fall back to traditional + # (non-specification-compliant) behaviour. + efidir="$grubdir" + efi_distributor= + efi_file=grub.efi + fi +fi + # Create the GRUB directory if it is not present. mkdir -p "$grubdir" || exit 1 @@ -369,6 +507,7 @@ if [ "x${devabstraction_module}" = "x" ] ; then grub_drive="`$grub_probe --target=drive --device ${grub_device}`" || exit 1 # Strip partition number + grub_partition="`echo ${grub_drive} | sed -e 's/^[^,]*,//; s/)$//'`" grub_drive="`echo ${grub_drive} | sed -e s/,[a-z0-9,]*//g`" if [ "$disk_module" = ata ] ; then # generic method (used on coreboot and ata mod) @@ -391,28 +530,113 @@ if [ "x${devabstraction_module}" = "x" ] ; then echo 'set prefix=($root)'"${relative_grubdir}" >> ${grubdir}/load.cfg config_opt="-c ${grubdir}/load.cfg " modules="$modules search_fs_uuid" + elif [ "x$platform" = xefi ] || [ "x$platform" = xpc ]; then + # we need to hardcode the partition number in the core image's prefix. + prefix_drive="(,$grub_partition)" fi else prefix_drive=`$grub_probe --target=drive --device ${grub_device}` || exit 1 fi case "${target_cpu}-${platform}" in - i386-pc) mkimage_target=i386-pc ;; sparc64-ieee1275) mkimage_target=sparc64-ieee1275-raw ;; mips-yeeloong) mkimage_target=mipsel-yeeloong-elf ;; - *) mkimage_target=i386-coreboot; + *) mkimage_target="${target_cpu}-${platform}" ;; esac -if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then - $grub_mkimage ${config_opt} -O ${mkimage_target} --output=${grubdir}/core.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 +case "${target_cpu}-${platform}" in + i386-efi | x86_64-efi) imgext=efi ;; + mips-yeeloong | i386-coreboot | i386-multiboot | i386-ieee1275 \ + | powerpc-ieee1275) imgext=elf ;; + *) imgext=img ;; +esac + +$grub_mkimage ${config_opt} -d ${pkglibdir} -O ${mkimage_target} --output=${grubdir}/core.${imgext} --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 + +# Backward-compatibility kludges +if [ "${target_cpu}-${platform}" = "mips-yeeloong" ]; then + cp ${grubdir}/core.${imgext} /boot/grub.elf +elif [ "${target_cpu}-${platform}" = "i386-ieee1275" ] || [ "${target_cpu}-${platform}" = "powerpc-ieee1275" ]; then + cp ${grubdir}/core.${imgext} /boot/grub/grub +elif [ "${target_cpu}-${platform}" = "i386-efi" ] || [ "${target_cpu}-${platform}" = "x86_64-efi" ]; then + $grub_mkimage ${config_opt} -d ${pkglibdir} -O ${mkimage_target} --output=${grubdir}/grub.efi --prefix="" $modules || exit 1 +fi + + +# Perform the platform-dependent install +if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] ; then # Now perform the installation. - $grub_setup ${setup_verbose} ${setup_force} --directory=${grubdir} --device-map=${device_map} \ - ${install_device} || exit 1 -elif [ "${target_cpu}-${platform}" = "mips-yeeloong" ] ; then - $grub_mkimage ${config_opt} -d ${pkglibdir} -O ${mkimage_target} --output=/boot/grub.elf --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 -else - $grub_mkimage -O ${mkimage_target} ${config_opt} -d ${pkglibdir} --output=/boot/multiboot.img --prefix=${prefix_drive}${relative_grubdir} $modules || exit 1 + $grub_setup ${setup_verbose} ${setup_force} --directory=${grubdir} \ + --device-map=${device_map} ${install_device} || exit 1 +elif [ "${target_cpu}-${platform}" = "i386-ieee1275" ] || [ "${target_cpu}-${platform}" = "powerpc-ieee1275" ]; then + if [ x"$update_nvram" = xyes ]; then + set $ofpathname dummy + if test -f "$1"; then + : + else + echo "$1: Not found." 1>&2 + exit 1 + fi + set $nvsetenv dummy + if test -f "$1"; then + : + else + echo "$1: Not found." 1>&2 + exit 1 + fi + # Get the Open Firmware device tree path translation. + dev=`echo $grub_device | sed -e 's/\/dev\///' -e 's/[0-9]\+//'` + partno=`echo $grub_device | sed -e 's/.*[^0-9]\([0-9]\+\)$/\1/'` + ofpath=`$ofpathname $dev` || { + echo "Couldn't find Open Firmware device tree path for $dev." + echo "You will have to set boot-device manually." + exit 1 + } + + # Point boot-device at the new grub install + boot_device="$ofpath:$partno,"`grub-mkrelpath ${grubdir}/core.${imgext} | sed 's,/,\\\\,g'` + "$nvsetenv" boot-device "$boot_device" || { + echo "$nvsetenv failed." + echo "You will have to set boot-device manually. At the Open Firmware prompt, type:" + echo " setenv boot-device $boot_device" + exit 1 + } + fi +elif [ x"$platform" = xefi ]; then + cp ${grubdir}/core.${imgext} ${efidir}/${efi_file} + + # Try to make this image bootable using the EFI Boot Manager, if available. + if test "$removable" = no && test -n "$efi_distributor" && \ + test -n "$efibootmgr"; then + # On Linux, we need the efivars kernel modules. + case "$host_os" in + linux*) + modprobe -q efivars 2>/dev/null || true ;; + esac + + # Delete old entries from the same distributor. + for bootnum in `efibootmgr | grep '^Boot[0-9]' | \ + fgrep -i " $efi_distributor" | cut -b5-8`; do + efibootmgr $efi_quiet -b "$bootnum" -B + done + + # Add a new entry for the image we just created. efibootmgr needs to be + # given the disk device and partition number separately, so we have to + # fiddle about with grub-probe to get hold of this reasonably reliably. + # Use fresh device map text to avoid any problems with stale data, since + # all we need here is a one-to-one mapping. + clean_devmap="$($grub_mkdevicemap --device-map=/dev/stdout)" + efidir_drive="$(echo "$clean_devmap" | $grub_probe --target=drive --device-map=/dev/stdin "$efidir")" + if test -z "$efidir_drive"; then + echo "Can't find GRUB drive for $efidir; unable to create EFI Boot Manager entry." >&2 + else + efidir_disk="$(echo "$clean_devmap" | grep "^$(echo "$efidir_drive" | sed 's/,[^)]*//')" | cut -f2)" + efidir_part="$(echo "$efidir_drive" | sed 's/^([^,]*,[^0-9]*//; s/[^0-9].*//')" + efibootmgr $efi_quiet -c -d "$efidir_disk" -p "$efidir_part" -w \ + -L "$GRUB_DISTRIBUTOR" -l "\\EFI\\$efi_distributor\\$efi_file" + fi + fi fi echo "Installation finished. No error reported." diff --git a/util/grub-kbdcomp.in b/util/grub-kbdcomp.in new file mode 100644 index 000000000..87b24bcdf --- /dev/null +++ b/util/grub-kbdcomp.in @@ -0,0 +1,6 @@ +#!/bin/sh + +grub_mklayout=${bindir}/`echo grub-mklayout | sed ${transform}` + +ckbcomp "$@" | $grub_mklayout -o "$1".gkb + diff --git a/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c new file mode 100644 index 000000000..512239e89 --- /dev/null +++ b/util/grub-menulst2cfg.c @@ -0,0 +1,120 @@ +/* + * 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 . + */ + +#include +#include +#include +#include +#include + +int +main (int argc, char **argv) +{ + FILE *in, *out; + char *entryname = NULL; + char *buf = NULL; + size_t bufsize = 0; + char *suffix = xstrdup (""); + int suffixlen = 0; + + if (argc >= 2 && argv[1][0] == '-') + { + fprintf (stdout, "Usage: %s [INFILE [OUTFILE]]\n", argv[0]); + return 0; + } + + if (argc >= 2) + { + in = fopen (argv[1], "r"); + if (!in) + { + fprintf (stderr, "Couldn't open %s for reading: %s\n", + argv[1], strerror (errno)); + return 1; + } + } + else + in = stdin; + + if (argc >= 3) + { + out = fopen (argv[2], "w"); + if (!out) + { + if (in != stdin) + fclose (in); + fprintf (stderr, "Couldn't open %s for writing: %s\n", + argv[2], strerror (errno)); + return 1; + } + } + else + out = stdout; + + while (1) + { + char *parsed; + + if (getline (&buf, &bufsize, in) < 0) + break; + + { + char *oldname = NULL; + char *newsuffix; + + oldname = entryname; + parsed = grub_legacy_parse (buf, &entryname, &newsuffix); + if (newsuffix) + { + suffixlen += strlen (newsuffix); + suffix = xrealloc (suffix, suffixlen + 1); + strcat (suffix, newsuffix); + } + if (oldname != entryname && oldname) + fprintf (out, "}\n\n"); + if (oldname != entryname) + { + char *escaped = grub_legacy_escape (entryname, strlen (entryname)); + fprintf (out, "menuentry \'%s\' {\n", escaped); + free (escaped); + free (oldname); + } + } + + if (parsed) + fprintf (out, "%s%s", entryname ? " " : "", parsed); + free (parsed); + parsed = NULL; + } + + if (entryname) + fprintf (out, "}\n\n"); + + fwrite (suffix, 1, suffixlen, out); + + free (buf); + free (suffix); + free (entryname); + + if (in != stdin) + fclose (in); + if (out != stdout) + fclose (out); + + return 0; +} diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in index 828b54bce..4a06e19bc 100644 --- a/util/grub-mkconfig.in +++ b/util/grub-mkconfig.in @@ -38,6 +38,8 @@ self=`basename $0` grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` +GRUB_PREFIX=`echo '/@bootdirname@/@grubdirname@' | sed "s,//*,/,g"` + # Usage: usage # Print the usage. usage () { @@ -93,18 +95,6 @@ done . ${libdir}/grub/grub-mkconfig_lib -case "$host_os" in -netbsd* | openbsd*) - # Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub - # instead of /boot/grub. - GRUB_PREFIX=`echo /grub | sed ${transform}` - ;; -*) - # Use /boot/grub by default. - GRUB_PREFIX=`echo /boot/grub | sed ${transform}` - ;; -esac - if [ "x$EUID" = "x" ] ; then EUID=`id -u` fi @@ -158,7 +148,7 @@ GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_u # Filesystem for the device containing our userland. Used for stuff like # choosing Hurd filesystem module. -GRUB_FS="`${grub_probe} --target=fs / 2> /dev/null || echo unknown`" +GRUB_FS="`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2> /dev/null || echo unknown`" if test -f ${sysconfdir}/default/grub ; then . ${sysconfdir}/default/grub @@ -200,7 +190,7 @@ for x in ${GRUB_TERMINAL_OUTPUT}; do exit 1 fi else - for dir in ${pkgdatadir} /boot/grub /usr/share/grub ; do + for dir in ${pkgdatadir} ${GRUB_PREFIX} /usr/share/grub ; do for basename in unicode unifont ascii; do path="${dir}/${basename}.pf2" if is_path_readable_by_grub ${path} > /dev/null ; then @@ -255,6 +245,7 @@ export GRUB_DEFAULT \ GRUB_HIDDEN_TIMEOUT_BUTTON \ GRUB_TIMEOUT_BUTTON \ GRUB_BUTTON_CMOS_ADDRESS \ + GRUB_BUTTON_CMOS_CLEAN \ GRUB_DISTRIBUTOR \ GRUB_CMDLINE_LINUX \ GRUB_CMDLINE_LINUX_DEFAULT \ @@ -314,8 +305,15 @@ for i in ${grub_mkconfig_dir}/* ; do done if test "x${grub_cfg}" != "x" ; then - # none of the children aborted with error, install the new grub.cfg - mv -f ${grub_cfg}.new ${grub_cfg} + if ! grub-script-check ${grub_cfg}.new; then + echo "Syntax errors are detected in generated GRUB config file." >&2 + echo "Ensure that there are no errors in /etc/default/grub" >&2 + echo "and /etc/grub.d/* files or please file a bug report with" >&2 + echo "${grub_cfg}.new file attached." >&2 + else + # none of the children aborted with error, install the new grub.cfg + mv -f ${grub_cfg}.new ${grub_cfg} + fi fi echo "done" >&2 diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in index 9a77d1bdf..41359975e 100644 --- a/util/grub-mkconfig_lib.in +++ b/util/grub-mkconfig_lib.in @@ -119,7 +119,7 @@ prepare_grub_to_access_device () # otherwise set root as per value in device.map. echo "set root='`${grub_probe} --device ${device} --target=drive`'" if fs_uuid="`${grub_probe} --device ${device} --target=fs_uuid 2> /dev/null`" ; then - echo "search --no-floppy --fs-uuid --set ${fs_uuid}" + echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}" fi } diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c index 0e82afae9..d798ad052 100644 --- a/util/grub-mkimage.c +++ b/util/grub-mkimage.c @@ -54,7 +54,8 @@ struct image_target_desc enum { IMAGE_I386_PC, IMAGE_EFI, IMAGE_COREBOOT, IMAGE_SPARC64_AOUT, IMAGE_SPARC64_RAW, IMAGE_I386_IEEE1275, - IMAGE_YEELOONG_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH + IMAGE_YEELOONG_ELF, IMAGE_QEMU, IMAGE_PPC, IMAGE_YEELOONG_FLASH, + IMAGE_I386_PC_PXE } id; enum { @@ -62,7 +63,7 @@ struct image_target_desc PLATFORM_FLAGS_LZMA = 1 } flags; unsigned prefix; - unsigned data_end; + unsigned prefix_end; unsigned raw_size; unsigned total_module_size; unsigned kernel_image_size; @@ -85,7 +86,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_COREBOOT, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_I386_COREBOOT_PREFIX, - .data_end = GRUB_KERNEL_I386_COREBOOT_DATA_END, + .prefix_end = GRUB_KERNEL_I386_COREBOOT_PREFIX_END, .raw_size = 0, .total_module_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD, @@ -107,7 +108,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_COREBOOT, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_I386_MULTIBOOT_PREFIX, - .data_end = GRUB_KERNEL_I386_MULTIBOOT_DATA_END, + .prefix_end = GRUB_KERNEL_I386_MULTIBOOT_PREFIX_END, .raw_size = 0, .total_module_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD, @@ -129,7 +130,25 @@ struct image_target_desc image_targets[] = .id = IMAGE_I386_PC, .flags = PLATFORM_FLAGS_LZMA, .prefix = GRUB_KERNEL_I386_PC_PREFIX, - .data_end = GRUB_KERNEL_I386_PC_DATA_END, + .prefix_end = GRUB_KERNEL_I386_PC_PREFIX_END, + .raw_size = GRUB_KERNEL_I386_PC_RAW_SIZE, + .total_module_size = GRUB_KERNEL_I386_PC_TOTAL_MODULE_SIZE, + .kernel_image_size = GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE, + .compressed_size = GRUB_KERNEL_I386_PC_COMPRESSED_SIZE, + .section_align = 1, + .vaddr_offset = 0, + .install_dos_part = GRUB_KERNEL_I386_PC_INSTALL_DOS_PART, + .install_bsd_part = GRUB_KERNEL_I386_PC_INSTALL_BSD_PART, + .link_addr = GRUB_KERNEL_I386_PC_LINK_ADDR + }, + { + .name = "i386-pc-pxe", + .voidp_sizeof = 4, + .bigendian = 0, + .id = IMAGE_I386_PC_PXE, + .flags = PLATFORM_FLAGS_LZMA, + .prefix = GRUB_KERNEL_I386_PC_PREFIX, + .prefix_end = GRUB_KERNEL_I386_PC_PREFIX_END, .raw_size = GRUB_KERNEL_I386_PC_RAW_SIZE, .total_module_size = GRUB_KERNEL_I386_PC_TOTAL_MODULE_SIZE, .kernel_image_size = GRUB_KERNEL_I386_PC_KERNEL_IMAGE_SIZE, @@ -147,7 +166,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_EFI, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_I386_EFI_PREFIX, - .data_end = GRUB_KERNEL_I386_EFI_DATA_END, + .prefix_end = GRUB_KERNEL_I386_EFI_PREFIX_END, .raw_size = 0, .total_module_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD, @@ -169,7 +188,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_I386_IEEE1275, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_I386_IEEE1275_PREFIX, - .data_end = GRUB_KERNEL_I386_IEEE1275_DATA_END, + .prefix_end = GRUB_KERNEL_I386_IEEE1275_PREFIX_END, .raw_size = 0, .total_module_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD, @@ -191,7 +210,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_QEMU, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_I386_QEMU_PREFIX, - .data_end = GRUB_KERNEL_I386_QEMU_DATA_END, + .prefix_end = GRUB_KERNEL_I386_QEMU_PREFIX_END, .raw_size = 0, .total_module_size = TARGET_NO_FIELD, .compressed_size = TARGET_NO_FIELD, @@ -209,7 +228,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_EFI, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_X86_64_EFI_PREFIX, - .data_end = GRUB_KERNEL_X86_64_EFI_DATA_END, + .prefix_end = GRUB_KERNEL_X86_64_EFI_PREFIX_END, .raw_size = 0, .total_module_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD, @@ -231,7 +250,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_YEELOONG_FLASH, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX, - .data_end = GRUB_KERNEL_MIPS_YEELOONG_DATA_END, + .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END, .raw_size = GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE, .total_module_size = GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE, .compressed_size = GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE, @@ -251,7 +270,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_YEELOONG_ELF, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_MIPS_YEELOONG_PREFIX, - .data_end = GRUB_KERNEL_MIPS_YEELOONG_DATA_END, + .prefix_end = GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END, .raw_size = GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE, .total_module_size = GRUB_KERNEL_MIPS_YEELOONG_TOTAL_MODULE_SIZE, .compressed_size = GRUB_KERNEL_MIPS_YEELOONG_COMPRESSED_SIZE, @@ -271,7 +290,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_PPC, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_POWERPC_IEEE1275_PREFIX, - .data_end = GRUB_KERNEL_POWERPC_IEEE1275_DATA_END, + .prefix_end = GRUB_KERNEL_POWERPC_IEEE1275_PREFIX_END, .raw_size = 0, .total_module_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD, @@ -293,7 +312,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_SPARC64_RAW, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX, - .data_end = GRUB_KERNEL_SPARC64_IEEE1275_DATA_END, + .prefix_end = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END, .raw_size = GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE, .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, .kernel_image_size = GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE, @@ -311,7 +330,7 @@ struct image_target_desc image_targets[] = .id = IMAGE_SPARC64_AOUT, .flags = PLATFORM_FLAGS_NONE, .prefix = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX, - .data_end = GRUB_KERNEL_SPARC64_IEEE1275_DATA_END, + .prefix_end = GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END, .raw_size = GRUB_KERNEL_SPARC64_IEEE1275_RAW_SIZE, .total_module_size = GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE, .kernel_image_size = GRUB_KERNEL_SPARC64_IEEE1275_KERNEL_IMAGE_SIZE, @@ -559,7 +578,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], total_module_size, &start_address, &rel_section, &reloc_size, &align, image_target); - if (image_target->prefix + strlen (prefix) + 1 > image_target->data_end) + if (image_target->prefix + strlen (prefix) + 1 > image_target->prefix_end) grub_util_error (_("prefix is too long")); strcpy (kernel_img + image_target->prefix, prefix); @@ -664,6 +683,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], switch (image_target->id) { case IMAGE_I386_PC: + case IMAGE_I386_PC_PXE: { unsigned num; char *boot_path, *boot_img; @@ -678,6 +698,20 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], if (num > 0xffff) grub_util_error (_("the core image is too big")); + if (image_target->id == IMAGE_I386_PC_PXE) + { + char *pxeboot_path, *pxeboot_img; + size_t pxeboot_size; + + pxeboot_path = grub_util_get_path (dir, "pxeboot.img"); + pxeboot_size = grub_util_get_image_size (pxeboot_path); + pxeboot_img = grub_util_read_image (pxeboot_path); + + grub_util_write_image (pxeboot_img, pxeboot_size, out); + free (pxeboot_img); + free (pxeboot_path); + } + boot_path = grub_util_get_path (dir, "diskboot.img"); boot_size = grub_util_get_image_size (boot_path); if (boot_size != GRUB_DISK_SECTOR_SIZE) diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index 4a257e329..ce51f2fbc 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -555,7 +555,7 @@ SUFFIX (locate_sections) (Elf_Shdr *sections, Elf_Half section_entsize, i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (SUFFIX (is_text_section) (s, image_target)) { - Elf_Word align = grub_host_to_target32 (s->sh_addralign); + Elf_Word align = grub_host_to_target_addr (s->sh_addralign); const char *name = strtab + grub_host_to_target32 (s->sh_name); if (align) current_address = ALIGN_UP (current_address + image_target->vaddr_offset, @@ -577,7 +577,7 @@ SUFFIX (locate_sections) (Elf_Shdr *sections, Elf_Half section_entsize, i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (SUFFIX (is_data_section) (s, image_target)) { - Elf_Word align = grub_host_to_target32 (s->sh_addralign); + Elf_Word align = grub_host_to_target_addr (s->sh_addralign); const char *name = strtab + grub_host_to_target32 (s->sh_name); if (align) @@ -641,7 +641,7 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, /* Relocate sections then symbols in the virtual address space. */ s = (Elf_Shdr *) ((char *) sections + grub_host_to_target16 (e->e_shstrndx) * section_entsize); - strtab = (char *) e + grub_host_to_target32 (s->sh_offset); + strtab = (char *) e + grub_host_to_target_addr (s->sh_offset); section_addresses = SUFFIX (locate_sections) (sections, section_entsize, num_sections, strtab, @@ -662,7 +662,7 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size, i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS) { - Elf_Word align = grub_host_to_target32 (s->sh_addralign); + Elf_Word align = grub_host_to_target_addr (s->sh_addralign); const char *name = strtab + grub_host_to_target32 (s->sh_name); if (align) diff --git a/util/grub-mklayout.c b/util/grub-mklayout.c new file mode 100644 index 000000000..ac59981c7 --- /dev/null +++ b/util/grub-mklayout.c @@ -0,0 +1,498 @@ +/* + * 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 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "progname.h" + +#define CKBCOMP "ckbcomp" + +static struct option options[] = { + {"output", required_argument, 0, 'o'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +struct console_grub_equivalence +{ + char *layout; + grub_uint32_t grub; +}; + +static struct console_grub_equivalence console_grub_equivalences_shift[] = { + {"KP_0", '0'}, + {"KP_1", '1'}, + {"KP_2", '2'}, + {"KP_3", '3'}, + {"KP_4", '4'}, + {"KP_5", '5'}, + {"KP_6", '6'}, + {"KP_7", '7'}, + {"KP_8", '8'}, + {"KP_9", '9'}, + {"KP_Period", '.'}, +}; + +static struct console_grub_equivalence console_grub_equivalences_unshift[] = { + {"KP_0", GRUB_TERM_KEY_INSERT}, + {"KP_1", GRUB_TERM_KEY_END}, + {"KP_2", GRUB_TERM_KEY_DOWN}, + {"KP_3", GRUB_TERM_KEY_NPAGE}, + {"KP_4", GRUB_TERM_KEY_LEFT}, + {"KP_5", GRUB_TERM_KEY_CENTER}, + {"KP_6", GRUB_TERM_KEY_RIGHT}, + {"KP_7", GRUB_TERM_KEY_HOME}, + {"KP_8", GRUB_TERM_KEY_UP}, + {"KP_9", GRUB_TERM_KEY_PPAGE}, + {"KP_Period", GRUB_TERM_KEY_DC}, +}; + +static struct console_grub_equivalence console_grub_equivalences_common[] = { + {"Escape", GRUB_TERM_ESC}, + {"Tab", GRUB_TERM_TAB}, + {"Delete", GRUB_TERM_BACKSPACE}, + + {"KP_Enter", '\n'}, + {"Return", '\n'}, + + {"KP_Multiply", '*'}, + {"KP_Subtract", '-'}, + {"KP_Add", '+'}, + {"KP_Divide", '/'}, + + {"F1", GRUB_TERM_KEY_F1}, + {"F2", GRUB_TERM_KEY_F2}, + {"F3", GRUB_TERM_KEY_F3}, + {"F4", GRUB_TERM_KEY_F4}, + {"F5", GRUB_TERM_KEY_F5}, + {"F6", GRUB_TERM_KEY_F6}, + {"F7", GRUB_TERM_KEY_F7}, + {"F8", GRUB_TERM_KEY_F8}, + {"F9", GRUB_TERM_KEY_F9}, + {"F10", GRUB_TERM_KEY_F10}, + {"F11", GRUB_TERM_KEY_F11}, + {"F12", GRUB_TERM_KEY_F12}, + {"F13", GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT}, + {"F14", GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT}, + {"F15", GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT}, + {"F16", GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT}, + {"F17", GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT}, + {"F18", GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT}, + {"F19", GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT}, + {"F20", GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT}, + {"F21", GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT}, + {"F22", GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT}, + {"F23", GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT}, + {"F24", GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT}, + {"Console_13", GRUB_TERM_KEY_F1 | GRUB_TERM_ALT}, + {"Console_14", GRUB_TERM_KEY_F2 | GRUB_TERM_ALT}, + {"Console_15", GRUB_TERM_KEY_F3 | GRUB_TERM_ALT}, + {"Console_16", GRUB_TERM_KEY_F4 | GRUB_TERM_ALT}, + {"Console_17", GRUB_TERM_KEY_F5 | GRUB_TERM_ALT}, + {"Console_18", GRUB_TERM_KEY_F6 | GRUB_TERM_ALT}, + {"Console_19", GRUB_TERM_KEY_F7 | GRUB_TERM_ALT}, + {"Console_20", GRUB_TERM_KEY_F8 | GRUB_TERM_ALT}, + {"Console_21", GRUB_TERM_KEY_F9 | GRUB_TERM_ALT}, + {"Console_22", GRUB_TERM_KEY_F10 | GRUB_TERM_ALT}, + {"Console_23", GRUB_TERM_KEY_F11 | GRUB_TERM_ALT}, + {"Console_24", GRUB_TERM_KEY_F12 | GRUB_TERM_ALT}, + {"Console_25", GRUB_TERM_KEY_F1 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_26", GRUB_TERM_KEY_F2 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_27", GRUB_TERM_KEY_F3 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_28", GRUB_TERM_KEY_F4 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_29", GRUB_TERM_KEY_F5 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_30", GRUB_TERM_KEY_F6 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_31", GRUB_TERM_KEY_F7 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_32", GRUB_TERM_KEY_F8 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_33", GRUB_TERM_KEY_F9 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_34", GRUB_TERM_KEY_F10 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_35", GRUB_TERM_KEY_F11 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + {"Console_36", GRUB_TERM_KEY_F12 | GRUB_TERM_SHIFT | GRUB_TERM_ALT}, + + {"Insert", GRUB_TERM_KEY_INSERT}, + {"Down", GRUB_TERM_KEY_DOWN}, + {"Up", GRUB_TERM_KEY_UP}, + {"Home", GRUB_TERM_KEY_HOME}, + {"End", GRUB_TERM_KEY_END}, + {"Right", GRUB_TERM_KEY_RIGHT}, + {"Left", GRUB_TERM_KEY_LEFT}, + {"Next", GRUB_TERM_KEY_NPAGE}, + {"Prior", GRUB_TERM_KEY_PPAGE}, + {"Remove", GRUB_TERM_KEY_DC}, + {"VoidSymbol", 0}, + + /* "Undead" keys since no dead key support in GRUB. */ + {"dead_acute", '\''}, + {"dead_circumflex", '^'}, + {"dead_grave", '`'}, + {"dead_tilde", '~'}, + {"dead_diaeresis", '"'}, + + /* Following ones don't provide any useful symbols for shell. */ + {"dead_cedilla", 0}, + {"dead_ogonek", 0}, + {"dead_caron", 0}, + {"dead_breve", 0}, + {"dead_doubleacute", 0}, + + /* Unused in GRUB. */ + {"Pause", 0}, + {"Scroll_Forward", 0}, + {"Scroll_Backward", 0}, + {"Hex_0", 0}, + {"Hex_1", 0}, + {"Hex_2", 0}, + {"Hex_3", 0}, + {"Hex_4", 0}, + {"Hex_5", 0}, + {"Hex_6", 0}, + {"Hex_7", 0}, + {"Hex_8", 0}, + {"Hex_9", 0}, + {"Hex_A", 0}, + {"Hex_B", 0}, + {"Hex_C", 0}, + {"Hex_D", 0}, + {"Hex_E", 0}, + {"Hex_F", 0}, + {"Scroll_Lock", 0}, + {"Show_Memory", 0}, + {"Show_Registers", 0}, + {"Control_backslash", 0}, + {"Compose", 0}, + + {NULL, '\0'} +}; + +static grub_uint8_t linux_to_usb_map[128] = { + /* 0x00 */ 0 /* Unused */, GRUB_KEYBOARD_KEY_ESCAPE, + /* 0x02 */ GRUB_KEYBOARD_KEY_1, GRUB_KEYBOARD_KEY_2, + /* 0x04 */ GRUB_KEYBOARD_KEY_3, GRUB_KEYBOARD_KEY_4, + /* 0x06 */ GRUB_KEYBOARD_KEY_5, GRUB_KEYBOARD_KEY_6, + /* 0x08 */ GRUB_KEYBOARD_KEY_7, GRUB_KEYBOARD_KEY_8, + /* 0x0a */ GRUB_KEYBOARD_KEY_9, GRUB_KEYBOARD_KEY_0, + /* 0x0c */ GRUB_KEYBOARD_KEY_DASH, GRUB_KEYBOARD_KEY_EQUAL, + /* 0x0e */ GRUB_KEYBOARD_KEY_BACKSPACE, GRUB_KEYBOARD_KEY_TAB, + /* 0x10 */ GRUB_KEYBOARD_KEY_Q, GRUB_KEYBOARD_KEY_W, + /* 0x12 */ GRUB_KEYBOARD_KEY_E, GRUB_KEYBOARD_KEY_R, + /* 0x14 */ GRUB_KEYBOARD_KEY_T, GRUB_KEYBOARD_KEY_Y, + /* 0x16 */ GRUB_KEYBOARD_KEY_U, GRUB_KEYBOARD_KEY_I, + /* 0x18 */ GRUB_KEYBOARD_KEY_O, GRUB_KEYBOARD_KEY_P, + /* 0x1a */ GRUB_KEYBOARD_KEY_LBRACKET, GRUB_KEYBOARD_KEY_RBRACKET, + /* 0x1c */ GRUB_KEYBOARD_KEY_ENTER, GRUB_KEYBOARD_KEY_LEFT_CTRL, + /* 0x1e */ GRUB_KEYBOARD_KEY_A, GRUB_KEYBOARD_KEY_S, + /* 0x20 */ GRUB_KEYBOARD_KEY_D, GRUB_KEYBOARD_KEY_F, + /* 0x22 */ GRUB_KEYBOARD_KEY_G, GRUB_KEYBOARD_KEY_H, + /* 0x24 */ GRUB_KEYBOARD_KEY_J, GRUB_KEYBOARD_KEY_K, + /* 0x26 */ GRUB_KEYBOARD_KEY_L, GRUB_KEYBOARD_KEY_SEMICOLON, + /* 0x28 */ GRUB_KEYBOARD_KEY_DQUOTE, GRUB_KEYBOARD_KEY_RQUOTE, + /* 0x2a */ GRUB_KEYBOARD_KEY_LEFT_SHIFT, GRUB_KEYBOARD_KEY_BACKSLASH, + /* 0x2c */ GRUB_KEYBOARD_KEY_Z, GRUB_KEYBOARD_KEY_X, + /* 0x2e */ GRUB_KEYBOARD_KEY_C, GRUB_KEYBOARD_KEY_V, + /* 0x30 */ GRUB_KEYBOARD_KEY_B, GRUB_KEYBOARD_KEY_N, + /* 0x32 */ GRUB_KEYBOARD_KEY_M, GRUB_KEYBOARD_KEY_COMMA, + /* 0x34 */ GRUB_KEYBOARD_KEY_DOT, GRUB_KEYBOARD_KEY_SLASH, + /* 0x36 */ GRUB_KEYBOARD_KEY_RIGHT_SHIFT, GRUB_KEYBOARD_KEY_NUMMUL, + /* 0x38 */ GRUB_KEYBOARD_KEY_LEFT_ALT, GRUB_KEYBOARD_KEY_SPACE, + /* 0x3a */ GRUB_KEYBOARD_KEY_CAPS_LOCK, GRUB_KEYBOARD_KEY_F1, + /* 0x3c */ GRUB_KEYBOARD_KEY_F2, GRUB_KEYBOARD_KEY_F3, + /* 0x3e */ GRUB_KEYBOARD_KEY_F4, GRUB_KEYBOARD_KEY_F5, + /* 0x40 */ GRUB_KEYBOARD_KEY_F6, GRUB_KEYBOARD_KEY_F7, + /* 0x42 */ GRUB_KEYBOARD_KEY_F8, GRUB_KEYBOARD_KEY_F9, + /* 0x44 */ GRUB_KEYBOARD_KEY_F10, GRUB_KEYBOARD_KEY_NUM_LOCK, + /* 0x46 */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, GRUB_KEYBOARD_KEY_NUM7, + /* 0x48 */ GRUB_KEYBOARD_KEY_NUM8, GRUB_KEYBOARD_KEY_NUM9, + /* 0x4a */ GRUB_KEYBOARD_KEY_NUMMINUS, GRUB_KEYBOARD_KEY_NUM4, + /* 0x4c */ GRUB_KEYBOARD_KEY_NUM5, GRUB_KEYBOARD_KEY_NUM6, + /* 0x4e */ GRUB_KEYBOARD_KEY_NUMPLUS, GRUB_KEYBOARD_KEY_NUM1, + /* 0x50 */ GRUB_KEYBOARD_KEY_NUM2, GRUB_KEYBOARD_KEY_NUM3, + /* 0x52 */ GRUB_KEYBOARD_KEY_NUMDOT, GRUB_KEYBOARD_KEY_NUMDOT, + /* 0x54 */ 0, 0, + /* 0x56 */ GRUB_KEYBOARD_KEY_102ND, GRUB_KEYBOARD_KEY_F11, + /* 0x58 */ GRUB_KEYBOARD_KEY_F12, 0, + /* 0x5a */ 0, 0, + /* 0x5c */ 0, 0, + /* 0x5e */ 0, 0, + /* 0x60 */ GRUB_KEYBOARD_KEY_NUMENTER, GRUB_KEYBOARD_KEY_RIGHT_CTRL, + /* 0x62 */ GRUB_KEYBOARD_KEY_NUMSLASH, 0, + /* 0x64 */ GRUB_KEYBOARD_KEY_RIGHT_ALT, 0, + /* 0x66 */ GRUB_KEYBOARD_KEY_HOME, GRUB_KEYBOARD_KEY_UP, + /* 0x68 */ GRUB_KEYBOARD_KEY_PPAGE, GRUB_KEYBOARD_KEY_LEFT, + /* 0x6a */ GRUB_KEYBOARD_KEY_RIGHT, GRUB_KEYBOARD_KEY_END, + /* 0x6c */ GRUB_KEYBOARD_KEY_DOWN, GRUB_KEYBOARD_KEY_NPAGE, + /* 0x6e */ GRUB_KEYBOARD_KEY_INSERT, GRUB_KEYBOARD_KEY_DELETE +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try `%s --help' for more information.\n", program_name); + else + printf ("\ +Usage: %s [OPTIONS] LAYOUT\n\ + -o, --output set output base name file. Default is LAYOUT.gkb\n\ + -h, --help display this message and exit.\n\ + -V, --version print version information and exit.\n\ + -v, --verbose print verbose messages.\n\ +\n\ +Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT); + + exit (status); +} + +static void +add_special_keys (struct grub_keyboard_layout *layout) +{ + (void) layout; +} + +static unsigned +lookup (char *code, int shift) +{ + int i; + struct console_grub_equivalence *pr; + + if (shift) + pr = console_grub_equivalences_shift; + else + pr = console_grub_equivalences_unshift; + + for (i = 0; pr[i].layout != NULL; i++) + if (strcmp (code, pr[i].layout) == 0) + return pr[i].grub; + + for (i = 0; console_grub_equivalences_common[i].layout != NULL; i++) + if (strcmp (code, console_grub_equivalences_common[i].layout) == 0) + return console_grub_equivalences_common[i].grub; + + fprintf (stderr, "Unknown key %s\n", code); + + return '\0'; +} + +static unsigned int +get_grub_code (char *layout_code, int shift) +{ + unsigned int code; + + if (strncmp (layout_code, "U+", sizeof ("U+") - 1) == 0) + sscanf (layout_code, "U+%x", &code); + else if (strncmp (layout_code, "+U+", sizeof ("+U+") - 1) == 0) + sscanf (layout_code, "+U+%x", &code); + else + code = lookup (layout_code, shift); + return code; +} + +static void +write_file (FILE *out, struct grub_keyboard_layout *layout) +{ + grub_uint32_t version; + unsigned i; + + version = grub_cpu_to_le32 (GRUB_KEYBOARD_LAYOUTS_VERSION); + + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map); i++) + layout->keyboard_map[i] = grub_cpu_to_le32(layout->keyboard_map[i]); + + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_shift); i++) + layout->keyboard_map_shift[i] + = grub_cpu_to_le32(layout->keyboard_map_shift[i]); + + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_l3); i++) + layout->keyboard_map_l3[i] + = grub_cpu_to_le32(layout->keyboard_map_l3[i]); + + for (i = 0; i < ARRAY_SIZE (layout->keyboard_map_shift_l3); i++) + layout->keyboard_map_shift_l3[i] + = grub_cpu_to_le32(layout->keyboard_map_shift_l3[i]); + + fwrite (GRUB_KEYBOARD_LAYOUTS_FILEMAGIC, 1, + GRUB_KEYBOARD_LAYOUTS_FILEMAGIC_SIZE, out); + fwrite (&version, sizeof (version), 1, out); + fwrite (layout, 1, sizeof (*layout), out); +} + +static void +write_keymaps (FILE *in, FILE *out) +{ + struct grub_keyboard_layout layout; + char line[2048]; + int ok; + + memset (&layout, 0, sizeof (layout)); + + /* Process the ckbcomp output and prepare the layouts. */ + ok = 0; + while (fgets (line, sizeof (line), in)) + { + if (strncmp (line, "keycode", sizeof ("keycode") - 1) == 0) + { + unsigned keycode_linux; + unsigned keycode_usb; + char normal[64]; + char shift[64]; + char normalalt[64]; + char shiftalt[64]; + + sscanf (line, "keycode %u = %60s %60s %60s %60s", &keycode_linux, + normal, shift, normalalt, shiftalt); + + /* Not used. */ + if (keycode_linux == 0x77 /* Pause */ + /* Some obscure keys */ + || keycode_linux == 0x63 || keycode_linux == 0x7d + || keycode_linux == 0x7e) + continue; + + /* Not remappable. */ + if (keycode_linux == 0x1d /* Left CTRL */ + || keycode_linux == 0x61 /* Right CTRL */ + || keycode_linux == 0x2a /* Left Shift. */ + || keycode_linux == 0x36 /* Right Shift. */ + || keycode_linux == 0x38 /* Left ALT. */ + || keycode_linux == 0x64 /* Right ALT. */ + || keycode_linux == 0x3a /* CapsLock. */ + || keycode_linux == 0x45 /* NumLock. */ + || keycode_linux == 0x46 /* ScrollLock. */) + continue; + + keycode_usb = linux_to_usb_map[keycode_linux]; + if (keycode_usb == 0 + || keycode_usb >= GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) + { + fprintf (stderr, "Unknown keycode 0x%02x\n", keycode_linux); + continue; + } + if (keycode_usb < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) + { + layout.keyboard_map[keycode_usb] = get_grub_code (normal, 0); + layout.keyboard_map_shift[keycode_usb] = get_grub_code (shift, 1); + layout.keyboard_map_l3[keycode_usb] + = get_grub_code (normalalt, 0); + layout.keyboard_map_shift_l3[keycode_usb] + = get_grub_code (shiftalt, 1); + ok = 1; + } + } + } + + if (ok == 0) + { + fprintf (stderr, "ERROR: no keycodes found. Check output of %s.\n", + CKBCOMP); + exit (1); + } + + add_special_keys (&layout); + + write_file (out, &layout); +} + +int +main (int argc, char *argv[]) +{ + int verbosity; + char *infile_name = NULL; + char *outfile_name = NULL; + FILE *in, *out; + + set_program_name (argv[0]); + + verbosity = 0; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "o:i:hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'i': + infile_name = optarg; + break; + + case 'o': + outfile_name = optarg; + break; + + case 'V': + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, + PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + if (infile_name) + in = fopen (infile_name, "r"); + else + in = stdin; + + if (!in) + grub_util_error ("Couldn't open input file: %s\n", strerror (errno)); + + if (outfile_name) + out = fopen (outfile_name, "wb"); + else + out = stdout; + + if (!out) + { + if (in != stdin) + fclose (in); + grub_util_error ("Couldn't open output file: %s\n", strerror (errno)); + } + + write_keymaps (in, out); + + if (in != stdin) + fclose (in); + + if (out != stdout) + fclose (out); + + return 0; +} diff --git a/util/grub-mknetdir.in b/util/grub-mknetdir.in new file mode 100644 index 000000000..b353e98b9 --- /dev/null +++ b/util/grub-mknetdir.in @@ -0,0 +1,230 @@ +#! /bin/sh + +# Install GRUB on your drive. +# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +# Initialize some variables. +transform="@program_transform_name@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +sbindir=@sbindir@ +bindir=@bindir@ +libdir=@libdir@ +PACKAGE_NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +target_cpu=@target_cpu@ +platform=@platform@ +host_os=@host_os@ +pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` +localedir=@datadir@/locale +native_platform=@platform@ +pkglib_DATA="moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst terminal.lst" + +self=`basename $0` + +grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` +rootdir=/srv/tftp +grub_prefix=`echo /boot/grub | sed ${transform}` +modules= + +install_device= +no_floppy= +recheck=no +debug=no +debug_image= +subdir=`echo /boot/grub | sed ${transform}` +pc_dir=${libdir}/$(echo ${PACKAGE_TARNAME} | sed ${transform})/i386-pc + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +argument () { + opt=$1 + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- '$opt'" 1>&2 + exit 1 + fi + echo $1 +} + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" + exit 0 ;; + + --modules) + modules=`argument $option "$@"`; shift;; + --modules=*) + modules=`echo "$option" | sed 's/--modules=//'` ;; + + --net-directory) + rootdir=`argument $option "$@"`; shift;; + --net-directory=*) + rootdir=`echo "$option" | sed 's/--net-directory=//'` ;; + + --subdir) + subdir=`argument $option "$@"`; shift;; + --subdir=*) + subdir=`echo "$option" | sed 's/--subdir=//'` ;; + + --grub-mkimage) + grub_mkimage=`argument $option "$@"`; shift;; + --grub-mkimage=*) + grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; + + # This is an undocumented feature... + --debug) + debug=yes ;; + --debug-image) + debug_image=`argument $option "$@"`; shift;; + --debug-image=*) + debug_image=`echo "$option" | sed 's/--debug-image=//'` ;; + + # Intentionally undocumented + --override-directory) + override_dir=`argument $option "$@"` + shift + PATH=${override_dir}:$PATH + export PATH + ;; + --override-directory=*) + override_dir=`echo "${option}/" | sed 's/--override-directory=//'` + PATH=${override_dir}:$PATH + export PATH + ;; + + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$install_device" != x; then + echo "More than one install_devices?" 1>&2 + usage + exit 1 + fi + install_device="${option}" ;; + esac +done + +set $grub_mkimage dummy +if test -f "$1"; then + : +else + echo "$1: Not found." 1>&2 + exit 1 +fi + +# Create the GRUB directory if it is not present. +mkdir -p "${rootdir}/${subdir}" || exit 1 + +process_input_dir () +{ + input_dir="$1" + platform="$2" + grubdir="${rootdir}/${subdir}/${platform}" + config_opt= + mkdir -p "$grubdir" || exit 1 + + for file in ${grubdir}/*.mod ${grubdir}/*.lst ${grubdir}/*.img ${grubdir}/efiemu??.o; do + if test -f $file && [ "`basename $file`" != menu.lst ]; then + rm -f $file || exit 1 + fi + done + for file in ${input_dir}/*.mod; do + if test -f "$file"; then + cp -f "$file" "$grubdir/" + fi + done + for file in ${pkglib_DATA}; do + if test -f "${input_dir}/${file}"; then + cp -f "${input_dir}/${file}" "$grubdir/" + fi + done + + mkdir -p "$grubdir/locale" + for file in ${input_dir}/po/*.mo; do + if test -f "$file"; then + cp -f "$file" "$grubdir/locale/" + fi + done + + rm -f ${grubdir}/load.cfg + + if [ "x${debug_image}" != x ]; then + echo "set debug='${debug_image}'" >> ${grubdir}/load.cfg + config_opt="-c ${grubdir}/load.cfg " + fi + + case "${platform}" in + i386-pc) mkimage_target=i386-pc-pxe; + netmodules="pxe"; + prefix="(pxe)/${subdir}/${platform}"; + ext=0 ;; + *) echo Unsupported platform ${platform}; + exit 1;; + esac + + cat << EOF > ${grubdir}/grub.cfg +source ${subdir}/grub.cfg +EOF + + $grub_mkimage ${config_opt} -d "${input_dir}" -O ${mkimage_target} --output=${grubdir}/core.$ext --prefix=$prefix $modules $netmodules || exit 1 + echo "Netboot directory for ${platform} created. Configure your DHCP server to point to ${subdir}/${platform}/core.$ext" +} + +if [ "${override_dir}" = "" ] ; then + if test -e "${pc_dir}" ; then + process_input_dir ${pc_dir} i386-pc + fi +else + process_input_dir ${override_dir} ${target_cpu}-${native_platform} +fi + + +# Bye. +exit 0 diff --git a/util/grub-mkrescue.in b/util/grub-mkrescue.in index 0f40e92cc..142ee85cd 100644 --- a/util/grub-mkrescue.in +++ b/util/grub-mkrescue.in @@ -62,7 +62,8 @@ Make GRUB rescue image. $self generates a bootable rescue image with specified source files, source directories, or mkisofs options listed by: xorriso -as mkisofs -help -Option -- switches to native xorriso command mode. or directories. + +Option -- switches to native xorriso command mode. Report bugs to . Mail xorriso support requests to . diff --git a/util/grub-probe.c b/util/grub-probe.c index ab3e2713e..9f8a443c8 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -226,48 +226,16 @@ probe (const char *path, char *device_name) if (print == PRINT_FS) { - if (path) - { - struct stat st; - - stat (path, &st); - - if (S_ISREG (st.st_mode)) - { - /* Regular file. Verify that we can read it properly. */ - - grub_file_t file; - char *rel_path; - grub_util_info ("reading %s via OS facilities", path); - filebuf_via_sys = grub_util_read_image (path); - - rel_path = grub_make_system_path_relative_to_its_root (path); - grub_path = xasprintf ("(%s)%s", drive_name, rel_path); - free (rel_path); - grub_util_info ("reading %s via GRUB facilities", grub_path); - file = grub_file_open (grub_path); - if (! file) - grub_util_error ("cannot open %s via GRUB facilities", grub_path); - filebuf_via_grub = xmalloc (file->size); - grub_file_read (file, filebuf_via_grub, file->size); - - grub_util_info ("comparing"); - - if (memcmp (filebuf_via_grub, filebuf_via_sys, file->size)) - grub_util_error ("files differ"); - } - } - printf ("%s\n", fs->name); } - - if (print == PRINT_FS_UUID) + else if (print == PRINT_FS_UUID) { char *uuid; if (! fs->uuid) grub_util_error ("%s does not support UUIDs", fs->name); - fs->uuid (dev, &uuid); + if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); printf ("%s\n", uuid); } @@ -277,7 +245,8 @@ probe (const char *path, char *device_name) if (! fs->label) grub_util_error ("%s does not support labels", fs->name); - fs->label (dev, &label); + if (fs->label (dev, &label) != GRUB_ERR_NONE) + grub_util_error ("%s", grub_errmsg); printf ("%s\n", label); } @@ -421,6 +390,13 @@ main (int argc, char *argv[]) /* Initialize all modules. */ grub_init_all (); + grub_lvm_fini (); + grub_mdraid_fini (); + grub_raid_fini (); + grub_raid_init (); + grub_mdraid_init (); + grub_lvm_init (); + /* Do it. */ if (argument_is_device) probe (NULL, argument); diff --git a/util/grub-reboot.in b/util/grub-reboot.in index e7a41f68f..929cf5202 100644 --- a/util/grub-reboot.in +++ b/util/grub-reboot.in @@ -29,6 +29,8 @@ self=`basename $0` grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` rootdir= +bootdir= +grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` # Usage: usage # Print the usage. @@ -39,8 +41,8 @@ Set the default boot entry for GRUB, for the next boot only. -h, --help print this message and exit -v, --version print the version information and exit - --root-directory=DIR expect GRUB images under the directory DIR - instead of the root directory + --boot-directory=DIR expect GRUB images under the directory DIR/@grubdirname@ + instead of the $grubdir directory ENTRY is a number or a menu item title. @@ -73,11 +75,17 @@ do echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" exit 0 ;; +# Accept for compatibility --root-directory) rootdir=`argument $option "$@"`; shift ;; --root-directory=*) rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; + --boot-directory) + bootdir=`argument $option "$@"`; shift;; + --boot-directory=*) + bootdir=`echo "$option" | sed 's/--boot-directory=//'` ;; + -*) echo "Unrecognized option \`$option'" 1>&2 usage @@ -99,21 +107,17 @@ if test "x$entry" = x; then exit 1 fi -# Initialize these directories here, since ROOTDIR was initialized. -case "$host_os" in -netbsd* | openbsd*) - # Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub - # instead of /boot/grub. - grub_prefix=`echo /grub | sed ${transform}` - bootdir=${rootdir} - ;; -*) - # Use /boot/grub by default. - bootdir=${rootdir}/boot - ;; -esac +if [ -z "$bootdir" ]; then + # Default bootdir if bootdir not initialized. + bootdir=/@bootdirname@ -grubdir=${bootdir}/`echo grub | sed ${transform}` + if [ -n "$rootdir" ] ; then + # Initialize bootdir if rootdir was initialized. + bootdir=${rootdir}/@bootdirname@ + fi +fi + +grubdir=`echo "${bootdir}/@grubdirname@" | sed 's,//*,/,g'` prev_saved_entry=`$grub_editenv ${grubdir}/grubenv list | sed -n 's/^saved_entry=//p'` if [ "$prev_saved_entry" ]; then diff --git a/util/grub-set-default.in b/util/grub-set-default.in index 389c504c7..b09727de2 100644 --- a/util/grub-set-default.in +++ b/util/grub-set-default.in @@ -29,6 +29,8 @@ self=`basename $0` grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` rootdir= +bootdir= +grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` # Usage: usage # Print the usage. @@ -39,8 +41,8 @@ Set the default boot entry for GRUB. -h, --help print this message and exit -v, --version print the version information and exit - --root-directory=DIR expect GRUB images under the directory DIR - instead of the root directory + --boot-directory=DIR expect GRUB images under the directory DIR/@grubdirname@ + instead of the $grubdir directory ENTRY is a number or a menu item title. @@ -73,11 +75,17 @@ do echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" exit 0 ;; +# Accept for compatibility --root-directory) rootdir=`argument $option "$@"`; shift ;; --root-directory=*) rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; + --boot-directory) + bootdir=`argument $option "$@"`; shift;; + --boot-directory=*) + bootdir=`echo "$option" | sed 's/--boot-directory=//'` ;; + -*) echo "Unrecognized option \`$option'" 1>&2 usage @@ -99,21 +107,17 @@ if test "x$entry" = x; then exit 1 fi -# Initialize these directories here, since ROOTDIR was initialized. -case "$host_os" in -netbsd* | openbsd*) - # Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub - # instead of /boot/grub. - grub_prefix=`echo /grub | sed ${transform}` - bootdir=${rootdir} - ;; -*) - # Use /boot/grub by default. - bootdir=${rootdir}/boot - ;; -esac +if [ -z "$bootdir" ]; then + # Default bootdir if bootdir not initialized. + bootdir=/@bootdirname@ -grubdir=${bootdir}/`echo grub | sed ${transform}` + if [ -n "$rootdir" ] ; then + # Initialize bootdir if rootdir was initialized. + bootdir=${rootdir}/@bootdirname@ + fi +fi + +grubdir=`echo "${bootdir}/@grubdirname@" | sed 's,//*,/,g'` $grub_editenv ${grubdir}/grubenv unset prev_saved_entry $grub_editenv ${grubdir}/grubenv set saved_entry="$entry" diff --git a/util/i386/pc/grub-setup.c b/util/grub-setup.c similarity index 55% rename from util/i386/pc/grub-setup.c rename to util/grub-setup.c index 9788efe4a..1bf0d958d 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/grub-setup.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #include #include @@ -36,9 +34,9 @@ #include #include #include -#include - -static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT; +#ifdef GRUB_MACHINE_IEEE1275 +#include +#endif #include #include @@ -48,96 +46,165 @@ static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_P #include #include #include +#include #include "progname.h" #define _GNU_SOURCE 1 #include +/* On SPARC this program fills in various fields inside of the 'boot' and 'core' + * image files. + * + * The 'boot' image needs to know the OBP path name of the root + * device. It also needs to know the initial block number of + * 'core' (which is 'diskboot' concatenated with 'kernel' and + * all the modules, this is created by grub-mkimage). This resulting + * 'boot' image is 512 bytes in size and is placed in the second block + * of a partition. + * + * The initial 'diskboot' block acts as a loader for the actual GRUB + * kernel. It contains the loading code and then a block list. + * + * The block list of 'core' starts at the end of the 'diskboot' image + * and works it's way backwards towards the end of the code of 'diskboot'. + * + * We patch up the images with the necessary values and write out the + * result. + */ + #define DEFAULT_BOOT_FILE "boot.img" #define DEFAULT_CORE_FILE "core.img" +#ifdef GRUB_MACHINE_SPARC64 +#define grub_target_to_host16(x) grub_be_to_cpu16(x) +#define grub_target_to_host32(x) grub_be_to_cpu32(x) +#define grub_target_to_host64(x) grub_be_to_cpu64(x) +#define grub_host_to_target16(x) grub_cpu_to_be16(x) +#define grub_host_to_target32(x) grub_cpu_to_be32(x) +#define grub_host_to_target64(x) grub_cpu_to_be64(x) +#elif defined (GRUB_MACHINE_PCBIOS) #define grub_target_to_host16(x) grub_le_to_cpu16(x) #define grub_target_to_host32(x) grub_le_to_cpu32(x) #define grub_target_to_host64(x) grub_le_to_cpu64(x) #define grub_host_to_target16(x) grub_cpu_to_le16(x) #define grub_host_to_target32(x) grub_cpu_to_le32(x) #define grub_host_to_target64(x) grub_cpu_to_le64(x) +#else +#error Complete this +#endif + +static void +write_rootdev (char *core_img, grub_device_t root_dev, + char *boot_img, grub_uint64_t first_sector) +{ +#ifdef GRUB_MACHINE_PCBIOS + { + grub_int32_t *install_dos_part, *install_bsd_part; + grub_int32_t dos_part, bsd_part; + grub_uint8_t *boot_drive; + grub_disk_addr_t *kernel_sector; + boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE); + kernel_sector = (grub_disk_addr_t *) (boot_img + + GRUB_BOOT_MACHINE_KERNEL_SECTOR); + + + install_dos_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART); + install_bsd_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE + + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART); + + /* If we hardcoded drive as part of prefix, we don't want to + override the current setting. */ + if (*install_dos_part != -2) + { + /* Embed information about the installed location. */ + if (root_dev->disk->partition) + { + if (root_dev->disk->partition->parent) + { + if (root_dev->disk->partition->parent->parent) + grub_util_error ("Installing on doubly nested partitions is " + "not supported"); + dos_part = root_dev->disk->partition->parent->number; + bsd_part = root_dev->disk->partition->number; + } + else + { + dos_part = root_dev->disk->partition->number; + bsd_part = -1; + } + } + else + dos_part = bsd_part = -1; + } + else + { + dos_part = grub_le_to_cpu32 (*install_dos_part); + bsd_part = grub_le_to_cpu32 (*install_bsd_part); + } + + grub_util_info ("dos partition is %d, bsd partition is %d", + dos_part, bsd_part); + + *install_dos_part = grub_cpu_to_le32 (dos_part); + *install_bsd_part = grub_cpu_to_le32 (bsd_part); + + /* FIXME: can this be skipped? */ + *boot_drive = 0xFF; + + *kernel_sector = grub_cpu_to_le64 (first_sector); + } +#endif +#ifdef GRUB_MACHINE_IEEE1275 + { + grub_disk_addr_t *kernel_byte; + kernel_byte = (grub_disk_addr_t *) (boot_img + + GRUB_BOOT_AOUT_HEADER_SIZE + + GRUB_BOOT_MACHINE_KERNEL_BYTE); + *kernel_byte = grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS); + } +#endif +} + +#ifdef GRUB_MACHINE_IEEE1275 +#define BOOT_SECTOR 1 +#else +#define BOOT_SECTOR 0 +#endif static void setup (const char *dir, const char *boot_file, const char *core_file, - const char *root, const char *dest, int must_embed, int force, int fs_probe) + const char *root, const char *dest, int must_embed, int force, + int fs_probe) { char *boot_path, *core_path, *core_path_dev, *core_path_dev_full; char *boot_img, *core_img; size_t boot_size, core_size; grub_uint16_t core_sectors; grub_device_t root_dev, dest_dev; - const char *dest_partmap; - int multiple_partmaps; - grub_uint8_t *boot_drive; - grub_disk_addr_t *kernel_sector; - grub_uint16_t *boot_drive_check; struct grub_boot_blocklist *first_block, *block; - grub_int32_t *install_dos_part, *install_bsd_part; - grub_int32_t dos_part, bsd_part; - char *install_prefix; - char *prefix = NULL; char *tmp_img; int i; grub_disk_addr_t first_sector; +#ifdef GRUB_MACHINE_PCBIOS grub_uint16_t current_segment = GRUB_BOOT_MACHINE_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4); +#endif grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE; grub_file_t file; FILE *fp; - struct { grub_uint64_t start; grub_uint64_t end; } embed_region; - embed_region.start = embed_region.end = ~0UL; - auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, unsigned offset, - unsigned length); - auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, unsigned offset, - unsigned length); + auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, + unsigned offset, + unsigned length); + auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, + unsigned offset, + unsigned length); - auto int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk, - const grub_partition_t p); - int NESTED_FUNC_ATTR find_usable_region_msdos (grub_disk_t disk __attribute__ ((unused)), - const grub_partition_t p) - { - /* There's always an embed region, and it starts right after the MBR. */ - embed_region.start = 1; - - if (embed_region.end > grub_partition_get_start (p)) - embed_region.end = grub_partition_get_start (p); - - return 0; - } - - auto int NESTED_FUNC_ATTR find_usable_region_gpt (grub_disk_t disk, - const grub_partition_t p); - int NESTED_FUNC_ATTR find_usable_region_gpt (grub_disk_t disk __attribute__ ((unused)), - const grub_partition_t p) - { - struct grub_gpt_partentry gptdata; - - disk->partition = p->parent; - if (grub_disk_read (disk, p->offset, p->index, - sizeof (gptdata), &gptdata)) - return 0; - - /* If there's an embed region, it is in a dedicated partition. */ - if (! memcmp (&gptdata.type, &grub_gpt_partition_type_bios_boot, 16)) - { - embed_region.start = grub_partition_get_start (p); - embed_region.end = grub_partition_get_start (p) + grub_partition_get_len (p); - - return 1; - } - return 0; - } - - void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, unsigned offset, - unsigned length) + void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, + unsigned offset, + unsigned length) { grub_util_info ("the first sector is <%llu,%u,%u>", sector, offset, length); @@ -148,26 +215,28 @@ setup (const char *dir, first_sector = sector; } - void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, unsigned offset, - unsigned length) + void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, + unsigned offset, + unsigned length) { struct grub_boot_blocklist *prev = block + 1; - grub_util_info ("saving <%llu,%u,%u> with the segment 0x%x", - sector, offset, length, (unsigned) current_segment); + grub_util_info ("saving <%llu,%u,%u>", sector, offset, length); if (offset != 0 || last_length != GRUB_DISK_SECTOR_SIZE) grub_util_error (_("non-sector-aligned data is found in the core file")); if (block != first_block - && (grub_le_to_cpu64 (prev->start) - + grub_le_to_cpu16 (prev->len)) == sector) - prev->len = grub_cpu_to_le16 (grub_le_to_cpu16 (prev->len) + 1); + && (grub_target_to_host64 (prev->start) + + grub_target_to_host16 (prev->len)) == sector) + prev->len = grub_host_to_target16 (grub_target_to_host16 (prev->len) + 1); else { - block->start = grub_cpu_to_le64 (sector); - block->len = grub_cpu_to_le16 (1); - block->segment = grub_cpu_to_le16 (current_segment); + block->start = grub_host_to_target64 (sector); + block->len = grub_host_to_target16 (1); +#ifdef GRUB_MACHINE_PCBIOS + block->segment = grub_host_to_target16 (current_segment); +#endif block--; if (block->len) @@ -175,7 +244,9 @@ setup (const char *dir, } last_length = length; +#ifdef GRUB_MACHINE_PCBIOS current_segment += GRUB_DISK_SECTOR_SIZE >> 4; +#endif } /* Read the boot image by the OS service. */ @@ -187,21 +258,16 @@ setup (const char *dir, boot_img = grub_util_read_image (boot_path); free (boot_path); - /* Set the addresses of variables in the boot image. */ - boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE); - kernel_sector = (grub_disk_addr_t *) (boot_img - + GRUB_BOOT_MACHINE_KERNEL_SECTOR); - boot_drive_check = (grub_uint16_t *) (boot_img - + GRUB_BOOT_MACHINE_DRIVE_CHECK); - core_path = grub_util_get_path (dir, core_file); core_size = grub_util_get_image_size (core_path); core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS); if (core_size < GRUB_DISK_SECTOR_SIZE) grub_util_error (_("the size of `%s' is too small"), core_path); - else if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE) +#ifdef GRUB_MACHINE_PCBIOS + if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE) grub_util_error (_("the size of `%s' is too large"), core_path); +#endif core_img = grub_util_read_image (core_path); @@ -209,19 +275,15 @@ setup (const char *dir, first_block = (struct grub_boot_blocklist *) (core_img + GRUB_DISK_SECTOR_SIZE - sizeof (*block)); - - install_dos_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE - + GRUB_KERNEL_MACHINE_INSTALL_DOS_PART); - install_bsd_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE - + GRUB_KERNEL_MACHINE_INSTALL_BSD_PART); - install_prefix = (char *) (core_img + GRUB_DISK_SECTOR_SIZE + - GRUB_KERNEL_MACHINE_PREFIX); + grub_util_info ("root is `%s', dest is `%s'", root, dest); /* Open the root device and the destination device. */ + grub_util_info ("Opening root"); root_dev = grub_device_open (root); if (! root_dev) grub_util_error ("%s", grub_errmsg); + grub_util_info ("Opening dest"); dest_dev = grub_device_open (dest); if (! dest_dev) grub_util_error ("%s", grub_errmsg); @@ -230,197 +292,171 @@ setup (const char *dir, if (grub_env_set ("root", root) != GRUB_ERR_NONE) grub_util_error ("%s", grub_errmsg); +#ifdef GRUB_MACHINE_PCBIOS /* Read the original sector from the disk. */ tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE); if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img)) grub_util_error ("%s", grub_errmsg); +#endif - if (dest_dev->disk->partition && fs_probe) +#ifdef GRUB_MACHINE_PCBIOS + { + grub_uint16_t *boot_drive_check; + boot_drive_check = (grub_uint16_t *) (boot_img + + GRUB_BOOT_MACHINE_DRIVE_CHECK); + /* Copy the possible DOS BPB. */ + memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START, + tmp_img + GRUB_BOOT_MACHINE_BPB_START, + GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START); + + /* If DEST_DRIVE is a hard disk, enable the workaround, which is + for buggy BIOSes which don't pass boot drive correctly. Instead, + they pass 0x00 or 0x01 even when booted from 0x80. */ + if (!grub_util_biosdisk_is_floppy (dest_dev->disk)) + /* Replace the jmp (2 bytes) with double nop's. */ + *boot_drive_check = 0x9090; + } +#endif + + /* Clean out the blocklists. */ + block = first_block; + while (block->len) { - grub_fs_t fs; - fs = grub_fs_probe (dest_dev); - if (! fs) - grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"), - dest_dev->disk->name); + grub_memset (block, 0, sizeof (block)); - if (! fs->reserved_first_sector) - grub_util_error (_("%s appears to contain a %s filesystem which isn't known to " - "reserve space for DOS-style boot. Installing GRUB there could " - "result in FILESYSTEM DESTRUCTION if valuable data is overwritten " - "by grub-setup (--skip-fs-probe disables this " - "check, use at your own risk)"), dest_dev->disk->name, fs->name); + block--; + + if ((char *) block <= core_img) + grub_util_error ("No terminator in the core image"); } - /* Copy the possible DOS BPB. */ - memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START, - tmp_img + GRUB_BOOT_MACHINE_BPB_START, - GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START); +#ifdef GRUB_MACHINE_PCBIOS + { + grub_partition_map_t dest_partmap = NULL; + grub_partition_t container = dest_dev->disk->partition; + int multiple_partmaps = 0; + grub_err_t err; + grub_disk_addr_t sectors[core_sectors]; + int i; + grub_fs_t fs; - /* Copy the possible partition table. */ - if (dest_dev->disk->has_partitions) - memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, - tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, - GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC); - - free (tmp_img); - - /* If DEST_DRIVE is a hard disk, enable the workaround, which is - for buggy BIOSes which don't pass boot drive correctly. Instead, - they pass 0x00 or 0x01 even when booted from 0x80. */ - if (dest_dev->disk->id & 0x80) - /* Replace the jmp (2 bytes) with double nop's. */ - *boot_drive_check = 0x9090; - - /* If we hardcoded drive as part of prefix, we don't want to - override the current setting. */ - if (*install_dos_part != -2) + /* Unlike root_dev, with dest_dev we're interested in the partition map even + if dest_dev itself is a whole disk. */ + auto int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk, + const grub_partition_t p); + int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)), + const grub_partition_t p) { - /* Embed information about the installed location. */ - if (root_dev->disk->partition) - { - if (root_dev->disk->partition->parent) - { - if (root_dev->disk->partition->parent->parent) - grub_util_error ("Installing on doubly nested partitions is " - "not supported"); - dos_part = root_dev->disk->partition->parent->number; - bsd_part = root_dev->disk->partition->number; - } - else - { - dos_part = root_dev->disk->partition->number; - bsd_part = -1; - } - - if (install_prefix[0] != '(') - { - char *root_part_name; - - root_part_name = - grub_partition_get_name (root_dev->disk->partition); - prefix = xasprintf ("(,%s)%s", root_part_name, install_prefix); - free (root_part_name); - } - } - else - dos_part = bsd_part = -1; - } - else - { - dos_part = grub_le_to_cpu32 (*install_dos_part); - bsd_part = grub_le_to_cpu32 (*install_bsd_part); - } - - grub_util_info ("dos partition is %d, bsd partition is %d", - dos_part, bsd_part); - - if (! dest_dev->disk->has_partitions) - { - grub_util_warn (_("Attempting to install GRUB to a partitionless disk. This is a BAD idea.")); - goto unable_to_embed; - } - - if (dest_dev->disk->partition) - { - grub_util_warn (_("Attempting to install GRUB to a partition instead of the MBR. This is a BAD idea.")); - goto unable_to_embed; - } - - /* Unlike root_dev, with dest_dev we're interested in the partition map even - if dest_dev itself is a whole disk. */ - auto int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk, - const grub_partition_t p); - int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)), - const grub_partition_t p) - { - if (p->parent) + if (p->parent != container) return 0; if (dest_partmap == NULL) - dest_partmap = p->partmap->name; - else if (strcmp (dest_partmap, p->partmap->name) != 0) { - multiple_partmaps = 1; - return 1; + dest_partmap = p->partmap; + return 0; } - return 0; - } - dest_partmap = 0; - multiple_partmaps = 0; - grub_partition_iterate (dest_dev->disk, identify_partmap); - - if (! dest_partmap) - { - grub_util_warn (_("Attempting to install GRUB to a partitionless disk. This is a BAD idea.")); - goto unable_to_embed; - } - if (multiple_partmaps) - { - grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet.")); - goto unable_to_embed; + if (dest_partmap == p->partmap) + return 0; + multiple_partmaps = 1; + return 1; } - if (strcmp (dest_partmap, "msdos") == 0) - grub_partition_iterate (dest_dev->disk, find_usable_region_msdos); - else if (strcmp (dest_partmap, "gpt") == 0) - grub_partition_iterate (dest_dev->disk, find_usable_region_gpt); - else - grub_util_error (_("No DOS-style partitions found")); + grub_partition_iterate (dest_dev->disk, identify_partmap); - if (embed_region.end <= embed_region.start) - { - if (! strcmp (dest_partmap, "msdos")) - grub_util_warn (_("This msdos-style partition label has no post-MBR gap; embedding won't be possible!")); - else - grub_util_warn (_("This GPT partition label has no BIOS Boot Partition; embedding won't be possible!")); - goto unable_to_embed; - } + fs = grub_fs_probe (dest_dev); + if (!fs) + grub_errno = GRUB_ERR_NONE; - if ((unsigned long) core_sectors > embed_region.end - embed_region.start) - { - if (core_sectors > 62) - grub_util_warn (_("Your core.img is unusually large. It won't fit in the embedding area.")); - else /* embed_region.end - embed_region.start < 62 */ - grub_util_warn (_("Your embedding area is unusually small. core.img won't fit in it.")); - goto unable_to_embed; - } +#ifdef GRUB_MACHINE_PCBIOS + if (fs_probe) + { + if (!fs && !dest_partmap) + grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"), + dest_dev->disk->name); + if (fs && !fs->reserved_first_sector) + grub_util_error (_("%s appears to contain a %s filesystem which isn't known to " + "reserve space for DOS-style boot. Installing GRUB there could " + "result in FILESYSTEM DESTRUCTION if valuable data is overwritten " + "by grub-setup (--skip-fs-probe disables this " + "check, use at your own risk)"), dest_dev->disk->name, fs->name); + if (dest_partmap && strcmp (dest_partmap->name, "msdos") != 0 + && strcmp (dest_partmap->name, "gpt") != 0 + && strcmp (dest_partmap->name, "bsd") != 0 + && strcmp (dest_partmap->name, "netbsd") != 0 + && strcmp (dest_partmap->name, "openbsd") != 0 + && strcmp (dest_partmap->name, "sunpc") != 0) + grub_util_error (_("%s appears to contain a %s partition map which isn't known to " + "reserve space for DOS-style boot. Installing GRUB there could " + "result in FILESYSTEM DESTRUCTION if valuable data is overwritten " + "by grub-setup (--skip-fs-probe disables this " + "check, use at your own risk)"), dest_dev->disk->name, dest_partmap->name); + } +#endif - grub_util_info ("the core image will be embedded at sector 0x%llx", embed_region.start); + if (! dest_partmap) + { + grub_util_warn (_("Attempting to install GRUB to a partitionless disk. This is a BAD idea.")); + goto unable_to_embed; + } + if (multiple_partmaps || fs) + { + grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet.")); + goto unable_to_embed; + } - *install_dos_part = grub_cpu_to_le32 (dos_part); - *install_bsd_part = grub_cpu_to_le32 (bsd_part); - if (prefix) - strcpy (install_prefix, prefix); + /* Copy the partition table. */ + if (dest_partmap) + memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, + tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC, + GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC); - /* The first blocklist contains the whole sectors. */ - first_block->start = grub_cpu_to_le64 (embed_region.start + 1); + free (tmp_img); + + if (!dest_partmap->embed) + { + grub_util_warn ("Partition style '%s' doesn't support embeding", + dest_partmap->name); + goto unable_to_embed; + } - /* These are filled elsewhere. Verify them just in case. */ - assert (first_block->len == grub_host_to_target16 (core_sectors - 1)); - assert (first_block->segment == grub_host_to_target16 (GRUB_BOOT_MACHINE_KERNEL_SEG - + (GRUB_DISK_SECTOR_SIZE >> 4))); + err = dest_partmap->embed (dest_dev->disk, core_sectors, + GRUB_EMBED_PCBIOS, sectors); + + if (err) + { + grub_util_warn ("%s", grub_errmsg); + grub_errno = GRUB_ERR_NONE; + goto unable_to_embed; + } - /* Make sure that the second blocklist is a terminator. */ - block = first_block - 1; - block->start = 0; - block->len = 0; - block->segment = 0; + save_first_sector (sectors[0] + grub_partition_get_start (container), + 0, GRUB_DISK_SECTOR_SIZE); - /* Write the core image onto the disk. */ - if (grub_disk_write (dest_dev->disk, embed_region.start, 0, core_size, core_img)) - grub_util_error ("%s", grub_errmsg); + block = first_block; + for (i = 1; i < core_sectors; i++) + save_blocklists (sectors[i] + grub_partition_get_start (container), + 0, GRUB_DISK_SECTOR_SIZE); - /* FIXME: can this be skipped? */ - *boot_drive = 0xFF; + write_rootdev (core_img, root_dev, boot_img, first_sector); - *kernel_sector = grub_cpu_to_le64 (embed_region.start); + /* Make sure that the second blocklist is a terminator. */ + block = first_block - 1; + block->start = 0; + block->len = 0; + block->segment = 0; - /* Write the boot image onto the disk. */ - if (grub_disk_write (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, - boot_img)) - grub_util_error ("%s", grub_errmsg); + /* Write the core image onto the disk. */ + for (i = 0; i < core_sectors; i++) + grub_disk_write (dest_dev->disk, sectors[i], 0, + (core_size - i * GRUB_DISK_SECTOR_SIZE + < GRUB_DISK_SECTOR_SIZE) ? core_size + - i * GRUB_DISK_SECTOR_SIZE + : GRUB_DISK_SECTOR_SIZE, + core_img + i * GRUB_DISK_SECTOR_SIZE); - goto finish; + goto finish; + } +#endif unable_to_embed: @@ -434,6 +470,9 @@ unable_to_embed: if (! force) grub_util_error (_("if you really want blocklists, use --force")); + /* The core image must be put on a filesystem unfortunately. */ + grub_util_info ("will leave the core image on the filesystem"); + /* Make sure that GRUB reads the identical image as the OS. */ tmp_img = xmalloc (core_size); core_path_dev_full = grub_util_get_path (dir, core_file); @@ -454,6 +493,7 @@ unable_to_embed: grub_disk_cache_invalidate_all (); + grub_file_filter_disable_compression (); file = grub_file_open (core_path_dev); if (file) { @@ -515,7 +555,9 @@ unable_to_embed: { block->start = 0; block->len = 0; +#ifdef GRUB_MACHINE_PCBIOS block->segment = 0; +#endif block--; @@ -524,6 +566,7 @@ unable_to_embed: } /* Now read the core image to determine where the sectors are. */ + grub_file_filter_disable_compression (); file = grub_file_open (core_path_dev); if (! file) grub_util_error ("%s", grub_errmsg); @@ -539,20 +582,39 @@ unable_to_embed: != (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE) grub_util_error (_("failed to read the rest sectors of the core image")); +#ifdef GRUB_MACHINE_IEEE1275 + { + char *boot_devpath; + boot_devpath = (char *) (boot_img + + GRUB_BOOT_AOUT_HEADER_SIZE + + GRUB_BOOT_MACHINE_BOOT_DEVPATH); + if (file->device->disk->id != dest_dev->disk->id) + { + const char *dest_ofpath; + dest_ofpath + = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (file->device->disk)); + grub_util_info ("dest_ofpath is `%s'", dest_ofpath); + strncpy (boot_devpath, dest_ofpath, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1); + boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0; + } + else + { + grub_util_info ("non cross-disk install"); + memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END + - GRUB_BOOT_MACHINE_BOOT_DEVPATH); + } + grub_util_info ("boot device path %s", boot_devpath); + } +#endif + grub_file_close (file); free (core_path_dev); free (tmp_img); - *kernel_sector = grub_cpu_to_le64 (first_sector); - - /* FIXME: can this be skipped? */ - *boot_drive = 0xFF; - - *install_dos_part = grub_cpu_to_le32 (dos_part); - *install_bsd_part = grub_cpu_to_le32 (bsd_part); - if (prefix) - strcpy (install_prefix, prefix); + write_rootdev (core_img, root_dev, boot_img, first_sector); /* Write the first two sectors of the core image onto the disk. */ grub_util_info ("opening the core image `%s'", core_path); @@ -563,16 +625,17 @@ unable_to_embed: grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp); fclose (fp); + finish: + /* Write the boot image onto the disk. */ - if (grub_disk_write (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, boot_img)) + if (grub_disk_write (dest_dev->disk, BOOT_SECTOR, + 0, GRUB_DISK_SECTOR_SIZE, boot_img)) grub_util_error ("%s", grub_errmsg); - finish: /* Sync is a Good Thing. */ sync (); - free (prefix); free (core_path); free (core_img); free (boot_img); @@ -644,14 +707,18 @@ get_device_name (char *dev) int main (int argc, char *argv[]) { - char *boot_file = 0; - char *core_file = 0; - char *dir = 0; - char *dev_map = 0; - char *root_dev = 0; - char *dest_dev; + char *boot_file = NULL; + char *core_file = NULL; + char *dir = NULL; + char *dev_map = NULL; + char *root_dev = NULL; + char *dest_dev = NULL; int must_embed = 0, force = 0, fs_probe = 1; +#ifdef GRUB_MACHINE_IEEE1275 + force = 1; +#endif + set_program_name (argv[0]); grub_util_init_nls (); @@ -749,6 +816,13 @@ main (int argc, char *argv[]) /* Initialize all modules. */ grub_init_all (); + grub_lvm_fini (); + grub_mdraid_fini (); + grub_raid_fini (); + grub_raid_init (); + grub_mdraid_init (); + grub_lvm_init (); + dest_dev = get_device_name (argv[optind]); if (! dest_dev) { @@ -759,10 +833,15 @@ main (int argc, char *argv[]) fprintf (stderr, _("Invalid device `%s'.\n"), argv[optind]); usage (1); } + grub_util_info ("transformed OS device `%s' into GRUB device `%s'", + argv[optind], dest_dev); } else - /* For simplicity. */ - dest_dev = xstrdup (dest_dev); + { + /* For simplicity. */ + dest_dev = xstrdup (dest_dev); + grub_util_info ("Using `%s' as GRUB device", dest_dev); + } if (root_dev) { @@ -777,13 +856,18 @@ main (int argc, char *argv[]) } else { - root_dev = grub_util_get_grub_dev (grub_guess_root_device (dir ? : DEFAULT_DIRECTORY)); + char *root_device = grub_guess_root_device (dir ? : DEFAULT_DIRECTORY); + + root_dev = grub_util_get_grub_dev (root_device); if (! root_dev) { grub_util_info ("guessing the root device failed, because of `%s'", grub_errmsg); grub_util_error (_("cannot guess the root device. Specify the option `--root-device'")); } + grub_util_info ("guessed root device `%s' and root_dev `%s' from " + "dir `%s'", root_device, root_dev, + dir ? : DEFAULT_DIRECTORY); } #ifdef __linux__ @@ -815,7 +899,7 @@ main (int argc, char *argv[]) } else #endif - /* Do the real work. */ + /* Do the real work. */ setup (dir ? : DEFAULT_DIRECTORY, boot_file ? : DEFAULT_BOOT_FILE, core_file ? : DEFAULT_CORE_FILE, diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in index 2f39650e9..9ed3fc3a1 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -247,6 +247,12 @@ else make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}" fi +if [ "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ] && [ "x$GRUB_BUTTON_CMOS_CLEAN" = "xyes" ]; then + cat <. - -# Initialize some variables. -transform="@program_transform_name@" - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -sbindir=@sbindir@ -bindir=@bindir@ -libdir=@libdir@ -PACKAGE_NAME=@PACKAGE_NAME@ -PACKAGE_TARNAME=@PACKAGE_TARNAME@ -PACKAGE_VERSION=@PACKAGE_VERSION@ -target_cpu=@target_cpu@ -platform=@platform@ -host_os=@host_os@ -pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` -localedir=@datadir@/locale - -self=`basename $0` - -grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` -grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` -grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` -grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` -rootdir= -grub_prefix=`echo /boot/grub | sed ${transform}` -modules= - -no_floppy= -force_lba= -recheck=no -debug=no - -# Usage: usage -# Print the usage. -usage () { - cat <. -EOF -} - -argument () { - opt=$1 - shift - - if test $# -eq 0; then - echo "$0: option requires an argument -- '$opt'" 1>&2 - exit 1 - fi - echo $1 -} - -# Check the arguments. -while test $# -gt 0 -do - option=$1 - shift - - case "$option" in - -h | --help) - usage - exit 0 ;; - -v | --version) - echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" - exit 0 ;; - - --modules) - modules=`argument $option "$@"`; shift ;; - --modules=*) - modules=`echo "$option" | sed 's/--modules=//'` ;; - - --root-directory) - rootdir=`argument $option "$@"`; shift ;; - --root-directory=*) - rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; - - --grub-mkimage) - grub_mkimage=`argument $option "$@"`; shift ;; - --grub-mkimage=*) - grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; - - --grub-mkdevicemap) - grub_mkdevicemap=`argument $option "$@"`; shift ;; - --grub-mkdevicemap=*) - grub_mkdevicemap=`echo "$option" | sed 's/--grub-mkdevicemap=//'` ;; - - --grub-probe) - grub_probe=`argument $option "$@"`; shift ;; - --grub-probe=*) - grub_probe=`echo "$option" | sed 's/--grub-probe=//'` ;; - - --no-floppy) - no_floppy="--no-floppy" ;; - --recheck) - recheck=yes ;; - # This is an undocumented feature... - --debug) - debug=yes ;; - *) - echo "Unrecognized option \`$option'" 1>&2 - usage - exit 1 - ;; - esac -done - -# If the debugging feature is enabled, print commands. -if test $debug = yes; then - set -x -fi - -# Initialize these directories here, since ROOTDIR was initialized. -case "$host_os" in -netbsd* | openbsd*) - # Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub - # instead of /boot/grub. - grub_prefix=`echo /grub | sed ${transform}` - bootdir=${rootdir} - ;; -*) - # Use /boot/grub by default. - bootdir=${rootdir}/boot - ;; -esac - -grubdir=${bootdir}/`echo grub | sed ${transform}` -device_map=${grubdir}/device.map - -# Check if GRUB is installed. -set $grub_mkimage dummy -if test -f "$1"; then - : -else - echo "$1: Not found." 1>&2 - exit 1 -fi - -set $grub_mkdevicemap dummy -if test -f "$1"; then - : -else - echo "$1: Not found." 1>&2 - exit 1 -fi - -# Create the GRUB directory if it is not present. -mkdir -p "$grubdir" || exit 1 - -# If --recheck is specified, remove the device map, if present. -if test $recheck = yes; then - rm -f $device_map -fi - -# Create the device map file if it is not present. -if test -f "$device_map"; then - : -else - # Create a safe temporary file. - test -n "$mklog" && log_file=`$mklog` - - $grub_mkdevicemap --device-map=$device_map $no_floppy || exit 1 -fi - -# Make sure that there is no duplicated entry. -tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' $device_map \ - | sort | uniq -d | sed -n 1p` -if test -n "$tmp"; then - echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2 - exit 1 -fi - -# Copy the GRUB images to the GRUB directory. -for file in ${grubdir}/*.mod ${grubdir}/*.lst; do - if test -f $file && [ "`basename $file`" != menu.lst ]; then - rm -f $file || exit 1 - fi -done -for file in ${pkglibdir}/*.mod ${pkglibdir}/*.lst; do - cp -f $file ${grubdir} || exit 1 -done - -# Copy gettext files -mkdir -p ${grubdir}/locale/ -for dir in ${localedir}/*; do - if test -f "$dir/LC_MESSAGES/grub.mo"; then - cp -f "$dir/LC_MESSAGES/grub.mo" "${grubdir}/locale/${dir##*/}.mo" - fi -done - -if ! test -f ${grubdir}/grubenv; then - $grub_editenv ${grubdir}/grubenv create -fi - -# Create the core image. First, auto-detect the filesystem module. -fs_module=`$grub_probe --target=fs --device-map=${device_map} ${grubdir}` -if test "x$fs_module" = xfat; then :; else - echo "${grubdir} doesn't look like an EFI partition." 1>&2 - exit 1 -fi - -# Then the partition map module. In order to support partition-less media, -# this command is allowed to fail (--target=fs already grants us that the -# filesystem will be accessible). -partmap_module= -for x in `$grub_probe --target=partmap --device-map=${device_map} ${grubdir} 2> /dev/null`; do - partmap_module="$partmap_module part_$x"; -done - -# Device abstraction module, if any (lvm, raid). -devabstraction_module=`$grub_probe --target=abstraction --device-map=${device_map} ${grubdir}` - -# The order in this list is critical. Be careful when modifying it. -modules="$modules $fs_module $partmap_module $devabstraction_module" - -$grub_mkimage -p "" -O ${target_cpu}-efi --output=${grubdir}/grub.efi $modules || exit 1 - -# Prompt the user to check if the device map is correct. -echo "Installation finished. No error reported." -echo "This is the contents of the device map $device_map." -echo "Check if this is correct or not. If any of the lines is incorrect," -echo "fix it and re-run the script \`$self'." -echo - -cat $device_map - -# Bye. -exit 0 diff --git a/util/ieee1275/grub-install.in b/util/ieee1275/grub-install.in deleted file mode 100644 index 98de5f348..000000000 --- a/util/ieee1275/grub-install.in +++ /dev/null @@ -1,273 +0,0 @@ -#! /bin/sh - -# Install GRUB on your drive. -# Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, Inc. -# -# GRUB is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# GRUB is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GRUB. If not, see . - -# This script uses `ofpathname', which is downloadable from -# http://ppc64-utils.ozlabs.org . - -# Initialize some variables. -transform="@program_transform_name@" - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -sbindir=@sbindir@ -bindir=@bindir@ -libdir=@libdir@ -PACKAGE_NAME=@PACKAGE_NAME@ -PACKAGE_TARNAME=@PACKAGE_TARNAME@ -PACKAGE_VERSION=@PACKAGE_VERSION@ -target_cpu=@target_cpu@ -platform=@platform@ -pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` - -self=`basename $0` - -grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}` -grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}` -grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` -grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}` -rootdir= -grub_prefix=`echo /boot/grub | sed ${transform}` -modules= - -install_device= -debug=no -update_nvram=yes - -ofpathname=`which ofpathname` -nvsetenv=`which nvsetenv` - -# Usage: usage -# Print the usage. -usage () { - cat <. -EOF -} - -argument () { - opt=$1 - shift - - if test $# -eq 0; then - echo "$0: option requires an argument -- '$opt'" 1>&2 - exit 1 - fi - echo $1 -} - -# Check the arguments. -while test $# -gt 0 -do - option=$1 - shift - - case "$option" in - -h | --help) - usage - exit 0 ;; - -v | --version) - echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" - exit 0 ;; - - --modules) - modules=`argument $option "$@"`; shift ;; - --modules=*) - modules=`echo "$option" | sed 's/--modules=//'` ;; - - --root-directory) - rootdir=`argument $option "$@"`; shift ;; - --root-directory=*) - rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; - - --grub-mkdevicemap) - grub_mkdevicemap=`argument $option "$@"`; shift ;; - --grub-mkdevicemap=*) - grub_mkdevicemap=`echo "$option" | sed 's/--grub-mkdevicemap=//'` ;; - - --grub-mkimage) - grub_mkimage=`argument $option "$@"`; shift ;; - --grub-mkimage=*) - grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;; - - --grub-probe) - grub_probe=`argument $option "$@"`; shift ;; - --grub-probe=*) - grub_probe=`echo "$option" | sed 's/--grub-probe=//'` ;; - - --no-nvram) - update_nvram=no ;; - # This is an undocumented feature... - --debug) - debug=yes ;; - -*) - echo "Unrecognized option \`$option'" 1>&2 - usage - exit 1 - ;; - *) - if test "x$install_device" != x; then - echo "More than one install_devices?" 1>&2 - usage - exit 1 - fi - install_device="${option}" ;; - esac -done - -# If the debugging feature is enabled, print commands. -if test $debug = yes; then - set -x -fi - -# Initialize these directories here, since ROOTDIR was initialized. -bootdir=${rootdir}/boot -grubdir=${bootdir}/`echo grub | sed ${transform}` -device_map=${grubdir}/device.map - -set $grub_mkimage dummy -if test -f "$1"; then - : -else - echo "$1: Not found." 1>&2 - exit 1 -fi - -# Find the partition at the right mount point. -install_device=`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${grubdir}` - -if test "x$install_device" = "x`$grub_mkdevicemap --device-map=/dev/stdout | $grub_probe --target=device --device-map=/dev/stdin ${bootdir}`"; then - echo "$grubdir must be a mount point." - exit 1 -fi -# XXX warn on firmware-unreadable filesystems? - -# Create the GRUB directory if it is not present. -mkdir -p "$grubdir" || exit 1 - -# Create the device map file if it is not present. -if test -f "$device_map"; then - : -else - # Create a safe temporary file. - test -n "$mklog" && log_file=`$mklog` - - $grub_mkdevicemap --device-map=$device_map $no_floppy || exit 1 -fi - -# Copy the GRUB images to the GRUB directory. -for file in ${grubdir}/*.mod ${grubdir}/*.lst ; do - if test -f $file; then - rm -f $file || exit 1 - fi -done -for file in ${pkglibdir}/*.mod ${pkglibdir}/*.lst ; do - cp -f $file ${grubdir} || exit 1 -done - -if ! test -f ${grubdir}/grubenv; then - $grub_editenv ${grubdir}/grubenv create -fi - -# Create the core image. First, auto-detect the filesystem module. -fs_module=`$grub_probe --target=fs --device-map=${device_map} ${grubdir}` -if test "x$fs_module" = x -a "x$modules" = x; then - echo "Auto-detection of a filesystem module failed." 1>&2 - echo "Please specify the module with the option \`--modules' explicitly." 1>&2 - exit 1 -fi - -# Then the partition map module. In order to support partition-less media, -# this command is allowed to fail (--target=fs already grants us that the -# filesystem will be accessible). -partmap_module= -for x in `$grub_probe --target=partmap --device-map=${device_map} ${grubdir} 2> /dev/null`; do - partmap_module="$partmap_module part_$x"; -done - -# Device abstraction module, if any (lvm, raid). -devabstraction_module=`$grub_probe --target=abstraction --device-map=${device_map} ${grubdir}` - -modules="$modules $fs_module $partmap_module $devabstraction_module" - -# Now perform the installation. -"$grub_mkimage" -O ${target_cpu}-ieee1275 --directory=${pkglibdir} --output=${grubdir}/grub $modules || exit 1 - -if test $update_nvram = yes; then - set $ofpathname dummy - if test -f "$1"; then - : - else - echo "$1: Not found." 1>&2 - exit 1 - fi - - set $nvsetenv dummy - if test -f "$1"; then - : - else - echo "$1: Not found." 1>&2 - exit 1 - fi - - # Get the Open Firmware device tree path translation. - dev=`echo $install_device | sed -e 's/\/dev\///' -e 's/[0-9]\+//'` - partno=`echo $install_device | sed -e 's/.*[^0-9]\([0-9]\+\)$/\1/'` - ofpath=`$ofpathname $dev` || { - echo "Couldn't find Open Firmware device tree path for $dev." - echo "You will have to set boot-device manually." - exit 1 - } - - # Point boot-device at the new grub install - boot_device="$ofpath:$partno,\\grub" - "$nvsetenv" boot-device "$boot_device" || { - echo "$nvsetenv failed." - echo "You will have to set boot-device manually. At the Open Firmware prompt, type:" - echo " setenv boot-device $boot_device" - exit 1 - } -fi - -# Prompt the user to check if the device map is correct. -echo "Installation finished. No error reported." -echo "This is the contents of the device map $device_map." -echo "Check if this is correct or not. If any of the lines is incorrect," -echo "fix it and re-run the script \`$self'." -echo - -cat $device_map - -# Bye. -exit 0 diff --git a/util/raid.c b/util/raid.c index edf865aa7..dac19a935 100644 --- a/util/raid.c +++ b/util/raid.c @@ -22,40 +22,19 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include -static char * -grub_util_getdiskname (int major, int minor) -{ - char *name = xmalloc (15); - - if (major == LOOP_MAJOR) - sprintf (name, "/dev/loop%d", minor); - else if (major == IDE0_MAJOR) - sprintf (name, "/dev/hd%c", 'a' + minor / 64); - else if (major == IDE1_MAJOR) - sprintf (name, "/dev/hd%c", 'c' + minor / 64); - else if (major == IDE2_MAJOR) - sprintf (name, "/dev/hd%c", 'e' + minor / 64); - else if (major == IDE3_MAJOR) - sprintf (name, "/dev/hd%c", 'g' + minor / 64); - else if (major == SCSI_DISK0_MAJOR) - sprintf (name, "/dev/sd%c", 'a' + minor / 16); - else - grub_util_error ("unknown device number: %d, %d", major, minor); - - return name; -} - char ** grub_util_raid_getmembers (char *name) { @@ -100,7 +79,8 @@ grub_util_raid_getmembers (char *name) if (disk.state & (1 << MD_DISK_ACTIVE)) { - devicelist[j] = grub_util_getdiskname (disk.major, disk.minor); + devicelist[j] = grub_find_device (NULL, + makedev (disk.major, disk.minor)); j++; } } diff --git a/util/sparc64/ieee1275/grub-setup.c b/util/sparc64/ieee1275/grub-setup.c deleted file mode 100644 index 94734b977..000000000 --- a/util/sparc64/ieee1275/grub-setup.c +++ /dev/null @@ -1,635 +0,0 @@ -/* grub-setup.c - make GRUB usable */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define _GNU_SOURCE 1 -#include - -#include "progname.h" - -/* This program fills in various fields inside of the 'boot' and 'core' - * image files. - * - * The 'boot' image needs to know the OBP path name of the root - * device. It also needs to know the initial block number of - * 'core' (which is 'diskboot' concatenated with 'kernel' and - * all the modules, this is created by grub-mkimage). This resulting - * 'boot' image is 512 bytes in size and is placed in the second block - * of a partition. - * - * The initial 'diskboot' block acts as a loader for the actual GRUB - * kernel. It contains the loading code and then a block list. - * - * The block list of 'core' starts at the end of the 'diskboot' image - * and works it's way backwards towards the end of the code of 'diskboot'. - * - * We patch up the images with the necessary values and write out the - * result. - */ - -#define DEFAULT_BOOT_FILE "boot.img" -#define DEFAULT_CORE_FILE "core.img" - -#define grub_target_to_host16(x) grub_be_to_cpu16(x) -#define grub_target_to_host32(x) grub_be_to_cpu32(x) -#define grub_target_to_host64(x) grub_be_to_cpu64(x) -#define grub_host_to_target16(x) grub_cpu_to_be16(x) -#define grub_host_to_target32(x) grub_cpu_to_be32(x) -#define grub_host_to_target64(x) grub_cpu_to_be64(x) - -/* This is the blocklist used in the diskboot image. */ -struct boot_blocklist -{ - grub_uint64_t start; - grub_uint32_t len; -} __attribute__ ((packed)); - -static void -setup (const char *prefix, const char *dir, - const char *boot_file, const char *core_file, - const char *root, const char *dest) -{ - char *boot_path, *core_path; - char *boot_img, *core_img; - size_t boot_size, core_size; - grub_uint16_t core_sectors; - grub_device_t root_dev, dest_dev; - char *boot_devpath; - grub_disk_addr_t *kernel_byte; - struct boot_blocklist *first_block, *block; - char *tmp_img; - int i; - grub_disk_addr_t first_sector; - grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE; - grub_file_t file; - FILE *fp; - struct { grub_uint64_t start; grub_uint64_t end; } embed_region; - embed_region.start = embed_region.end = ~0UL; - - auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, - unsigned int offset, - unsigned int length); - auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, - unsigned int offset, - unsigned int length); - - void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, - unsigned int offset, - unsigned int length) - { - grub_util_info ("first sector is <%llu,%u,%u>", sector, offset, length); - - if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE) - grub_util_error ("the first sector of the core file " - "is not sector-aligned"); - - first_sector = sector; - } - - void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, - unsigned int offset, - unsigned int length) - { - struct boot_blocklist *prev = block + 1; - - grub_util_info ("saving <%llu,%u,%u>", sector, offset, length); - - if (offset != 0 || last_length != GRUB_DISK_SECTOR_SIZE) - grub_util_error ("non-sector-aligned data is found in the core file"); - - if (block != first_block - && (grub_be_to_cpu64 (prev->start) - + grub_be_to_cpu16 (prev->len)) == sector) - prev->len = grub_cpu_to_be16 (grub_be_to_cpu16 (prev->len) + 1); - else - { - block->start = grub_cpu_to_be64 (sector); - block->len = grub_cpu_to_be16 (1); - - block--; - if (block->len) - grub_util_error ("the sectors of the core file are too fragmented"); - } - - last_length = length; - } - - /* Read the boot image by the OS service. */ - boot_path = grub_util_get_path (dir, boot_file); - boot_size = grub_util_get_image_size (boot_path); - if (boot_size != GRUB_DISK_SECTOR_SIZE) - grub_util_error ("the size of `%s' is not %d", - boot_path, GRUB_DISK_SECTOR_SIZE); - boot_img = grub_util_read_image (boot_path); - free (boot_path); - - /* Set the addresses of variables in the boot image. */ - boot_devpath = (char *) (boot_img - + GRUB_BOOT_AOUT_HEADER_SIZE - + GRUB_BOOT_MACHINE_BOOT_DEVPATH); - kernel_byte = (grub_disk_addr_t *) (boot_img - + GRUB_BOOT_AOUT_HEADER_SIZE - + GRUB_BOOT_MACHINE_KERNEL_BYTE); - - core_path = grub_util_get_path (dir, core_file); - core_size = grub_util_get_image_size (core_path); - core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) - >> GRUB_DISK_SECTOR_BITS); - if (core_size < GRUB_DISK_SECTOR_SIZE) - grub_util_error ("the size of `%s' is too small", core_path); - - core_img = grub_util_read_image (core_path); - free (core_path); - - /* Have FIRST_BLOCK to point to the first blocklist. */ - first_block = (struct boot_blocklist *) (core_img - + GRUB_DISK_SECTOR_SIZE - - sizeof (*block)); - - grub_util_info ("root is `%s', dest is `%s'", root, dest); - - /* Open the root device and the destination device. */ - grub_util_info ("Opening root"); - root_dev = grub_device_open (root); - if (! root_dev) - grub_util_error ("%s", grub_errmsg); - - grub_util_info ("Opening dest"); - dest_dev = grub_device_open (dest); - if (! dest_dev) - grub_util_error ("%s", grub_errmsg); - - grub_util_info ("setting the root device to `%s'", root); - if (grub_env_set ("root", root) != GRUB_ERR_NONE) - grub_util_error ("%s", grub_errmsg); - - /* The core image must be put on a filesystem unfortunately. */ - grub_util_info ("will leave the core image on the filesystem"); - - /* Make sure that GRUB reads the identical image as the OS. */ - tmp_img = xmalloc (core_size); - core_path = grub_util_get_path (prefix, core_file); - - /* It is a Good Thing to sync two times. */ - sync (); - sync (); - -#define MAX_TRIES 5 - - for (i = 0; i < MAX_TRIES; i++) - { - grub_util_info ("attempting to read the core image `%s' from GRUB%s", - core_path, (i == 0) ? "" : " again"); - - grub_disk_cache_invalidate_all (); - - file = grub_file_open (core_path); - if (file) - { - if (grub_file_size (file) != core_size) - grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)", - (int) grub_file_size (file), (int) core_size); - else if (grub_file_read (file, tmp_img, core_size) - != (grub_ssize_t) core_size) - grub_util_info ("succeeded in opening the core image but cannot read %d bytes", - (int) core_size); - else if (memcmp (core_img, tmp_img, core_size) != 0) - { -#if 0 - FILE *dump; - FILE *dump2; - - dump = fopen ("dump.img", "wb"); - if (dump) - { - fwrite (tmp_img, 1, core_size, dump); - fclose (dump); - } - - dump2 = fopen ("dump2.img", "wb"); - if (dump2) - { - fwrite (core_img, 1, core_size, dump2); - fclose (dump2); - } - -#endif - grub_util_info ("succeeded in opening the core image but the data is different"); - } - else - { - grub_file_close (file); - break; - } - - grub_file_close (file); - } - else - grub_util_info ("couldn't open the core image"); - - if (grub_errno) - grub_util_info ("error message = %s", grub_errmsg); - - grub_errno = GRUB_ERR_NONE; - sync (); - sleep (1); - } - - if (i == MAX_TRIES) - grub_util_error ("cannot read `%s' correctly", core_path); - - /* Clean out the blocklists. */ - block = first_block; - while (block->len) - { - block->start = 0; - block->len = 0; - - block--; - - if ((char *) block <= core_img) - grub_util_error ("no terminator in the core image"); - } - - /* Now read the core image to determine where the sectors are. */ - file = grub_file_open (core_path); - if (! file) - grub_util_error ("%s", grub_errmsg); - - file->read_hook = save_first_sector; - if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE) - != GRUB_DISK_SECTOR_SIZE) - grub_util_error ("failed to read the first sector of the core image"); - - block = first_block; - file->read_hook = save_blocklists; - if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE) - != (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE) - grub_util_error ("failed to read the rest sectors of the core image"); - - if (file->device->disk->id != dest_dev->disk->id) - { - const char *dest_ofpath; - dest_ofpath - = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (file->device->disk)); - grub_util_info ("dest_ofpath is `%s'", dest_ofpath); - strncpy (boot_devpath, dest_ofpath, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END - - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1); - boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END - - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0; - } - else - { - grub_util_info ("non cross-disk install"); - memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END - - GRUB_BOOT_MACHINE_BOOT_DEVPATH); - } - - grub_file_close (file); - - free (core_path); - free (tmp_img); - - *kernel_byte = grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS); - - grub_util_info ("boot device path %s, prefix is %s, dest is %s", - boot_devpath, prefix, dest); - - /* Write the first two sectors of the core image onto the disk. */ - core_path = grub_util_get_path (dir, core_file); - grub_util_info ("opening the core image `%s'", core_path); - fp = fopen (core_path, "r+b"); - if (! fp) - grub_util_error ("cannot open `%s'", core_path); - - grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE, fp); - fclose (fp); - free (core_path); - - /* Write the boot image onto the disk. */ - if (grub_disk_write (dest_dev->disk, 1, 0, GRUB_DISK_SECTOR_SIZE, boot_img)) - grub_util_error ("%s", grub_errmsg); - - /* Sync is a Good Thing. */ - sync (); - - free (core_img); - free (boot_img); - grub_device_close (dest_dev); - grub_device_close (root_dev); -} - -static struct option options[] = - { - {"boot-image", required_argument, 0, 'b'}, - {"core-image", required_argument, 0, 'c'}, - {"directory", required_argument, 0, 'd'}, - {"device-map", required_argument, 0, 'm'}, - {"root-device", required_argument, 0, 'r'}, - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'V'}, - {"verbose", no_argument, 0, 'v'}, - {0, 0, 0, 0} - }; - -static void -usage (int status) -{ - if (status) - fprintf (stderr, "Try `%s --help' for more information.\n", program_name); - else - printf ("\ -Usage: %s [OPTION]... DEVICE\n\ -\n\ -Set up images to boot from DEVICE.\n\ -DEVICE must be a GRUB device (e.g. `(hd0,1)').\n\ -\n\ -You should not normally run %s directly. Use grub-install instead.\n\ -\n\ - -b, --boot-image=FILE use FILE as the boot image [default=%s]\n\ - -c, --core-image=FILE use FILE as the core image [default=%s]\n\ - -d, --directory=DIR use GRUB files in the directory DIR [default=%s]\n\ - -m, --device-map=FILE use FILE as the device map [default=%s]\n\ - -r, --root-device=DEV use DEV as the root device [default=guessed]\n\ - -h, --help display this message and exit\n\ - -V, --version print version information and exit\n\ - -v, --verbose print verbose messages\n\ -\n\ -Report bugs to <%s>.\n\ -", program_name, program_name, - DEFAULT_BOOT_FILE, DEFAULT_CORE_FILE, DEFAULT_DIRECTORY, - DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); - - exit (status); -} - -struct grub_setup_info -{ - char *boot_file; - char *core_file; - char *dir; - char *dev_map; - char *root_dev; - char *prefix; - char *dest_dev; -}; - -static void -init_info (struct grub_setup_info *gp) -{ - gp->boot_file = NULL; - gp->core_file = NULL; - gp->dir = NULL; - gp->dev_map = NULL; - gp->root_dev = NULL; - gp->prefix = NULL; - gp->dest_dev = NULL; -} - -static int -parse_options (struct grub_setup_info *gp, int argc, char *argv[]) -{ - while (1) - { - int c = getopt_long (argc, argv, "b:c:d:m:r:hVv", options, 0); - - if (c == -1) - break; - else - switch (c) - { - case 'b': - if (gp->boot_file) - free (gp->boot_file); - - gp->boot_file = xstrdup (optarg); - break; - - case 'c': - if (gp->core_file) - free (gp->core_file); - - gp->core_file = xstrdup (optarg); - break; - - case 'd': - if (gp->dir) - free (gp->dir); - - gp->dir = xstrdup (optarg); - break; - - case 'm': - if (gp->dev_map) - free (gp->dev_map); - - gp->dev_map = xstrdup (optarg); - break; - - case 'r': - if (gp->root_dev) - free (gp->root_dev); - - gp->root_dev = xstrdup (optarg); - break; - - case 'h': - usage (0); - break; - - case 'V': - printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); - return 0; - - case 'v': - verbosity++; - break; - - default: - usage (1); - break; - } - } - - if (verbosity > 1) - grub_env_set ("debug", "all"); - - if (optind >= argc) - { - fprintf (stderr, "No device is specified.\n"); - usage (1); - } - - if (optind + 1 != argc) - { - fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); - usage (1); - } - return 1; -} - -static char * -get_device_name (char *dev) -{ - size_t len = strlen (dev); - - if (dev[0] != '(' || dev[len - 1] != ')') - return 0; - - dev[len - 1] = '\0'; - return dev + 1; -} - -static void -find_dest_dev (struct grub_setup_info *gp, char *argv[]) -{ - gp->dest_dev = get_device_name (argv[optind]); - if (! gp->dest_dev) - { - /* Possibly, the user specified an OS device file. */ - gp->dest_dev = grub_util_get_grub_dev (argv[optind]); - if (! gp->dest_dev) - { - fprintf (stderr, "Invalid device `%s'.\n", argv[optind]); - usage (1); - } - grub_util_info ("transformed OS device `%s' into GRUB device `%s'", - argv[optind], gp->dest_dev); - } - else - { - /* For simplicity. */ - gp->dest_dev = xstrdup (gp->dest_dev); - grub_util_info ("Using `%s' as GRUB device", gp->dest_dev); - } -} - -static void -check_root_dev (struct grub_setup_info *gp) -{ - if (gp->root_dev) - { - char *tmp = get_device_name (gp->root_dev); - - if (! tmp) - grub_util_error ("invalid root device `%s'", gp->root_dev); - - tmp = xstrdup (tmp); - free (gp->root_dev); - gp->root_dev = tmp; - } - else - { - char *dir = gp->dir ? gp->dir : DEFAULT_DIRECTORY; - char *root_device = grub_guess_root_device (dir); - - gp->root_dev = grub_util_get_grub_dev (root_device); - if (! gp->root_dev) - { - grub_util_info ("guessing the root device failed, because of `%s'", - grub_errmsg); - grub_util_error ("cannot guess the root device. " - "Specify the option `--root-device'"); - } - grub_util_info ("guessed root device `%s' and root_dev `%s' from " - "dir `%s'", root_device, gp->root_dev, dir); - } -} - -static void -free_memory (struct grub_setup_info *gp) -{ - free (gp->boot_file); - free (gp->core_file); - free (gp->dir); - free (gp->dev_map); - free (gp->root_dev); - free (gp->prefix); - free (gp->dest_dev); -} - -int -main (int argc, char *argv[]) -{ - struct grub_setup_info ginfo; - - set_program_name (argv[0]); - - grub_util_init_nls (); - - init_info (&ginfo); - if (!parse_options (&ginfo, argc, argv)) - return 0; - - /* Initialize the emulated biosdisk driver. */ - grub_util_biosdisk_init (ginfo.dev_map ? ginfo.dev_map : DEFAULT_DEVICE_MAP); - - /* Initialize all modules. */ - grub_init_all (); - - find_dest_dev (&ginfo, argv); - - ginfo.prefix = grub_make_system_path_relative_to_its_root (ginfo.dir ? - : DEFAULT_DIRECTORY); - - check_root_dev (&ginfo); - - /* Do the real work. */ - setup (ginfo.prefix, - ginfo.dir ? ginfo.dir : DEFAULT_DIRECTORY, - ginfo.boot_file ? ginfo.boot_file : DEFAULT_BOOT_FILE, - ginfo.core_file ? ginfo.core_file : DEFAULT_CORE_FILE, - ginfo.root_dev, ginfo.dest_dev); - - /* Free resources. */ - grub_fini_all (); - - free_memory (&ginfo); - - return 0; -}