diff --git a/.bzrignore b/.bzrignore index 7347c0950..cdc55d00b 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1,5 +1,6 @@ 00_header 10_* +20_linux_xen 30_os-prober 40_custom 41_custom @@ -39,6 +40,7 @@ grub-fstest grub_fstest_init.c grub_fstest_init.h grub-install +grub-macho2img grub-mk* grub-pbkdf2 grub-pe2elf diff --git a/ChangeLog b/ChangeLog index 1fdf98bf1..bf1a0cfbf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,730 @@ +2010-08-18 Colin Watson + + * configure.ac: Move AM_INIT_AUTOMAKE after AC_CANONICAL_TARGET to + fix warnings from Autoconf. + +2010-08-18 Colin Watson + + * acinclude.m4 (grub_ASM_USCORE): Use a more accurate grep pattern, + to avoid false positives with some assemblers that output things + like "someprefix_func" as part of their output. + +2010-08-15 Robert Millan + + * kern/emu/misc.c (grub_get_libzfs_handle): Handle libzfs_init() + errors. + * kern/emu/getroot.c (find_root_device_from_libzfs): Handle + grub_get_libzfs_handle() errors. + +2010-08-14 Robert Millan + + * kern/emu/misc.c (grub_find_zpool_from_dir): Abort function if + filesystem is not ZFS. + +2010-08-12 BVK Chaitanya + + Fix for misspelled color names defaulting to black/black (bug + reported by Doug Nazar) + + * include/grub/normal.h (grub_parse_color_name_pair): Add return + status to prototype. + * normal/color.c (grub_parse_color_name_pair): Return failure + status. + (grub_env_write_color_normal): Ignore bad color names. + (grub_env_write_color_highlight): Likewise. + * normal/main.c (GRUB_MOD_INIT): Set default color names. + +2010-08-12 BVK Chaitanya + + "shift" command support to GRUB script. + + * include/grub/script_sh.h (grub_script_shift): New prototype. + * script/execute.c (grub_script_shift): New function. + * script/main.c (grub_script_init): Register shift command. + (grub_script_fini): Unregister shift command. + * util/grub-script-check.c (grub_script_cmd_shift): New function. + + * tests/grub_script_shift.in: New testcase. + * conf/tests.rmk: Rules for new testcase. + +2010-08-12 BVK Chaitanya + + "continue" command support to GRUB script. + + * script/execute.c (grub_script_execute_cmdwhile): Continue support. + (grub_script_break): Continue support. + * script/main.c (grub_script_init): Register continue command. + (grub_script_fini): Unregister continue command. + + * tests/grub_script_continue.in: New testcase. + * conf/tests.rmk: Rules for new testcase. + +2010-08-12 BVK Chaitanya + + "break" command support to GRUB script. + + * conf/common.rmk: Rule updates to grub-script-check. + * include/grub/misc.h (grub_min): New function. + * include/grub/script_sh.h (grub_script_init): New prototype. + (grub_script_fini): New prototype. + (grub_script_break): New prototype. + * script/main.c (grub_script_init): New function. + (grub_script_fini): New function. + * script/execute.c (grub_script_break): New function. + * normal/main.c: Calls to grub_script_{init,fini}. + * util/grub-script-check.c (grub_script_break): New function. + + * tests/grub_script_break.in: New testcase. + * conf/tests.rmk: Rules for new test case. + +2010-08-12 BVK Chaitanya + + Function parameters support to GRUB script. + + * script/yylex.l (VARIABLE): Regular expression update. + * script/function.c (grub_script_function_call): Moved ... + * script/execute.c (grub_script_function_call): ... to here. + (grub_script_execute_arglist_to_argv): Removed. + (grub_script_arglist_to_argv): New function. + * script/argv.c: New file. + (grub_script_argv_free): New function. + (grub_script_argv_next): Likewise. + (grub_script_argv_append): Likewise. + (grub_script_argv_split_append): Likewise. + * include/grub/script_sh.h (grub_script_argv): New struct. + (grub_script_argv_free): New function. + (grub_script_argv_next): Likewise. + (grub_script_argv_append): Likewise. + (grub_script_argv_split_append): Likewise. + + * conf/common.rmk (normal.mod): New source script/argv.c. + + * tests/grub_script_echo1.in: More tests. + * tests/grub_script_vars1.in: Likewise. + * tests/grub_script_functions.in: New test case. + * conf/tests.rmk: Rules for new testcase. + +2010-08-12 BVK Chaitanya + + Remove grub_script_cmdblock struct. + + * include/grub/script_sh.h: Remove grub_script_cmdblock. + * script/parser.y: Likewise. + * script/execute.c: Rename cmdblock suffix to cmdlist. + * script/script.c: Likewise. + * util/grub-script-check.c: Likewise. + +2010-08-11 Yves Blusseau + + * .bzrignore: add grub-macho2img + +2010-08-11 Vladimir Serbinenko + + * kern/i386/qemu/init.c (grub_qemu_init_cirrus): Fix compilation error. + +2010-08-11 Vladimir Serbinenko + + Remove the dump of sm712 initialisation sequence. + + * include/grub/pci.h (GRUB_PCI_CLASS_SUBCLASS_VGA): New const. + * include/grub/vga.h (GRUB_VGA_IO_ARX_READ): New register. + (GRUB_VGA_IO_MISC_WRITE): Likewise. + (GRUB_VGA_CR_*): Added many registers. + (GRUB_VGA_SR_*): Likewise. + (GRUB_VGA_GR_*): Likewise. + (grub_vga_write_arx): New function. + (grub_video_hw_config): New struct. + (grub_vga_set_geometry): New function. + * kern/i386/qemu/init.c (load_palette): Use grub_vga_write_arx and + GRUB_PCI_CLASS_SUBCLASS_VGA. + * video/cirrus.c (grub_video_cirrus_setup): Use grub_vga_set_geometry. + * video/sm712.c (grub_sm712_write_reg): New function + (grub_sm712_read_reg): Likewise. + (grub_sm712_sr_write): Likewise. + (grub_sm712_gr_write): Likewise. + (grub_sm712_cr_write): Likewise. + (grub_sm712_write_arx): Likewise. + (grub_sm712_cr_shadow_write): Likewise. + (grub_sm712_write_dda_lookup): Likewise. + (grub_video_sm712_setup): Initialise the video rather then + blindly replay the dump. + (main) [TEST]: Add a routine to be able to compile as standalone for + tests. + * video/sm712_init.c (sm712_init): Removed. + (sm712_sr_seq1): New array. + (sm712_sr_seq2): Likewise. + +2010-08-10 Vladimir Serbinenko + + * include/grub/vga.h: Add missing grub/pci.h include. + +2010-08-10 Yves Blusseau + + * util/grub-macho2img.c (main): fix typo + +2010-08-10 Vladimir Serbinenko + + * include/grub/vga.h (grub_vga_gr_write): Add GRUB_MACHINE_PCI_IO_BASE. + (grub_vga_gr_read): Likewise. + (grub_vga_cr_write): Likewise. + (grub_vga_cr_read): Likewise. + (grub_vga_sr_write): Likewise. + (grub_vga_sr_read): Likewise. + (grub_vga_palette_read): Likewise. + (grub_vga_palette_write): Likewise. + * video/sm712.c (GRUB_SM712_REG_BASE): New definition. + (grub_sm712_sr_read): New function. + (grub_video_sm712_setup): Use grub_vga_sr_write and grub_sm712_sr_read. + * video/sm712_init.c (sm712_init): Substract GRUB_MACHINE_PCI_IO_BASE. + +2010-08-09 Robert Millan + + * kern/emu/misc.c (grub_make_system_path_relative_to_its_root): Filter + out unused variables on non-ZFS build. + +2010-08-08 Robert Millan + + Fix path generation for sub-filesystems in ZFS. + + * kern/emu/misc.c (grub_make_system_path_relative_to_its_root): Add + missing slash. + +2010-08-08 Robert Millan + + * util/grub-fstest.c (read_file, cmd_cmp): Improve error message. + +2010-08-08 Robert Millan + + * util/grub.d/10_kfreebsd.in: When files required for ZFS do not + exist, issue a proper error message (rely on `ls' for translated + strings). + +2010-08-08 Robert Millan + + Fix grub-probe invocation. + + * util/grub.d/10_kfreebsd.in: s/label/fs_label/g. + +2010-08-04 Robert Millan + + * configure.ac: Remove checks for getfsstat() and getmntany(). + Add checks for `' and `'. + * kern/emu/misc.c [HAVE_GETMNTANY]: Remove `'. + [HAVE_SYS_PARAM_H]: Include `'. + [HAVE_SYS_MOUNT_H]: Include `'. + [HAVE_LIBZFS && HAVE_LIBNVPAIR] (find_mount_point_from_dir): Remove + function. + (grub_find_zpool_from_dir): Use statfs() instead of indirect matching + via find_mount_point_from_dir() and getfsstat() / getmntany(). + +2010-08-04 Robert Millan + + * include/grub/emu/misc.h (grub_find_mount_point_from_dir) + (grub_find_zpool_from_mount_point): Merge into ... + (grub_find_zpool_from_dir): ... this. + * kern/emu/misc.c: Likewise. + + * kern/emu/misc.c + (grub_make_system_path_relative_to_its_root): Replace + grub_find_mount_point_from_dir() / grub_find_zpool_from_mount_point() + with grub_find_zpool_from_dir(). + * kern/emu/getroot.c (find_root_device_from_libzfs): Likewise. + +2010-08-04 Robert Millan + + Support OpenSolaris in ZFS device resolution. + + * configure.ac: Check for getmntany(). + * kern/emu/misc.c [HAVE_GETMNTANY]: Include `'. + [HAVE_GETMNTANY] (grub_find_zpool_from_mount_point): Add OpenSolaris + support. + +2010-08-03 Robert Millan + + Fix grub-emu build. + + * include/grub/util/misc.h: Move `' to ... + * include/grub/emu/misc.h: ... here. + + * include/grub/util/misc.h (grub_get_libzfs_handle): Move function ... + * include/grub/emu/misc.h (grub_get_libzfs_handle): ... here. + + * util/misc.c: Remove `'. + [HAVE_LIBZFS] (libzfs_handle, fini_libzfs) + (grub_get_libzfs_handle): Move to ... + * kern/emu/misc.c [HAVE_LIBZFS] (__libzfs_handle, fini_libzfs) + (grub_get_libzfs_handle): ... here. + +2010-08-03 BVK Chaitanya + + * script/execute.c (grub_script_execute_cmdline): Check for NULL + as command name case. + +2010-08-02 Colin Watson + + * disk/raid.c (insert_array): Select unique numbers for named arrays + as well, for use as keys in the disk cache. + +2010-08-01 Robert Millan + + * util/grub.d/10_kfreebsd.in: Initialize ${kfreebsd_device} as the + kFreeBSD device name, except on ZFS where the filesystem label is + used. + (kfreebsd_entry): On ZFS root, load `opensolaris.ko', `zfs.ko' and + `/boot/zfs/zpool.cache'. + Set mountfrom kernel variable using ${kfreebsd_device}. + +2010-08-01 Robert Millan + + Make it even harder to use uninitialized `libzfs_handle' (and + make the interface a bit simpler). + + * include/grub/util/misc.h (grub_util_init_libzfs) + (libzfs_handle): Remove. + (grub_get_libzfs_handle): New prototype. + + * util/misc.c [HAVE_LIBZFS] (libzfs_handle): Add `static' + attribute. + (grub_util_init_libzfs): Remove. + (grub_get_libzfs_handle): New function. + + * kern/emu/getroot.c (find_root_device_from_libzfs): Use + grub_get_libzfs_handle() to obtain a libzfs handle instead of + accessing `libzfs_handle' directly. + +2010-08-01 Robert Millan + + * include/grub/emu/misc.h (grub_find_mount_point_from_dir) + (grub_find_zpool_from_mount_point): New function prototypes. + + * kern/emu/getroot.c [HAVE_GETFSSTAT]: Move `' to ... + * kern/emu/misc.c [HAVE_GETFSSTAT]: ... here. + + * kern/emu/getroot.c (find_mount_point_from_dir): Move to ... + * kern/emu/misc.c (grub_find_mount_point_from_dir): ... this. Remove + `static' attribute. + + * kern/emu/getroot.c (find_root_device_from_libzfs): Split code for + finding zpool from mount point into ... + * kern/emu/misc.c (grub_find_zpool_from_mount_point): ... this. + + * kern/emu/misc.c (grub_make_system_path_relative_to_its_root): When + requested path is part of a ZFS pool, use + grub_find_zpool_from_mount_point() to detect its filesystem name, + and generate a path with `/fsname@path' syntax. + +2010-08-01 Colin Watson + + * include/grub/util/libzfs.h (libzfs_init): Set argument list to + (void) rather than () so that this is a proper prototype. + +2010-08-01 Vladimir Serbinenko + + * lib/arg.c (grub_arg_show_help): Add the necessary spacing. + +2010-08-01 Vladimir Serbinenko + + * kern/emu/getroot.c (find_mount_point_from_dir): Compile only if + [HAVE_LIBZFS && HAVE_LIBNVPAIR] + +2010-08-01 Colin Watson + + * util/grub-mkrescue.in: Remove ${efi_dir} after building efi.img. + +2010-08-01 Colin Watson + + * script/yylex.l (NAME): Remove [:digit:], redundant with [:alnum:]. + +2010-08-01 Colin Watson + + * docs/grub.texi (Simple configuration): Document GRUB_CMDLINE_XEN + and GRUB_CMDLINE_XEN_DEFAULT. Recommend setting + GRUB_GFXPAYLOAD_LINUX=text rather than unsetting it in order to + disable gfxpayload. + (Shell-like scripting): Add real content. + (Serial terminal): Suggest `terminal_input serial; terminal_output + serial' rather than putting the two commands on separate lines, + since console input will be inoperative after the first command. + (menuentry): Document --class, --users, and --hotkey options. + (terminfo): Describe what `visually-ordered UTF-8' means (thanks, + Vladimir Serbinenko). + +2010-08-01 Vladimir Serbinenko +2010-08-01 Colin Watson + + * kern/misc.c (grub_memset): Optimise to reduce cache stalls. + +2010-08-01 Robert Millan + + * include/grub/emu/misc.h (grub_find_mount_point_from_dir) + (grub_find_zpool_from_mount_point): New function prototypes. + + * kern/emu/getroot.c [HAVE_GETFSSTAT]: Move `' to ... + * kern/emu/misc.c [HAVE_GETFSSTAT]: ... here. + + * kern/emu/getroot.c (find_mount_point_from_dir): Move to ... + * kern/emu/misc.c (grub_find_mount_point_from_dir): ... this. Remove + `static' attribute. + + * kern/emu/getroot.c (find_root_device_from_libzfs): Split code for + finding zpool from mount point into ... + * kern/emu/misc.c (grub_find_zpool_from_mount_point): ... this. + + * kern/emu/misc.c (grub_make_system_path_relative_to_its_root): When + requested path is part of a ZFS pool, use + grub_find_zpool_from_mount_point() to detect its filesystem name, + and generate a path with `/fsname@path' syntax. + +2010-08-01 Robert Millan + + Prevent accidental use of uninitialized libzfs_handle. + + * util/grub-probe.c (main): Move grub_util_init_libzfs() call to ... + * kern/emu/getroot.c (find_root_device_from_libzfs): ... here. + * util/misc.c (grub_util_init_libzfs): Make this function idempotent. + +2010-08-01 Colin Watson + + * util/grub.d/20_linux_xen.in: Don't use UUID for LVM root (matching + util/grub.d/10_linux.in). Fixes Debian bug #591093. + +2010-08-01 Robert Millan + + * kern/emu/getroot.c: Include `'. + +2010-07-31 Robert Millan + + * util/grub.d/10_kfreebsd.in: Make module handling more generic. + +2010-07-31 Robert Millan + + * kern/emu/misc.c: Add missing license header. + +2010-07-31 Robert Millan + + * configure.ac: Check for `libzfs.h' and `libnvpair.h'. + + * include/grub/util/libnvpair.h: Include `'. + [HAVE_LIBNVPAIR_H]: Include `' instead of + declaring libnvpair prototypes ourselves. + * include/grub/util/libzfs.h: Include `'. + [HAVE_LIBZFS_H]: Include `' instead of + declaring libzfs prototypes ourselves. + + (libzfs_handle): Moved to ... + * include/grub/util/misc.h (libzfs_handle): ... here. + Include `'. + +2010-07-30 Robert Millan + + * include/grub/emu/misc.h: Add missing license header. + +2010-07-30 Robert Millan + + Enable `grub-probe -t device' resolution on ZFS. + + * configure.ac: Check for getfsstat(), libzfs and libnvpair. + * include/grub/util/libnvpair.h: New file. + * include/grub/util/libzfs.h: New file. + + * kern/emu/getroot.c: Include `' and `'. + [HAVE_LIBZFS && HAVE_LIBNVPAIR]: Include `' and + `'. + [HAVE_GETFSSTAT]: Include `'. + + (find_mount_point_from_dir): New static function. + [HAVE_LIBZFS && HAVE_LIBNVPAIR] (find_root_device_from_libzfs): New + function. + [HAVE_LIBZFS && HAVE_LIBNVPAIR] (grub_guess_root_device): Use + find_root_device_from_libzfs() before ressorting to find_root_device(). + + * include/grub/util/misc.h (grub_util_init_libzfs): New function + prototype. + * util/misc.c: Include `'. + (grub_util_init_libzfs): New function. + [HAVE_LIBZFS] (libzfs_handle): New global variable. + [HAVE_LIBZFS] (fini_libzfs): New static function. + (grub_util_init_libzfs): New function. + * util/grub-probe.c (main): Call grub_util_init_libzfs(). + +2010-07-30 Robert Millan + + * include/grub/emu/misc.h (grub_make_system_path_relative_to_its_root) + (xmalloc, xrealloc, xstrdup, xasprintf): Add + `warn_unused_result' attribute. + * include/grub/misc.h (grub_strdup, grub_strndup, grub_strlen) + (grub_xasprintf, grub_xvasprintf): Likewise. + * include/grub/emu/misc.h (xasprintf): Remove duplicate prototype. + +2010-07-29 Robert Millan + + * util/grub-probe.c (PRINT_FS_LABEL): New enum value. + (probe): Handle `PRINT_FS_LABEL'. + (main): Handle `-t fs_label'. + +2010-07-29 Robert Millan + + * configure.ac: Remove grub-mkisofs checks. + +2010-07-28 Vladimir Serbinenko + + * util/ieee1275/grub-install.in: Don't use empty grub_device. + Reported by: Lennart Sorensen. + +2010-07-20 Vladimir Serbinenko + + * util/grub.d/00_header.in: Remove compatibility with terminal.mod + prior to terminal_input/terminal_output separation. It's been over 1.5 + years and those versions weren't widely deployed. + +2010-07-22 Colin Watson + + * disk/raid.c (insert_array): Don't count named arrays when looking + for unused array numbers. + Reported and tested by: Michael Guntsche. + +2010-07-20 Colin Watson + + * bus/usb/emu/usb.c (grub_usb_poll_devices): Add a dummy + implementation of this so that grub-emu links again, with a note + that this should support hotplugging in the future. + +2010-07-20 Colin Watson + + * kern/emu/getroot.c (grub_util_get_grub_dev): Use xasprintf. + +2010-07-20 Colin Watson + + * disk/loopback.c (grub_cmd_loopback): Don't leak a grub_file_t + handle on failure. + (grub_loopback_close): Remove empty function. + (grub_loopback_dev): Remove close method. + +2010-07-20 Colin Watson + + Disable EFI cursor when the EFI console becomes inactive. + + * term/efi/console.c (grub_efi_console_init): New function. + (grub_efi_console_fini): New function. + (grub_console_term_output): Register init and fini methods. + +2010-07-20 Vladimir Serbinenko + + * tests/util/grub-shell-tester.in: Remove bashism and declare as + sh script. + +2010-07-20 Vladimir Serbinenko + + * disk/loopback.c (grub_loopback): Replace filename with file. + (delete_loopback): Handle new semantics. + (grub_cmd_loopback): Likewise. + (grub_loopback_iterate): Likewise. + (grub_loopback_close): Likewise. + +2010-07-20 Vladimir Serbinenko + + * util/i386/efi/grub-install.in: Revert to platform-specific behaviour + with -p "". + Reported by: Tito Keitel. + +2010-07-20 Vladimir Serbinenko + + * docs/grub.texi (Naming convention): Document new naming convention. + +2010-07-20 Vadim Solomin +2010-07-20 Colin Watson + + Generate device.map in something closer to the old ordering. + + * util/deviceiter.c (struct device): New declaration. + (compare_file_names): Rename to ... + (compare_devices): ... this. Sort by kernel name in preference to + the stable by-id name, but keep the latter as a fallback comparison. + Update header comment. + (grub_util_iterate_devices) [__linux__]: Construct and sort an array + of `struct device' rather than of plain file names. + +2010-07-20 Thomas Frauendorfer + + * lib/i386/relocator_asm.S [! __x86_64__]: Don't try to disable amd64 + on i386. + +2010-07-20 Vladimir Serbinenko + + * commands/acpi.c (setup_common_tables): Use sizeof instead of + hardcoding size. + (setv1table): Likewise. + +2010-07-20 Colin Watson + + * disk/raid.c (insert_array): Use md/%s to name mdadm 1.x devices, + removing the homehost if present. + * kern/emu/getroot.c (get_mdadm_name) [__linux__]: New function. + (grub_util_get_grub_dev): Use md/%s to name mdadm 1.x devices, + removing the homehost if present. + (grub_util_get_grub_dev) [__linux__]: Get the array name from mdadm + if possible. + * util/i386/pc/grub-setup.c (main): Handle md/* devices. + + * disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Add start_sector + parameter. Set its pointer target to 0. + * disk/mdraid_linux.c (grub_mdraid_detect): Add start_sector + parameter. Set its pointer target to 0 for 0.9 metadata, or to the + `data_offset' value from the superblock for 1.x metadata. + * disk/raid.c (grub_raid_read): Offset reads by the start sector of + data on the device. + (insert_array): Record the start sector of data on the device. + (grub_raid_register): Pass start_sector parameters to + grub_raid_list->detect and insert_array. + * include/grub/raid.h (struct grub_raid_array): Add start_sector + member. + (struct grub_raid): Add start_sector parameter to `detect'. + + * disk/mdraid_linux.c (struct grub_raid_super_1x): Remove + __attribute__ ((packed)), leaving a comment. + (grub_mdraid_detect): Split out 0.9 and 1.x detection to ... + (grub_mdraid_detect_09): ... here and ... + (grub_mdraid_detect_1x): ... here. + +2010-07-20 Peter Henn + + * disk/mdraid_linux.c (grub_mdraid_detect): Fix calculation of 1.x + chunk size and disk size, which are already given as sector counts + as distinct from the 0.90 units. Fetch the correct device number + from the role table instead of using the table index. + +2010-07-20 Felix Zielcke + + * disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Set array->name to NULL. + * disk/mdraid_linux.c (grub_raid_super_1x): New structure. + (WriteMostly1): New macro. + Set array->name to NULL for metadata format 0.90. Add support for + metadata 1.x. Fix some comments. + * disk/raid.c (): Add support for name based RAID arrays. Fix a + few comments. + * util/getroot.c (grub_util_get_grub_dev): Add support for + /dev/md/name style devices. + +2010-07-20 Colin Watson + + * .bzrignore: Ignore 20_linux_xen. + +2010-07-17 Colin Watson + + * util/import_unicode.py: Remove unnecessary imports. + +2010-07-17 Aleš Nesrsta + + Hotplugging and USB hub support. + + * bus/usb/ohci.c (grub_ohci_td): Add convenience fields. + (grub_ohci): Likewise. + (GRUB_OHCI_REG_CONTROL_BULK_ENABLE): New definition. + (GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE): Likewise. + (GRUB_OHCI_RESET_CONNECT_CHANGE): Likewise. + (GRUB_OHCI_CTRL_EDS): Likewise. + (GRUB_OHCI_BULK_EDS): Likewise. + (GRUB_OHCI_TDS): Likewise. + (GRUB_OHCI_ED_ADDR_MASK): Likewise. + (grub_ohci_ed_phys2virt): New function. + (grub_ohci_virt_to_phys): Likewise. + (grub_ohci_td_phys2virt): Likewise. + (grub_ohci_td_virt2phys): Likewise. + (grub_ohci_pci_iter): Allocate memory and don't wait for stable + attachment. + (grub_ohci_find_ed): New function. + (grub_ohci_alloc_td): Likewise. + (grub_ohci_free_td): Likewise. + (grub_ohci_free_tds): Likewise. + (grub_ohci_transfer): Use previously allocated memory. + (grub_ohci_portstatus): Reset status changed bit. + (grub_ohci_detect_dev): Supply status changed. + (grub_ohci_fini_hw): Free memory. + (grub_ohci_restore_hw): Reallocate memory. + * bus/usb/uhci.c (grub_uhci_portstatus): Don't reset on disable. + Reset status change. + (grub_uhci_detect_dev): Supply status_change. + * bus/usb/usb.c (attach_hooks): New var. + (grub_usb_device_attach): New function. + (grub_usb_register_attach_hook_class): Likewise. + (grub_usb_unregister_attach_hook_class): Likewise. + * bus/usb/usbhub.c (grub_usb_hub_add_dev): Handle errors correctly. + (grub_usb_add_hub): Reset connection changed bit. + (attach_root_port): New function. + (grub_usb_root_hub): Likewise. + (poll_nonroot_hub): Likewise. + (grub_usb_poll_devices): Likewise. + * commands/usbtest.c (grub_cmd_usbtest): Poll devices before listing. + * disk/usbms.c (grub_usbms_open): Use device hooks. + (grub_usbms_iterate) :Poll devices. + (grub_usbms_finddevs): Split into ... + (grub_usbms_attach): ... this ... + (grub_usbms_attach): ... and this. + * include/grub/usb.h (grub_usb_controller_dev): Supply status_changed + in detect_dev. + (grub_usb_interface): New fields attached and detach_hook. + (grub_usb_attach_hook_class): New type. + (grub_usb_attach_desc): New struct. + (grub_usb_register_attach_hook_class): New function. + (grub_usb_unregister_attach_hook_class): Likewise. + (grub_usb_poll_devices): Likewise. + (grub_usb_device_attach): Likewise. + * include/grub/usbtrans.h (GRUB_USB_HUB_FEATURE_C_CONNECTED): New const. + (GRUB_USB_HUB_STATUS_C_CONNECTED): Likewise. + +2010-07-17 Vladimir Serbinenko + + * include/grub/bsdlabel.h (GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION): New definition. + * partmap/bsdlabel.c (bsdlabel_partition_map_iterate): Use FreeBSD + delta determination style. Works with most NetBSD partitions too. + +2010-07-17 Vladimir Serbinenko + + * kern/partition.c [GRUB_UTIL]: Add missing util/misc.h inclusion. + * partmap/bsdlabel.c [GRUB_UTIL]: Likewise. + +2010-07-17 Vladimir Serbinenko + + * disk/scsi.c (grub_scsi_open): Fix incorrect pointer dereference. + +2010-07-14 Anton Blanchard + + * loader/powerpc/ieee1275/linux.c (grub_cmd_linux): Do not reject + ET_DYN files. + +2010-07-14 Grégoire Sutre + + * Makefile.in: Use the substituted @USE_NLS@ instead of ENABLE_NLS. + +2010-07-14 Grégoire Sutre + + * kern/partition.c (grub_partition_check_containment): New function to + check that a partition is physically contained in a parent. Since + offsets are relative (and non-negative), this reduces to checking that + the partition ends before its parent. + (grub_partition_map_probe): Discard out-of-range sub-partitions. + (grub_partition_iterate): Likewise. + * include/grub/partition.h (grub_partition_map): Slightly more detailed + comments. + * partmap/bsdlabel.c (bsdlabel_partition_map_iterate): Discard + partitions that start before their parent, and add debug printfs. + +2010-07-13 Colin Watson + + * Makefile.in (.SUFFIX): Spell correctly, as ... + (.SUFFIXES): ... this. Fixes bug where `make foo' (where foo is a + bare module name without `.mod', e.g. `test') tried to invoke a + Modula-2 compiler. + +2010-07-13 Colin Watson + + * README: Point to the Info manual. + +2010-07-13 Jiro SEKIBA + + * fs/nilfs2.c: fix macro NILFS_2ND_SUPER_BLOCK to calculate + 2nd superblock position from partition size. + 2010-07-10 Colin Watson * Makefile.in (MAINTAINER_CLEANFILES): Remove diff --git a/README b/README index b6c7fd6d7..b30a4b68b 100644 --- a/README +++ b/README @@ -10,5 +10,13 @@ GRUB 2 data and program files. Please visit the official web page of GRUB 2, for more information. The URL is . -For now, there is not much documentation yet. Please look at the GRUB -Wiki for testing procedures. +More extensive documentation is available in the Info manual, +accessible using 'info grub' after building and installing GRUB 2. +Please look at the GRUB Wiki for testing +procedures. + +There are a number of important user-visible differences from the +first version of GRUB, now known as GRUB Legacy. For a summary, please +see: + + info grub Introduction 'Changes from GRUB Legacy' diff --git a/acinclude.m4 b/acinclude.m4 index 0615c863a..e8dd3dc7b 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -38,6 +38,7 @@ dnl Written by Pavel Roskin. Based on grub_ASM_EXT_C written by dnl Erich Boleyn and modified by Yoshinori K. Okuji. AC_DEFUN([grub_ASM_USCORE], [AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_EGREP]) AC_MSG_CHECKING([if C symbols get an underscore after compilation]) AC_CACHE_VAL(grub_cv_asm_uscore, [cat > conftest.c <<\EOF @@ -56,7 +57,7 @@ else AC_MSG_ERROR([${CC-cc} failed to produce assembly code]) fi -if grep _func conftest.s >/dev/null 2>&1; then +if $EGREP '(^|[^_[:alnum]])_func' conftest.s >/dev/null 2>&1; then grub_cv_asm_uscore=yes else grub_cv_asm_uscore=no diff --git a/conf/common.rmk b/conf/common.rmk index f92e5bc4c..908bd74e8 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -94,7 +94,7 @@ grub_script_check_SOURCES = gnulib/progname.c gnulib/getdelim.c gnulib/getline.c util/grub-script-check.c util/misc.c kern/emu/misc.c kern/emu/mm.c \ script/main.c script/script.c script/function.c script/lexer.c \ kern/err.c kern/list.c \ - kern/misc.c kern/env.c grub_script.tab.c \ + kern/command.c kern/misc.c kern/env.c grub_script.tab.c \ grub_script.yy.c grub_script_check_CFLAGS = $(GNULIB_UTIL_CFLAGS) grub_script_check_DEPENDENCIES = grub_script.tab.h @@ -636,7 +636,7 @@ normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \ normal/color.c normal/completion.c normal/datetime.c normal/menu.c \ normal/menu_entry.c normal/menu_text.c normal/charset.c \ normal/misc.c normal/crypto.c normal/term.c normal/context.c \ - script/main.c script/script.c script/execute.c unidata.c \ + script/main.c script/script.c script/execute.c script/argv.c unidata.c \ script/function.c script/lexer.c grub_script.tab.c grub_script.yy.c normal_mod_CFLAGS = $(COMMON_CFLAGS) $(POSIX_CFLAGS) -Wno-error normal_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/conf/tests.rmk b/conf/tests.rmk index 9af2f8f86..c14fe0fda 100644 --- a/conf/tests.rmk +++ b/conf/tests.rmk @@ -71,6 +71,18 @@ grub_script_dollar_SOURCES = tests/grub_script_dollar.in check_SCRIPTS += grub_script_comments grub_script_comments_SOURCES = tests/grub_script_comments.in +check_SCRIPTS += grub_script_functions +grub_script_functions_SOURCES = tests/grub_script_functions.in + +check_SCRIPTS += grub_script_break +grub_script_break_SOURCES = tests/grub_script_break.in + +check_SCRIPTS += grub_script_continue +grub_script_continue_SOURCES = tests/grub_script_continue.in + +check_SCRIPTS += grub_script_shift +grub_script_shift_SOURCES = tests/grub_script_shift.in + # List of tests to execute on "make check" # SCRIPTED_TESTS = example_scripted_test # SCRIPTED_TESTS += example_grub_script_test @@ -87,6 +99,10 @@ SCRIPTED_TESTS += grub_script_blanklines SCRIPTED_TESTS += grub_script_final_semicolon SCRIPTED_TESTS += grub_script_dollar SCRIPTED_TESTS += grub_script_comments +SCRIPTED_TESTS += grub_script_functions +SCRIPTED_TESTS += grub_script_break +SCRIPTED_TESTS += grub_script_continue +SCRIPTED_TESTS += grub_script_shift # dependencies between tests and testing-tools $(SCRIPTED_TESTS): grub-shell grub-shell-tester diff --git a/configure.ac b/configure.ac index b4dd0e9e0..9b918f1bc 100644 --- a/configure.ac +++ b/configure.ac @@ -246,15 +246,9 @@ else AC_PATH_PROG(HELP2MAN, help2man) fi -# Check for functions. +# Check for functions and headers. AC_CHECK_FUNCS(posix_memalign memalign asprintf vasprintf) - -# For grub-mkisofs -AC_HEADER_MAJOR -AC_HEADER_DIRENT -AC_CHECK_FUNCS(memmove sbrk strdup lstat getuid getgid) -AC_CHECK_HEADERS(sys/mkdev.h sys/sysmacros.h malloc.h termios.h sys/types.h) -AC_CHECK_HEADERS(unistd.h string.h strings.h sys/stat.h sys/fcntl.h limits.h) +AC_CHECK_HEADERS(libzfs.h libnvpair.h sys/param.h sys/mount.h) # For opendisk() and getrawpartition() on NetBSD. # Used in util/deviceiter.c and in util/hostdisk.c. @@ -813,6 +807,18 @@ if test x"$device_mapper_excuse" = x ; then fi AC_SUBST([LIBDEVMAPPER]) +AC_CHECK_LIB([zfs], [libzfs_init], + [LIBZFS="-lzfs" + AC_DEFINE([HAVE_LIBZFS], [1], + [Define to 1 if you have the ZFS library.])],) +AC_SUBST([LIBZFS]) + +AC_CHECK_LIB([nvpair], [nvlist_print], + [LIBNVPAIR="-lnvpair" + AC_DEFINE([HAVE_LIBNVPAIR], [1], + [Define to 1 if you have the NVPAIR library.])],) +AC_SUBST([LIBNVPAIR]) + pkglibrootdir='$(libdir)'/`echo $PACKAGE | sed "$program_transform_name"` AC_SUBST(pkglibrootdir) diff --git a/docs/grub.texi b/docs/grub.texi index 5d412ecd4..583cf98cb 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -444,12 +444,13 @@ disk. The number @samp{0} is the drive number, which is counted from disk. @example -(hd0,2) +(hd0,msdos2) @end example Here, @samp{hd} means it is a hard disk drive. The first integer -@samp{0} indicates the drive number, that is, the first hard disk, while -the second integer, @samp{1}, indicates the partition number (or the +@samp{0} indicates the drive number, that is, the first hard disk, +the string @samp{msdos} indicates the partition scheme, while +the second integer, @samp{2}, indicates the partition number (or the @sc{pc} slice number in the BSD terminology). The partition numbers are counted from @emph{one}, not from zero (as was the case in previous versions of GRUB). This expression means the second partition of the @@ -457,7 +458,7 @@ first hard disk drive. In this case, GRUB uses one partition of the disk, instead of the whole disk. @example -(hd0,5) +(hd0,msdos5) @end example This specifies the first @dfn{extended partition} of the first hard disk @@ -466,18 +467,15 @@ counted from @samp{5}, regardless of the actual number of primary partitions on your hard disk. @example -(hd1,a) +(hd1,msdos1,bsd1) @end example -This means the BSD @samp{a} partition of the second hard disk. If you -need to specify which @sc{pc} slice number should be used, use something -like this: @samp{(hd1,1,a)}. If the @sc{pc} slice number is omitted, -GRUB searches for the first @sc{pc} slice which has a BSD @samp{a} -partition. +This means the BSD @samp{a} partition on first @sc{pc} slice number +of the second hard disk. Of course, to actually access the disks or partitions with GRUB, you need to use the device specification in a command, like @samp{set -root=(fd0)} or @samp{parttool (hd0,3) hidden-}. To help you find out +root=(fd0)} or @samp{parttool (hd0,msdos3) hidden-}. To help you find out which number specifies a partition you want, the GRUB command-line (@pxref{Command-line interface}) options have argument completion. This means that, for example, you only need to type @@ -501,7 +499,7 @@ Now the question is, how to specify a file? Again, consider an example: @example -(hd0,1)/vmlinuz +(hd0,msdos1)/vmlinuz @end example This specifies the file named @samp{vmlinuz}, found on the first @@ -1064,6 +1062,11 @@ only to the default menu entry, after those listed in As @samp{GRUB_CMDLINE_LINUX} and @samp{GRUB_CMDLINE_LINUX_DEFAULT}, but for NetBSD. +@item GRUB_CMDLINE_XEN +@itemx GRUB_CMDLINE_XEN_DEFAULT +As @samp{GRUB_CMDLINE_LINUX} and @samp{GRUB_CMDLINE_LINUX_DEFAULT}, but for +Linux and Xen. + @item GRUB_DISABLE_LINUX_UUID Normally, @command{grub-mkconfig} will generate menu entries that use universally-unique identifiers (UUIDs) to identify the root filesystem to @@ -1115,8 +1118,8 @@ try several modes in sequence. Depending on your kernel, your distribution, your graphics card, and the phase of the moon, note that using this option may cause GNU/Linux to suffer from various display problems, particularly during the early part of the -boot sequence. If you have problems, simply unset this option and GRUB will -tell Linux to boot in normal text mode. +boot sequence. If you have problems, set this option to @samp{text} and +GRUB will tell Linux to boot in normal text mode. @item GRUB_DISABLE_OS_PROBER Normally, @command{grub-mkconfig} will try to use the external @@ -1145,6 +1148,142 @@ that file, making sure to leave at least the first two lines intact. @node Shell-like scripting @section Writing full configuration files directly +@c Some of this section is derived from the GNU Bash manual page, also +@c copyrighted by the FSF. + +@file{grub.cfg} is written in GRUB's built-in scripting language, which has +a syntax quite similar to that of GNU Bash and other Bourne shell +derivatives. + +@heading Words + +A @dfn{word} is a sequence of characters considered as a single unit by +GRUB. Words are separated by @dfn{metacharacters}, which are the following +plus space, tab, and newline: + +@example +@{ @} | & $ ; < > +@end example + +Quoting may be used to include metacharacters in words; see below. + +@heading Reserved words + +Reserved words have a special meaning to GRUB. The following words are +recognised as reserved when unquoted and either the first word of a simple +command or the third word of a @code{for} command: + +@example +! [[ ]] @{ @} +case do done elif else esac fi for function +if in menuentry select then time until while +@end example + +Not all of these reserved words have a useful purpose yet; some are reserved +for future expansion. + +@heading Quoting + +Quoting is used to remove the special meaning of certain characters or +words. It can be used to treat metacharacters as part of a word, to prevent +reserved words from being recognised as such, and to prevent variable +expansion. + +There are three quoting mechanisms: the escape character, single quotes, and +double quotes. + +A non-quoted backslash (\) is the @dfn{escape character}. It preserves the +literal value of the next character that follows, with the exception of +newline. + +Enclosing characters in single quotes preserves the literal value of each +character within the quotes. A single quote may not occur between single +quotes, even when preceded by a backslash. + +Enclosing characters in double quotes preserves the literal value of all +characters within the quotes, with the exception of @samp{$} and @samp{\}. +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. + +@heading Variable expansion + +The @samp{$} character introduces variable expansion. The variable name to +be expanded may be enclosed in braces, which are optional but serve to +protect the variable to be expanded from characters immediately following it +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. + +The special variable name @samp{?} expands to the exit status of the most +recently executed command. + +@heading Comments + +A word beginning with @samp{#} causes that word and all remaining characters +on that line to be ignored. + +@heading Simple commands + +A @dfn{simple command} is a sequence of words separated by spaces or tabs +and terminated by a semicolon or a newline. The first word specifies the +command to be executed. The remaining words are passed as arguments to the +invoked command. + +The return value of a simple command is its exit status. + +@heading Compound commands + +A @dfn{compound command} is one of the following: + +@table @asis +@item for @var{name} in @var{word} @dots{}; do @var{list}; done +The list of words following @code{in} is expanded, generating a list of +items. The variable @var{name} is set to each element of this list in turn, +and @var{list} is executed each time. The return value is the exit status +of the last command that executes. If the expansion of the items following +@code{in} results in an empty list, no commands are executed, and the return +status is 0. + +@item if @var{list}; then @var{list}; [elif @var{list}; then @var{list};] @dots{} [else @var{list};] fi +The @code{if} @var{list} is executed. If its exit status is zero, the +@code{then} @var{list} is executed. Otherwise, each @code{elif} @var{list} +is executed in turn, and if its exit status is zero, the corresponding +@code{then} @var{list} is executed and the command completes. Otherwise, +the @code{else} @var{list} is executed, if present. The exit status is the +exit status of the last command executed, or zero if no condition tested +true. + +@item while @var{cond}; do @var{list}; done +@itemx until @var{cond}; do @var{list}; done +The @code{while} command continuously executes the @code{do} @var{list} as +long as the last command in @var{cond} returns an exit status of zero. The +@code{until} command is identical to the @code{while} command, except that +the test is negated; the @code{do} @var{list} is executed as long as the +last command in @var{cond} returns a non-zero exit status. The exit status +of the @code{while} and @code{until} commands is the exit status of the last +@code{do} @var{list} command executed, or zero if none was executed. + +@item function @var{name} @{ @var{command}; @dots{} @} +This defines a function named @var{name}. The @dfn{body} of the function is +the list of commands within braces, each of which must be terminated with a +semicolon or a newline. This list of commands will be executed whenever +@var{name} is specified as the name of a simple command. Function +definitions do not affect the exit status in @code{$?}. When executed, the +exit status of a function is the exit status of the last command executed in +the body. + +@item menuentry @var{title} [@option{--class=class} @dots{}] [@option{--users=users}] [@option{--hotkey=key}] @{ @var{command}; @dots{} @} +@xref{menuentry}. +@end table + @node Embedded configuration @section Embedding a configuration file into GRUB @@ -1310,8 +1449,7 @@ simple. Here is an example: @example @group grub> @kbd{serial --unit=0 --speed=9600} -grub> @kbd{terminal_input serial} -grub> @kbd{terminal_output serial} +grub> @kbd{terminal_input serial; terminal_output serial} @end group @end example @@ -1322,11 +1460,14 @@ command accepts many other options, so please refer to @ref{serial}, for more details. The commands @command{terminal_input} (@pxref{terminal_input}) and -@command{terminal_output} (@pxref{terminal_output} choose which type of +@command{terminal_output} (@pxref{terminal_output}) choose which type of terminal you want to use. In the case above, the terminal will be a serial terminal, but you can also pass @code{console} to the command, as @samp{terminal serial console}. In this case, a terminal in which -you press any key will be selected as a GRUB terminal. +you press any key will be selected as a GRUB terminal. In the example above, +note that you need to put both commands on the same command line, as you +will lose the ability to type commands on the console after the first +command. However, note that GRUB assumes that your terminal emulator is compatible with VT100 by default. This is true for most terminal @@ -1791,9 +1932,26 @@ These commands can only be used in the menu: @node menuentry @subsection menuentry -@deffn Command title name @dots{} -Start a new boot entry, and set its name to the contents of the rest of -the line, starting with the first non-space character. +@deffn Command menuentry @var{title} @ + [@option{--class=class} @dots{}] [@option{--users=users}] @ + [@option{--hotkey=key}] @ + @{ @var{command}; @dots{} @} +This defines a GRUB menu entry named @var{title}. When this entry is +selected from the menu, GRUB will set the @var{chosen} environment variable +to @var{title}, execute the list of commands given within braces, and if the +last command in the list returned successfully and a kernel was loaded it +will execute the @command{boot} command. + +The @option{--class} option may be used any number of times to group menu +entries into classes. Menu themes may display different classes using +different styles. + +The @option{--users} option grants specific users access to specific menu +entries. @xref{Security}. + +The @option{--hotkey} option associates a hotkey with a menu entry. +@var{key} may be a single letter, or one of the aliases @samp{backspace}, +@samp{tab}, or @samp{delete}. @end deffn @@ -1887,7 +2045,9 @@ The @option{-a} (@option{--ascii}), @option{-u} (@option{--utf8}), and @option{-v} (@option{--visual-utf8}) options control how non-ASCII text is displayed. @option{-a} specifies an ASCII-only terminal; @option{-u} specifies logically-ordered UTF-8; and @option{-v} specifies -visually-ordered UTF-8. +"visually-ordered UTF-8" (in other words, arranged such that a terminal +emulator without bidirectional text support will display right-to-left text +in the proper order; this is not really proper UTF-8, but a workaround). If no option or terminal type is specified, the current terminal type is printed. diff --git a/grub-core/bus/usb/emu/usb.c b/grub-core/bus/usb/emu/usb.c index 187857b5b..7d52decb2 100644 --- a/grub-core/bus/usb/emu/usb.c +++ b/grub-core/bus/usb/emu/usb.c @@ -78,6 +78,12 @@ grub_libusb_devices (void) return GRUB_USB_ERR_NONE; } +void +grub_usb_poll_devices (void) +{ + /* TODO: recheck grub_usb_devs */ +} + int grub_usb_iterate (int (*hook) (grub_usb_device_t dev)) diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c index 47cca7ce4..42af11466 100644 --- a/grub-core/bus/usb/ohci.c +++ b/grub-core/bus/usb/ohci.c @@ -46,6 +46,23 @@ struct grub_ohci_hcca grub_uint8_t reserved[116]; } __attribute__((packed)); +/* OHCI General Transfer Descriptor */ +struct grub_ohci_td +{ + /* Information used to construct the TOKEN packet. */ + grub_uint32_t token; + grub_uint32_t buffer; /* LittleEndian physical address */ + grub_uint32_t next_td; /* LittleEndian physical address */ + grub_uint32_t buffer_end; /* LittleEndian physical address */ + /* next values are not for OHCI HW */ + grub_uint32_t prev_td_phys; /* we need it to find previous TD + * physical address in CPU endian */ + grub_uint32_t link_td; /* pointer to next free/chained TD + * pointer as uint32 */ + grub_uint32_t tr_index; /* index of TD in transfer */ + grub_uint8_t pad[4]; /* padding to 32 bytes */ +} __attribute__((packed)); + /* OHCI Endpoint Descriptor. */ struct grub_ohci_ed { @@ -55,26 +72,33 @@ struct grub_ohci_ed grub_uint32_t next_ed; } __attribute__((packed)); -struct grub_ohci_td -{ - /* Information used to construct the TOKEN packet. */ - grub_uint32_t token; - - grub_uint32_t buffer; - grub_uint32_t next_td; - grub_uint32_t buffer_end; -} __attribute__((packed)); - typedef volatile struct grub_ohci_td *grub_ohci_td_t; typedef volatile struct grub_ohci_ed *grub_ohci_ed_t; +/* Experimental change of ED/TD allocation */ +/* Little bit similar as in UHCI */ +/* Implementation assumes: + * 32-bits architecture - XXX: fix for 64-bits + * memory allocated by grub_memalign_dma32 must be continuous + * in virtual and also in physical memory */ struct grub_ohci { volatile grub_uint32_t *iobase; volatile struct grub_ohci_hcca *hcca; grub_uint32_t hcca_addr; struct grub_pci_dma_chunk *hcca_chunk; + grub_ohci_ed_t ed_ctrl; /* EDs for CONTROL */ + grub_uint32_t ed_ctrl_addr; + struct grub_pci_dma_chunk *ed_ctrl_chunk; + grub_ohci_ed_t ed_bulk; /* EDs for BULK */ + grub_uint32_t ed_bulk_addr; + struct grub_pci_dma_chunk *ed_bulk_chunk; + grub_ohci_td_t td; /* TDs */ + grub_uint32_t td_addr; + 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; @@ -121,6 +145,56 @@ typedef enum #define GRUB_OHCI_SET_PORT_RESET (1 << 4) #define GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE (1 << 20) +#define GRUB_OHCI_REG_CONTROL_BULK_ENABLE (1 << 5) +#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_TDS 256 + +#define GRUB_OHCI_ED_ADDR_MASK 0x7ff + +static inline grub_ohci_ed_t +grub_ohci_ed_phys2virt (struct grub_ohci *o, int bulk, grub_uint32_t x) +{ + if (!x) + return NULL; + if (bulk) + return (grub_ohci_ed_t) (x - o->ed_bulk_addr + + (grub_uint8_t *) o->ed_bulk); + return (grub_ohci_ed_t) (x - o->ed_ctrl_addr + + (grub_uint8_t *) o->ed_ctrl); +} + +static grub_uint32_t +grub_ohci_virt_to_phys (struct grub_ohci *o, int bulk, grub_ohci_ed_t x) +{ + if (!x) + return 0; + + if (bulk) + return (grub_uint8_t *) x - (grub_uint8_t *) o->ed_bulk + o->ed_bulk_addr; + return (grub_uint8_t *) x - (grub_uint8_t *) o->ed_ctrl + o->ed_ctrl_addr; +} + +static inline grub_ohci_td_t +grub_ohci_td_phys2virt (struct grub_ohci *o, grub_uint32_t x) +{ + if (!x) + return NULL; + return (grub_ohci_td_t) (x - o->td_addr + (grub_uint8_t *) o->td); +} + +static grub_uint32_t +grub_ohci_td_virt2phys (struct grub_ohci *o, grub_ohci_td_t x) +{ + if (!x) + return 0; + return (grub_uint8_t *)x - (grub_uint8_t *)o->td + o->td_addr; +} + + static grub_uint32_t grub_ohci_readreg32 (struct grub_ohci *o, grub_ohci_reg_t reg) { @@ -148,7 +222,8 @@ grub_ohci_pci_iter (grub_pci_device_t dev, struct grub_ohci *o; grub_uint32_t revision; int cs5536; - + int j; + /* Determine IO base address. */ grub_dprintf ("ohci", "pciid = %x\n", pciid); @@ -204,7 +279,7 @@ grub_ohci_pci_iter (grub_pci_device_t dev, o = grub_malloc (sizeof (*o)); if (! o) return 1; - + grub_memset ((void*)o, 0, sizeof (*o)); o->iobase = grub_pci_device_map_range (dev, base, 0x800); grub_dprintf ("ohci", "base=%p\n", o->iobase); @@ -212,9 +287,57 @@ grub_ohci_pci_iter (grub_pci_device_t dev, /* Reserve memory for the HCCA. */ o->hcca_chunk = grub_memalign_dma32 (256, 256); if (! o->hcca_chunk) - return 1; + goto fail; o->hcca = grub_dma_get_virt (o->hcca_chunk); o->hcca_addr = grub_dma_get_phys (o->hcca_chunk); + grub_memset ((void*)o->hcca, 0, sizeof(*o->hcca)); + grub_dprintf ("ohci", "hcca: chunk=%p, virt=%p, phys=0x%02x\n", + o->hcca_chunk, o->hcca, o->hcca_addr); + + /* Reserve memory for ctrl EDs. */ + o->ed_ctrl_chunk = grub_memalign_dma32 (16, sizeof(struct grub_ohci_ed)*GRUB_OHCI_CTRL_EDS); + if (! o->ed_ctrl_chunk) + goto fail; + o->ed_ctrl = grub_dma_get_virt (o->ed_ctrl_chunk); + o->ed_ctrl_addr = grub_dma_get_phys (o->ed_ctrl_chunk); + /* Preset EDs */ + grub_memset ((void*)o->ed_ctrl, 0, sizeof(struct grub_ohci_ed) * GRUB_OHCI_CTRL_EDS); + for (j=0; j < GRUB_OHCI_CTRL_EDS; j++) + o->ed_ctrl[j].target = grub_cpu_to_le32 (1 << 14); /* skip */ + + grub_dprintf ("ohci", "EDs-C: chunk=%p, virt=%p, phys=0x%02x\n", + o->ed_ctrl_chunk, o->ed_ctrl, o->ed_ctrl_addr); + + /* Reserve memory for bulk EDs. */ + o->ed_bulk_chunk = grub_memalign_dma32 (16, sizeof(struct grub_ohci_ed)*GRUB_OHCI_BULK_EDS); + if (! o->ed_bulk_chunk) + goto fail; + o->ed_bulk = grub_dma_get_virt (o->ed_bulk_chunk); + o->ed_bulk_addr = grub_dma_get_phys (o->ed_bulk_chunk); + /* Preset EDs */ + grub_memset ((void*)o->ed_bulk, 0, sizeof(struct grub_ohci_ed) * GRUB_OHCI_BULK_EDS); + for (j=0; j < GRUB_OHCI_BULK_EDS; j++) + o->ed_bulk[j].target = grub_cpu_to_le32 (1 << 14); /* skip */ + + grub_dprintf ("ohci", "EDs-B: chunk=%p, virt=%p, phys=0x%02x\n", + o->ed_bulk_chunk, o->ed_bulk, o->ed_bulk_addr); + + /* Reserve memory for TDs. */ + o->td_chunk = grub_memalign_dma32 (32, sizeof(struct grub_ohci_td)*GRUB_OHCI_TDS); + /* Why is it aligned on 32 boundary if spec. says 16 ? + * We have structure 32 bytes long and we don't want cross + * 4K boundary inside structure. */ + if (! o->td_chunk) + goto fail; + o->td_free = o->td = grub_dma_get_virt (o->td_chunk); + o->td_addr = grub_dma_get_phys (o->td_chunk); + /* Preset free TDs chain in TDs */ + grub_memset ((void*)o->td, 0, sizeof(struct grub_ohci_td) * GRUB_OHCI_TDS); + for (j=0; j < (GRUB_OHCI_TDS-1); j++) + o->td[j].link_td = (grub_uint32_t)&o->td[j+1]; + + grub_dprintf ("ohci", "TDs: chunk=%p, virt=%p, phys=0x%02x\n", + o->td_chunk, o->td, o->td_addr); /* Check if the OHCI revision is actually 1.0 as supported. */ revision = grub_ohci_readreg32 (o, GRUB_OHCI_REG_REVISION); @@ -286,9 +409,13 @@ grub_ohci_pci_iter (grub_pci_device_t dev, /* Misc. pre-sets. */ o->hcca->donehead = 0; grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, 0x7f); /* Clears everything */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, 0); + /* We don't want modify CONTROL/BULK HEAD registers. + * So we assign to HEAD registers zero ED from related array + * and we will not use this ED, it will be always skipped. + * It should not produce notable performance penalty (I hope). */ + 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, 0); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, o->ed_bulk_addr); grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); /* Check OHCI Legacy Support */ @@ -302,9 +429,11 @@ grub_ohci_pci_iter (grub_pci_device_t dev, grub_dprintf ("ohci", "OHCI Legacy Support disabled.\n"); } - /* Enable the OHCI. */ + /* Enable the OHCI + enable CONTROL and BULK LIST. */ grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, - (2 << 6)); + (2 << 6) + | GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE + | GRUB_OHCI_REG_CONTROL_BULK_ENABLE ); grub_dprintf ("ohci", "OHCI enable: 0x%02x\n", (grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) >> 6) & 3); @@ -313,23 +442,8 @@ 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); - /* Wait for stable power (100ms) and stable attachment (100ms) */ - /* I.e. minimum wait time should be probably 200ms. */ - /* We assume that device is attached when ohci is loaded. */ - /* Some devices take long time to power-on or indicate attach. */ - /* Here is some experimental value which should probably mostly work. */ - /* Cameras with manual USB mode selection and maybe some other similar - * devices will not work in some cases - they are repowered during - * ownership change and then they are starting slowly and mostly they - * are wanting select proper mode again... - * The same situation can be on computers where BIOS not set-up OHCI - * to be at least powered USB bus (maybe it is Yeelong case...?) - * Possible workaround could be for example some prompt - * for user with confirmation of proper USB device connection. - * Another workaround - "rmmod usbms", "rmmod ohci", proper start - * and configuration of USB device and then "insmod ohci" - * and "insmod usbms". */ - grub_millisleep (500); + /* Now we have hot-plugging, we need to wait for stable power only */ + grub_millisleep (100); /* Link to ohci now that initialisation is successful. */ o->next = ohci; @@ -339,6 +453,9 @@ grub_ohci_pci_iter (grub_pci_device_t dev, fail: if (o) + grub_dma_free (o->td_chunk); + grub_dma_free (o->ed_bulk_chunk); + grub_dma_free (o->ed_ctrl_chunk); grub_dma_free (o->hcca_chunk); grub_free (o); @@ -370,6 +487,114 @@ grub_ohci_iterate (int (*hook) (grub_usb_controller_t dev)) return 0; } +static grub_ohci_ed_t +grub_ohci_find_ed (struct grub_ohci *o, int bulk, grub_uint32_t target) +{ + grub_ohci_ed_t ed, ed_next; + grub_uint32_t target_addr = target & GRUB_OHCI_ED_ADDR_MASK; + int count; + int i; + + /* Use proper values and structures. */ + if (bulk) + { + count = GRUB_OHCI_BULK_EDS; + ed = o->ed_bulk; + ed_next = grub_ohci_ed_phys2virt(o, bulk, + grub_le_to_cpu32 (ed->next_ed) ); + } + else + { + count = GRUB_OHCI_CTRL_EDS; + ed = o->ed_ctrl; + ed_next = grub_ohci_ed_phys2virt(o, bulk, + grub_le_to_cpu32 (ed->next_ed) ); + } + + /* First try to find existing ED with proper target address */ + for (i = 0; ; ) + { + if (i && /* We ignore zero ED */ + ((ed->target & GRUB_OHCI_ED_ADDR_MASK) == target_addr)) + return ed; /* Found proper existing ED */ + i++; + if (ed_next && (i < count)) + { + ed = ed_next; + ed_next = grub_ohci_ed_phys2virt(o, bulk, + grub_le_to_cpu32 (ed->next_ed) ); + continue; + } + break; + } + /* ED with target_addr does not exist, we have to add it */ + /* Have we any free ED in array ? */ + if (i >= count) /* No. */ + return NULL; + /* Currently we simply take next ED in array, no allocation + * function is used. It should be no problem until hot-plugging + * will be implemented, i.e. until we will need to de-allocate EDs + * of unplugged devices. */ + /* We can link new ED to previous ED safely as the new ED should + * still have set skip bit. */ + ed->next_ed = grub_cpu_to_le32 ( grub_ohci_virt_to_phys (o, + bulk, &ed[1])); + return &ed[1]; +} + +static grub_ohci_td_t +grub_ohci_alloc_td (struct grub_ohci *o) +{ + grub_ohci_td_t ret; + + /* Check if there is a Transfer Descriptor available. */ + if (! o->td_free) + return NULL; + + ret = o->td_free; /* Take current free TD */ + o->td_free = (grub_ohci_td_t)ret->link_td; /* Advance to next free TD in chain */ + ret->link_td = 0; /* Reset link_td in allocated TD */ + return ret; +} + +static void +grub_ohci_free_td (struct grub_ohci *o, grub_ohci_td_t td) +{ + grub_memset ( (void*)td, 0, sizeof(struct grub_ohci_td) ); + td->link_td = (grub_uint32_t) o->td_free; /* Cahin new free TD & rest */ + o->td_free = td; /* Change address of first free TD */ +} + +static void +grub_ohci_free_tds (struct grub_ohci *o, grub_ohci_td_t td) +{ + if (!td) + return; + + /* Unchain first TD from previous TD if it is chained */ + if (td->prev_td_phys) + { + grub_ohci_td_t td_prev_virt = grub_ohci_td_phys2virt(o, + td->prev_td_phys); + + if (td == (grub_ohci_td_t) td_prev_virt->link_td) + td_prev_virt->link_td = 0; + } + + /* Free all TDs from td (chained by link_td) */ + while (td) + { + grub_ohci_td_t tdprev; + + /* Unlink the queue. */ + tdprev = td; + td = (grub_ohci_td_t) td->link_td; + + /* Free the TD. */ + grub_ohci_free_td (o, tdprev); + } +} + static void grub_ohci_transaction (grub_ohci_td_t td, grub_transfer_type_t type, unsigned int toggle, @@ -398,12 +623,7 @@ grub_ohci_transaction (grub_ohci_td_t td, break; } -#if 0 /* Always generate interrupt */ - /* Generate no interrupts. */ - token |= 7 << 21; -#endif - - /* Set the token. */ + /* Set the token (Always generate interrupt - bits 21-23 = 0). */ token |= toggle << 24; token |= 1 << 25; @@ -437,174 +657,180 @@ grub_ohci_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; - grub_uint32_t ed_addr; - struct grub_pci_dma_chunk *ed_chunk, *td_list_chunk; - grub_ohci_td_t td_list; - grub_uint32_t td_list_addr; + 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_tail; - grub_uint32_t td_head; + 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_usb_err_t err; + 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; - grub_uint32_t tderr_addr = 0; - - /* Allocate an Endpoint Descriptor. */ - ed_chunk = grub_memalign_dma32 (256, sizeof (*ed)); - if (! ed_chunk) - return GRUB_USB_ERR_INTERNAL; - ed = grub_dma_get_virt (ed_chunk); - ed_addr = grub_dma_get_phys (ed_chunk); - - td_list_chunk = grub_memalign_dma32 (256, sizeof (*td_list) - * (transfer->transcnt + 1)); - if (! td_list_chunk) - { - grub_dma_free (ed_chunk); - return GRUB_USB_ERR_INTERNAL; - } - td_list = grub_dma_get_virt (td_list_chunk); - td_list_addr = grub_dma_get_phys (td_list_chunk); - - grub_dprintf ("ohci", "alloc=%p/0x%x\n", td_list, td_list_addr); - - /* Setup all Transfer Descriptors. */ - for (i = 0; i < transfer->transcnt; i++) - { - grub_usb_transaction_t tr = &transfer->transactions[i]; - - grub_ohci_transaction (&td_list[i], tr->pid, tr->toggle, - tr->size, tr->data); - - td_list[i].next_td = grub_cpu_to_le32 (td_list_addr - + (i + 1) * sizeof (td_list[0])); - } - -#if 0 /* Better will be enable interrupt on all TDs. */ - /* The last-1 TD token we should change to enable interrupt when TD finishes. - * As OHCI interrupts are disabled, it does only setting of WDH bit in - * HcInterruptStatus register - and that is what we want to safely detect - * normal end of all transactions. */ - td_list[transfer->transcnt - 1].token &= ~(7 << 21); -#endif - - td_list[transfer->transcnt].token = 0; - td_list[transfer->transcnt].buffer = 0; - td_list[transfer->transcnt].buffer_end = 0; - td_list[transfer->transcnt].next_td = - (grub_uint32_t) &td_list[transfer->transcnt]; - - /* Setup the Endpoint Descriptor. */ + /* Pre-set target for ED - we need it to find proper ED */ /* Set the device address. */ target = transfer->devaddr; - /* Set the endpoint. It should be masked, we need 4 bits only. */ target |= (transfer->endpoint & 15) << 7; - /* Set the device speed. */ target |= (transfer->dev->speed == GRUB_USB_SPEED_LOW) << 13; - /* Set the maximum packet size. */ target |= transfer->max << 16; - td_head = td_list_addr; + /* Determine if transfer type is bulk - we need to select proper ED */ + switch (transfer->type) + { + case GRUB_USB_TRANSACTION_TYPE_BULK: + bulk = 1; + break; - td_tail = td_list_addr + transfer->transcnt * sizeof (*td_list); + case GRUB_USB_TRANSACTION_TYPE_CONTROL: + break; - ed->target = grub_cpu_to_le32 (target); - ed->td_head = grub_cpu_to_le32 (td_head); - ed->td_tail = grub_cpu_to_le32 (td_tail); - ed->next_ed = grub_cpu_to_le32 (0); + default : + return GRUB_USB_ERR_INTERNAL; + } + + /* Find proper ED or add new ED */ + ed_virt = grub_ohci_find_ed (o, bulk, target); + if (!ed_virt) + { + grub_dprintf ("ohci","Fatal: No free ED !\n"); + 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; + + /* Sanity check - td_head should be equal to td_tail */ + if (td_head_phys != td_tail_phys) /* Should never happen ! */ + { + grub_dprintf ("ohci", "Fatal: HEAD is not equal to TAIL !\n"); + grub_dprintf ("ohci", "HEAD = 0x%02x, TAIL = 0x%02x\n", + td_head_phys, td_tail_phys); + /* XXX: Fix: What to do ? */ + return GRUB_USB_ERR_INTERNAL; + } + + /* Now we should handle first TD. If ED is newly allocated, + * we must allocate the first TD. */ + if (!td_head_phys) + { + td_head_virt = grub_ohci_alloc_td (o); + if (!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; + } + else + 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; + i < transfer->transcnt; i++) + { + grub_usb_transaction_t tr = &transfer->transactions[i]; + + grub_ohci_transaction (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); + + /* Remember last used (processed) TD phys. addr. */ + td_last_phys = grub_ohci_td_virt2phys (o, 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) ) ); + /* Reset head TD */ + grub_memset ( (void*)td_head_virt, 0, + sizeof(struct grub_ohci_td) ); + grub_dprintf ("ohci", "Fatal: No free TD !"); + return GRUB_USB_ERR_INTERNAL; + } + + /* Chain TDs */ + td_current_virt->link_td = (grub_uint32_t) td_next_virt; + 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; + } + + grub_dprintf ("ohci", "Tail TD (not processed) = %p\n", + td_current_virt); + + /* Setup the Endpoint Descriptor for transfer. */ + /* First set necessary fields in TARGET but keep (or set) skip bit */ + /* Note: It could be simpler if speed, format and max. packet + * 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)); + /* Set td_tail */ + ed_virt->td_tail + = grub_cpu_to_le32 (grub_ohci_td_virt2phys (o, td_current_virt)); + /* Now reset skip bit */ + 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 ! */ grub_dprintf ("ohci", "program OHCI\n"); - /* Disable the Control and Bulk lists. */ - control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); - control &= ~(3 << 4); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); - - /* Clear BulkListFilled and ControlListFilled. */ - status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - status &= ~(3 << 1); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); - - /* Now we should wait for start of next frame. Because we are not using - * interrupt, we reset SF bit and wait when it goes to 1. */ - /* 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 it should be safe to change CONTROL and BULK lists. */ - - /* This we do for safety's sake - it should be done in previous call - * of grub_ohci_transfer and nobody should change it in meantime... - * It should be done before start of control or bulk OHCI list. */ - o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears WDH */ - /* Program the OHCI to actually transfer. */ switch (transfer->type) { case GRUB_USB_TRANSACTION_TYPE_BULK: { - grub_dprintf ("ohci", "add to bulk list\n"); - - /* Set BulkList Head and Current */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, ed_addr); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); - -#define GRUB_OHCI_REG_CONTROL_BULK_ENABLE (1 << 5) -#define GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE (1 << 4) - - /* Enable the Bulk list. */ - control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); - control |= GRUB_OHCI_REG_CONTROL_BULK_ENABLE; - control &= ~GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE; - - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); - + grub_dprintf ("ohci", "BULK list filled\n"); /* Set BulkListFilled. */ - status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - status |= 1 << 2; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); - + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1 << 2); + /* Read back of register should ensure it is really written */ + grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); break; } case GRUB_USB_TRANSACTION_TYPE_CONTROL: { - grub_dprintf ("ohci", "add to control list\n"); - - /* Set ControlList Head and Current */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, ed_addr); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); - - /* Enable the Control list. */ - control |= GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE; - control &= ~GRUB_OHCI_REG_CONTROL_BULK_ENABLE; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); - + grub_dprintf ("ohci", "CONTROL list filled\n"); /* Set ControlListFilled. */ - status |= 1 << 1; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1 << 1); + /* Read back of register should ensure it is really written */ + grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); break; } } - grub_dprintf ("ohci", "wait for completion\n"); - grub_dprintf ("ohci", "begin: control=0x%02x status=0x%02x\n", - grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL), - grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS)); - grub_dprintf ("ohci","intstatus=0x%02x\n", - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS)); - /* Safety measure to avoid a hang. */ maxtime = grub_get_time_ms () + 1000; @@ -613,19 +839,22 @@ grub_ohci_transfer (grub_usb_controller_t dev, { /* Check transfer status */ intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); - if ((intstatus & 0x2) != 0) + if (!o->bad_OHCI && (intstatus & 0x2) != 0) { - grub_dprintf ("ohci", "Current HccaDoneHead=0x%08x\n", - o->hcca->donehead); /* Remember last successful TD */ - tderr_addr = grub_le_to_cpu32 (o->hcca->donehead) & ~0xf; + 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_addr == td_list_addr - + sizeof (td_list[0]) * (transfer->transcnt - 1)) - break; + if (tderr_phys == td_last_phys) + { + if (grub_le_to_cpu32 (ed_virt->td_head) & 1) + err_halt = 1; + break; + } continue; } @@ -636,102 +865,169 @@ grub_ohci_transfer (grub_usb_controller_t dev, } /* Detected a HALT. */ - if (grub_le_to_cpu32 (ed->td_head) & 1) - break; + 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) { - /* Disable the Control and Bulk lists. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, - grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) & ~(3 << 4)); err_timeout = 1; break; } - if ((ed->td_head & ~0xf) == (ed->td_tail & ~0xf)) - break; - grub_cpu_idle (); } while (1); - grub_dprintf ("ohci", "end: control=0x%02x status=0x%02x\n", - grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL), - grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS)); - grub_dprintf ("ohci", "intstatus=0x%02x\n", - grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS)); + /* There are many ways how the loop above can finish: + * - normally without any error via INTSTATUS WDH bit + * : tderr_phys == td_last_phys, td_head == td_tail + * - normally with error via HALT bit in ED TD HEAD + * : td_head = next TD after TD with error + * : tderr_phys = last processed and retired TD with error, + * i.e. should be != 0 + * : if bad_OHCI == TRUE, tderr_phys will be probably invalid + * - unrecoverable error - I never seen it but it could be + * : err_unrec == TRUE, other values can contain anything... + * - timeout, it can be caused by: + * -- bad USB device - some devices have some bugs, see Linux source + * and related links + * -- bad OHCI controller - e.g. lost interrupts or does not set + * proper bits in INTSTATUS when real IRQ not enabled etc., + * see Linux source and related links + * One known bug is handled - if transfer finished + * successfully (i.e. HEAD==TAIL, last transfer TD is retired, + * HALT bit is not set) and WDH bit is not set in INTSTATUS - in + * this case we set o->bad_OHCI=TRUE and do alternate loop + * and error handling - but there is problem how to find retired + * TD with error code if HALT occurs and if DONEHEAD is not + * working - we need to find TD previous to current ED HEAD + * -- bad code of this driver or some unknown reasons - :-( + * it can be e.g. bad handling of EDs/TDs/toggle bit... + */ - if (!tderr_addr) + /* 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)); + /* Read registers for debug - they should be read now because + * debug prints case unwanted delays, so something can happen + * in the meantime... */ + control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); + status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); + intstatus = grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); + /* 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", "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) ); + + if (!err_halt && !err_unrec && !err_timeout) /* normal finish */ { - /* It means that something wrong happened, - * it could be: - * - timeout and no TD processed - * - some or unrecoverable error and no TD processed - * - something unexpected... :-( */ - /* Try look into DONEHEAD reg., but there should be also zero */ - grub_dprintf("ohci", "HCCA DoneHead is zero, something is bad!\n"); - tderr_addr = grub_ohci_readreg32 (o, GRUB_OHCI_REG_DONEHEAD) & ~0xf; + /* 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; } - - /* Remember last processed transaction (TD) - it is necessary for - * proper setting of toggle bit in next transaction. */ - transfer->last_trans = ((tderr_addr - td_list_addr) / sizeof (*td_list)); - grub_dprintf("ohci", "tderr_addr=0x%x, td_list_addr=0x%x,\n", - tderr_addr, td_list_addr); - if ((ed->td_head & ~0xf) == (ed->td_tail & ~0xf)) - transfer->last_trans = transfer->transcnt - 1; - - /* Check correct value in last_trans */ - /* It could happen if timeout happens and no TD was retired */ - if (transfer->last_trans >= transfer->transcnt || !tderr_addr) + else if (err_halt) /* error, ED is halted by OHCI, i.e. can be modified */ { - grub_dprintf("ohci", "tderr==0 or out of TDs range!\n"); - grub_dprintf("ohci", "last_trans=%d, transcnt=%d\n", - transfer->last_trans, transfer->transcnt); + /* 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; + } + } - /* We should set something valid... */ - transfer->last_trans = -1; /* Probably no TD done */ - tderr_addr = td_list_addr; - } - - /* In case of timeout do not detect error from TD */ - if (err_timeout) - { - err = GRUB_ERR_TIMEOUT; - grub_dprintf("ohci", "Timeout, target=%08x, head=%08x\n", - grub_le_to_cpu32(ed->target), - grub_le_to_cpu32(ed->td_head)); - grub_dprintf("ohci", "tail=%08x, next=%08x\n", - grub_le_to_cpu32(ed->td_tail), - grub_le_to_cpu32(ed->next_ed)); - } - /* In case of unrecoverable error do not detect error from TD */ - else if (err_unrec) - { - err = GRUB_USB_ERR_UNRECOVERABLE; - grub_dprintf("ohci", - "Unrecoverable error, target=%08x, head=%08x\n", - grub_le_to_cpu32(ed->target), - grub_le_to_cpu32(ed->td_head)); - grub_dprintf("ohci", "tail=%08x, next=%08x\n", - grub_le_to_cpu32(ed->td_tail), - grub_le_to_cpu32(ed->next_ed)); - } - else if (grub_le_to_cpu32 (ed->td_head) & 1) - { - grub_uint8_t errcode; - grub_ohci_td_t tderr = NULL; + /* 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; + } - transfer->last_trans--; - - tderr = (grub_ohci_td_t) ((char *) td_list - + (tderr_addr - td_list_addr)); - - errcode = grub_le_to_cpu32 (tderr->token) >> 28; - grub_dprintf ("ohci", "OHCI errcode=0x%02x\n", errcode); + /* 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: @@ -777,16 +1073,17 @@ grub_ohci_transfer (grub_usb_controller_t dev, /* XXX: Data overrun error. */ err = GRUB_USB_ERR_DATA; grub_dprintf ("ohci", "Overrun, failed TD address: %p, index: %d\n", - tderr, transfer->last_trans); + tderr_virt, tderr_virt->tr_index); break; case 9: /* XXX: Data underrun error. */ err = GRUB_USB_ERR_DATA; grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n", - tderr, transfer->last_trans); + tderr_virt, tderr_virt->tr_index); grub_dprintf ("ohci", "Underrun, number of not transferred bytes: %d\n", - 1 + grub_le_to_cpu32 (tderr->buffer_end) - grub_le_to_cpu32 (tderr->buffer)); + 1 + grub_le_to_cpu32 (tderr_virt->buffer_end) + - grub_le_to_cpu32 (tderr_virt->buffer)); break; case 10: @@ -813,69 +1110,100 @@ grub_ohci_transfer (grub_usb_controller_t dev, err = GRUB_USB_ERR_NAK; break; } + } - else - err = GRUB_USB_ERR_NONE; + + 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!"); - /* Disable the Control and Bulk lists. */ - control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL); - control &= ~(3 << 4); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control); + /* Do OHCI reset in case of unrecoverable error - maybe we will need + * do more - re-enumerate bus etc. (?) */ - /* Clear BulkListFilled and ControlListFilled. */ - status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS); - status &= ~(3 << 1); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status); - - /* Set ED to be skipped - for safety */ - ed->target |= grub_cpu_to_le32 (1 << 14); - - /* Now we should wait for start of next frame. - * It is necessary because we will invalidate pointer to ED and it - * can be on OHCI active till SOF! - * Because we are not using interrupt, we reset SF bit and wait when - * it goes to 1. */ - /* 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) - && !err_unrec); - /* Now it should be safe to change CONTROL and BULK lists. */ - - /* Important cleaning. */ + /* 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; + + } + + /* 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); + + /* 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 */ o->hcca->donehead = 0; - grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears WDH */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, 0); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, 0); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 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 (err_unrec) - { - /* Do OHCI reset in case of unrecoverable error - maybe we will need - * do more - re-enumerate bus etc. (?) */ + /* 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); - /* Suspend the OHCI by issuing a reset. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); /* XXX: Magic. */ - grub_millisleep (1); - grub_dprintf ("ohci", "Unrecoverable error - OHCI reset\n"); + 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; + } - /* 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, 0); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, 0); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); - - /* Enable the OHCI. */ - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, (2 << 6)); - } - - grub_dprintf ("ohci", "OHCI finished, freeing, err=0x%02x\n", err); - - grub_dma_free (td_list_chunk); - grub_dma_free (ed_chunk); + grub_dprintf ("ohci", "OHCI finished, freeing, err=0x%02x, errcode=0x%02x\n", + err, errcode); + grub_ohci_free_tds (o, td_head_virt); return err; } @@ -885,10 +1213,28 @@ grub_ohci_portstatus (grub_usb_controller_t dev, unsigned int port, unsigned int enable) { struct grub_ohci *o = (struct grub_ohci *) dev->data; + grub_uint64_t endtime; grub_dprintf ("ohci", "begin of portstatus=0x%02x\n", grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)); + if (!enable) /* We don't need reset port */ + { + /* Disable the port and wait for it. */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_CLEAR_PORT_ENABLE); + 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 - disable"); + + grub_dprintf ("ohci", "end of portstatus=0x%02x\n", + grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)); + 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 */ @@ -898,14 +1244,21 @@ grub_ohci_portstatus (grub_usb_controller_t dev, GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE); grub_millisleep (10); - if (enable) - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, - GRUB_OHCI_SET_PORT_ENABLE); - else - grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, - GRUB_OHCI_CLEAR_PORT_ENABLE); + /* Enable the port and wait for it. */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, + GRUB_OHCI_SET_PORT_ENABLE); + 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); + grub_dprintf ("ohci", "end of portstatus=0x%02x\n", grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)); @@ -913,7 +1266,7 @@ grub_ohci_portstatus (grub_usb_controller_t dev, } static grub_usb_speed_t -grub_ohci_detect_dev (grub_usb_controller_t dev, int port) +grub_ohci_detect_dev (grub_usb_controller_t dev, int port, int *changed) { struct grub_ohci *o = (struct grub_ohci *) dev->data; grub_uint32_t status; @@ -922,6 +1275,9 @@ grub_ohci_detect_dev (grub_usb_controller_t dev, int port) 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); + if (! (status & 1)) return GRUB_USB_SPEED_NONE; else if (status & (1 << 9)) @@ -940,7 +1296,6 @@ grub_ohci_hubports (grub_usb_controller_t dev) grub_dprintf ("ohci", "root hub ports=%d\n", portinfo & 0xFF); - /* The root hub has exactly two ports. */ return portinfo & 0xFF; } @@ -952,10 +1307,32 @@ grub_ohci_fini_hw (int noreturn __attribute__ ((unused))) for (o = ohci; o; o = o->next) { int i, nports = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBA) & 0xff; + grub_uint64_t maxtime; + + /* Set skip in all EDs */ + if (o->ed_bulk) + for (i=0; i < GRUB_OHCI_BULK_EDS; i++) + o->ed_bulk[i].target |= grub_cpu_to_le32 (1 << 14); /* skip */ + if (o->ed_ctrl) + for (i=0; i < GRUB_OHCI_CTRL_EDS; i++) + o->ed_ctrl[i].target |= grub_cpu_to_le32 (1 << 14); /* skip */ + + /* We should wait for next SOF to be sure that all EDs are + * unaccessed by OHCI. But OHCI can be non-functional, so + * more than 1ms timeout have to be applied. */ + /* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */ + grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2)); + maxtime = grub_get_time_ms () + 2; + /* Wait for new SOF or timeout */ + while ( ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) + == 0) || (grub_get_time_ms () >= maxtime) ); + for (i = 0; i < nports; i++) grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + i, GRUB_OHCI_CLEAR_PORT_ENABLE); + grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); + grub_millisleep (1); grub_ohci_writereg32 (o, GRUB_OHCI_REG_HCCA, 0); grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, 0); grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0); @@ -963,7 +1340,22 @@ grub_ohci_fini_hw (int noreturn __attribute__ ((unused))) grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0); grub_ohci_writereg32 (o, GRUB_OHCI_REG_DONEHEAD, 0); grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, 0); - grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); + /* Read back of register should ensure it is really written */ + grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS); + +#if 0 /* Is this necessary before booting? Probably not .(?) + * But it must be done if module is removed ! (Or not ?) + * How to do it ? - Probably grub_ohci_restore_hw should be more + * complicated. (?) + * (If we do it, we need to reallocate EDs and TDs in function + * grub_ohci_restore_hw ! */ + + /* Free allocated EDs and TDs */ + grub_dma_free (o->td_chunk); + grub_dma_free (o->ed_bulk_chunk); + grub_dma_free (o->ed_ctrl_chunk); + grub_dma_free (o->hcca_chunk); +#endif } grub_millisleep (10); @@ -976,7 +1368,23 @@ grub_ohci_restore_hw (void) struct grub_ohci *o; for (o = ohci; o; o = o->next) - grub_ohci_writereg32 (o, GRUB_OHCI_REG_HCCA, o->hcca_addr); + { + grub_ohci_writereg32 (o, GRUB_OHCI_REG_HCCA, o->hcca_addr); + 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 ); + } return GRUB_ERR_NONE; } diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c index 1510f98e8..efdf3aceb 100644 --- a/grub-core/bus/usb/uhci.c +++ b/grub-core/bus/usb/uhci.c @@ -612,8 +612,23 @@ grub_uhci_portstatus (grub_usb_controller_t dev, status = grub_uhci_readreg16 (u, reg); grub_dprintf ("uhci", "detect=0x%02x\n", status); + if (!enable) /* We don't need reset port */ + { + /* Disable the port. */ + grub_uhci_writereg16 (u, reg, 0 << 2); + grub_dprintf ("uhci", "waiting for the port to be disabled\n"); + 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"); + + status = grub_uhci_readreg16 (u, reg); + grub_dprintf ("uhci", ">3detect=0x%02x\n", status); + return GRUB_ERR_NONE; + } + /* Reset the port. */ - grub_uhci_writereg16 (u, reg, enable << 9); + grub_uhci_writereg16 (u, reg, 1 << 9); /* Wait for the reset to complete. XXX: How long exactly? */ grub_millisleep (50); /* For root hub should be nominaly 50ms */ @@ -623,16 +638,20 @@ grub_uhci_portstatus (grub_usb_controller_t dev, grub_millisleep (10); /* Enable the port. */ - grub_uhci_writereg16 (u, reg, enable << 2); + grub_uhci_writereg16 (u, reg, 1 << 2); grub_millisleep (10); grub_dprintf ("uhci", "waiting for the port to be enabled\n"); endtime = grub_get_time_ms () + 1000; - while (! (grub_uhci_readreg16 (u, reg) & (1 << 2))) + while (! ((status = grub_uhci_readreg16 (u, reg)) & (1 << 2))) if (grub_get_time_ms () > endtime) return grub_error (GRUB_ERR_IO, "UHCI Timed out"); + /* Reset bit Connect Status Change */ + grub_uhci_writereg16 (u, reg, status | (1 << 1)); + + /* Read final port status */ status = grub_uhci_readreg16 (u, reg); grub_dprintf ("uhci", ">3detect=0x%02x\n", status); @@ -641,7 +660,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev, } static grub_usb_speed_t -grub_uhci_detect_dev (grub_usb_controller_t dev, int port) +grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed) { struct grub_uhci *u = (struct grub_uhci *) dev->data; int reg; @@ -661,6 +680,9 @@ grub_uhci_detect_dev (grub_usb_controller_t dev, int port) 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)) return GRUB_USB_SPEED_NONE; else if (status & (1 << 8)) diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c index c872e9276..f6a0a8b56 100644 --- a/grub-core/bus/usb/usb.c +++ b/grub-core/bus/usb/usb.c @@ -21,8 +21,10 @@ #include #include #include +#include static grub_usb_controller_dev_t grub_usb_list; +struct grub_usb_attach_desc *attach_hooks; void grub_usb_controller_dev_register (grub_usb_controller_dev_t usb) @@ -164,7 +166,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) * max. size of packet */ dev->descdev.maxsize0 = 0; /* invalidating, for safety only, can be removed if it is sure it is zero here */ err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE, - 0, 8, (char *) &dev->descdev); + 0, 8, (char *) &dev->descdev); if (err) return err; @@ -232,3 +234,75 @@ grub_usb_device_initialize (grub_usb_device_t dev) return err; } + +void grub_usb_device_attach (grub_usb_device_t dev) +{ + int i; + + /* XXX: Just check configuration 0 for now. */ + for (i = 0; i < dev->config[0].descconf->numif; i++) + { + struct grub_usb_desc_if *interf; + struct grub_usb_attach_desc *desc; + + interf = dev->config[0].interf[i].descif; + + grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n", + i, interf->class, interf->subclass, interf->protocol); + + if (dev->config[0].interf[i].attached) + continue; + + for (desc = attach_hooks; desc; desc = desc->next) + if (interf->class == desc->class && desc->hook (dev, 0, i)) + dev->config[0].interf[i].attached = 1; + } +} + +void +grub_usb_register_attach_hook_class (struct grub_usb_attach_desc *desc) +{ + auto int usb_iterate (grub_usb_device_t dev); + + int usb_iterate (grub_usb_device_t usbdev) + { + struct grub_usb_desc_device *descdev = &usbdev->descdev; + int i; + + if (descdev->class != 0 || descdev->subclass || descdev->protocol != 0 + || descdev->configcnt == 0) + return 0; + + /* XXX: Just check configuration 0 for now. */ + for (i = 0; i < usbdev->config[0].descconf->numif; i++) + { + struct grub_usb_desc_if *interf; + + interf = usbdev->config[0].interf[i].descif; + + grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n", + i, interf->class, interf->subclass, interf->protocol); + + if (usbdev->config[0].interf[i].attached) + continue; + + if (interf->class != desc->class) + continue; + if (desc->hook (usbdev, 0, i)) + usbdev->config[0].interf[i].attached = 1; + } + + return 0; + } + + desc->next = attach_hooks; + attach_hooks = desc; + + grub_usb_iterate (usb_iterate); +} + +void +grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc) +{ + grub_list_remove (GRUB_AS_LIST_P (&attach_hooks), GRUB_AS_LIST (desc)); +} diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c index 2bbc850d0..6c14f4b8d 100644 --- a/grub-core/bus/usb/usbhub.c +++ b/grub-core/bus/usb/usbhub.c @@ -23,8 +23,21 @@ #include #include +#define GRUB_USBHUB_MAX_DEVICES 128 + /* USB Supports 127 devices, with device 0 as special case. */ -static struct grub_usb_device *grub_usb_devs[128]; +static struct grub_usb_device *grub_usb_devs[GRUB_USBHUB_MAX_DEVICES]; + +struct grub_usb_hub +{ + struct grub_usb_hub *next; + grub_usb_controller_t controller; + int nports; + grub_usb_speed_t *speed; + grub_usb_device_t dev; +}; + +struct grub_usb_hub *hubs; /* Add a device that currently has device number 0 and resides on CONTROLLER, the Hub reported that the device speed is SPEED. */ @@ -33,6 +46,7 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed) { grub_usb_device_t dev; int i; + grub_usb_err_t err; dev = grub_zalloc (sizeof (struct grub_usb_device)); if (! dev) @@ -41,31 +55,51 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed) dev->controller = *controller; dev->speed = speed; - grub_usb_device_initialize (dev); + err = grub_usb_device_initialize (dev); + if (err) + { + grub_free (dev); + return NULL; + } /* Assign a new address to the device. */ - for (i = 1; i < 128; i++) + for (i = 1; i < GRUB_USBHUB_MAX_DEVICES; i++) { if (! grub_usb_devs[i]) break; } - if (i == 128) + if (i == GRUB_USBHUB_MAX_DEVICES) { grub_error (GRUB_ERR_IO, "can't assign address to USB device"); + for (i = 0; i < 8; i++) + grub_free (dev->config[i].descconf); + grub_free (dev); return NULL; } - grub_usb_control_msg (dev, - (GRUB_USB_REQTYPE_OUT - | GRUB_USB_REQTYPE_STANDARD - | GRUB_USB_REQTYPE_TARGET_DEV), - GRUB_USB_REQ_SET_ADDRESS, - i, 0, 0, NULL); + err = grub_usb_control_msg (dev, + (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_STANDARD + | GRUB_USB_REQTYPE_TARGET_DEV), + GRUB_USB_REQ_SET_ADDRESS, + i, 0, 0, NULL); + if (err) + { + for (i = 0; i < 8; i++) + grub_free (dev->config[i].descconf); + grub_free (dev); + return NULL; + } dev->addr = i; dev->initialized = 1; grub_usb_devs[i] = dev; + /* Wait "recovery interval", spec. says 2ms */ + grub_millisleep (2); + + grub_usb_device_attach (dev); + return dev; } @@ -133,7 +167,7 @@ grub_usb_add_hub (grub_usb_device_t dev) 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) { @@ -180,7 +214,22 @@ grub_usb_add_hub (grub_usb_device_t dev) (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); @@ -196,49 +245,237 @@ grub_usb_add_hub (grub_usb_device_t dev) return GRUB_ERR_NONE; } +static void +attach_root_port (grub_usb_controller_t controller, int portno, + grub_usb_speed_t speed) +{ + grub_usb_device_t dev; + grub_err_t err; + + /* Disable the port. XXX: Why? */ + err = controller->dev->portstatus (controller, portno, 0); + if (err) + return; + + /* Enable the port. */ + err = controller->dev->portstatus (controller, portno, 1); + if (err) + return; + + /* Enable the port and create a device. */ + dev = grub_usb_hub_add_dev (controller, speed); + if (! dev) + return; + + /* If the device is a Hub, scan it for more devices. */ + if (dev->descdev.class == 0x09) + grub_usb_add_hub (dev); +} + grub_usb_err_t grub_usb_root_hub (grub_usb_controller_t controller) { - grub_err_t err; - int ports; int i; + struct grub_usb_hub *hub; + int changed=0; + + hub = grub_malloc (sizeof (*hub)); + if (!hub) + return GRUB_USB_ERR_INTERNAL; + + hub->next = hubs; + hubs = hub; + hub->controller = grub_malloc (sizeof (*controller)); + if (!hub->controller) + { + grub_free (hub); + return GRUB_USB_ERR_INTERNAL; + } + + grub_memcpy (hub->controller, controller, sizeof (*controller)); + hub->dev = 0; /* Query the number of ports the root Hub has. */ - ports = controller->dev->hubports (controller); - - for (i = 0; i < ports; i++) + hub->nports = controller->dev->hubports (controller); + hub->speed = grub_malloc (sizeof (hub->speed[0]) * hub->nports); + if (!hub->speed) { - grub_usb_speed_t speed = controller->dev->detect_dev (controller, i); + grub_free (hub->controller); + grub_free (hub); + return GRUB_USB_ERR_INTERNAL; + } - if (speed != GRUB_USB_SPEED_NONE) - { - grub_usb_device_t dev; + for (i = 0; i < hub->nports; i++) + { + hub->speed[i] = controller->dev->detect_dev (hub->controller, i, + &changed); - /* Enable the port. */ - err = controller->dev->portstatus (controller, i, 1); - if (err) - continue; - - /* Enable the port and create a device. */ - dev = grub_usb_hub_add_dev (controller, speed); - if (! dev) - continue; - - /* If the device is a Hub, scan it for more devices. */ - if (dev->descdev.class == 0x09) - grub_usb_add_hub (dev); - } + if (hub->speed[i] != GRUB_USB_SPEED_NONE) + attach_root_port (hub->controller, i, hub->speed[i]); } return GRUB_USB_ERR_NONE; } +static void +poll_nonroot_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; + + err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN + | GRUB_USB_REQTYPE_CLASS + | GRUB_USB_REQTYPE_TARGET_DEV), + GRUB_USB_REQ_GET_DESCRIPTOR, + (GRUB_USB_DESCRIPTOR_HUB << 8) | 0, + 0, sizeof (hubdesc), (char *) &hubdesc); + if (err) + return; + + /* Iterate over the Hub ports. */ + for (i = 1; i <= hubdesc.portcnt; i++) + { + grub_uint32_t status; + + /* 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; + + /* 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 + { + 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. */ + 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; + + /* Add the device and assign a device address to it. */ + next_dev = grub_usb_hub_add_dev (&dev->controller, speed); + if (! next_dev) + continue; + + /* 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 +grub_usb_poll_devices (void) +{ + struct grub_usb_hub *hub; + int i; + + for (hub = hubs; hub; hub = hub->next) + { + int changed=0; + /* Do we have to recheck number of ports? */ + /* No, it should be never changed, it should be constant. */ + for (i = 0; i < hub->nports; i++) + { + grub_usb_speed_t speed; + + speed = hub->controller->dev->detect_dev (hub->controller, i, + &changed); + + if (speed != GRUB_USB_SPEED_NONE) + { + if (changed) + attach_root_port (hub->controller, i, speed); + } + + /* XXX: There should be also handling + * of disconnected devices. */ + + hub->speed[i] = speed; + } + } + + /* 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); + } + } + +} + int grub_usb_iterate (int (*hook) (grub_usb_device_t dev)) { int i; - for (i = 0; i < 128; i++) + for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++) { if (grub_usb_devs[i]) { diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c index e1b9097e6..4a55cab11 100644 --- a/grub-core/bus/usb/usbtrans.c +++ b/grub-core/bus/usb/usbtrans.c @@ -81,7 +81,7 @@ grub_usb_control_msg (grub_usb_device_t dev, else max = 64; - grub_dprintf ("usb", "transfer = %p, dev = %p\n", transfer, dev); + grub_dprintf ("usb", "control: transfer = %p, dev = %p\n", transfer, dev); datablocks = (size + max - 1) / max; @@ -146,6 +146,7 @@ grub_usb_control_msg (grub_usb_device_t dev, transfer->transactions[datablocks + 1].toggle = 1; err = dev->controller.dev->transfer (&dev->controller, transfer); + grub_dprintf ("usb", "control: err=%d\n", err); grub_free (transfer->transactions); @@ -174,6 +175,8 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, struct grub_pci_dma_chunk *data_chunk; grub_size_t size = size0; + grub_dprintf ("usb", "bulk: size=0x%02x type=%d\n", size, type); + /* FIXME: avoid allocation any kind of buffer in a first place. */ data_chunk = grub_memalign_dma32 (128, size); if (!data_chunk) @@ -248,7 +251,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev, toggle = transfer->transactions[transfer->last_trans].toggle ? 0 : 1; else toggle = dev->toggle[endpoint]; /* Nothing done, take original */ - grub_dprintf ("usb", "toggle=%d\n", toggle); + grub_dprintf ("usb", "bulk: err=%d, toggle=%d\n", err, toggle); dev->toggle[endpoint] = toggle; grub_free (transfer->transactions); diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c index 5bbfd008b..884ddf000 100644 --- a/grub-core/commands/acpi.c +++ b/grub-core/commands/acpi.c @@ -325,7 +325,8 @@ setup_common_tables (void) /* If it's FADT correct DSDT and FACS addresses. */ fadt = (struct grub_acpi_fadt *) cur->addr; - if (grub_memcmp (fadt->hdr.signature, "FACP", 4) == 0) + if (grub_memcmp (fadt->hdr.signature, "FACP", + sizeof (fadt->hdr.signature)) == 0) { fadt->dsdt_addr = PTR_TO_UINT32 (table_dsdt); fadt->facs_addr = facs_addr; @@ -351,16 +352,16 @@ setup_common_tables (void) rsdt_addr = rsdt = (struct grub_acpi_table_header *) playground_ptr; playground_ptr += sizeof (struct grub_acpi_table_header) + 4 * numoftables; - rsdt_entry = (grub_uint32_t *)(rsdt + 1); + rsdt_entry = (grub_uint32_t *) (rsdt + 1); /* Fill RSDT header. */ grub_memcpy (&(rsdt->signature), "RSDT", 4); rsdt->length = sizeof (struct grub_acpi_table_header) + 4 * numoftables; rsdt->revision = 1; - grub_memcpy (&(rsdt->oemid), root_oemid, 6); - grub_memcpy (&(rsdt->oemtable), root_oemtable, 4); + grub_memcpy (&(rsdt->oemid), root_oemid, sizeof (rsdt->oemid)); + grub_memcpy (&(rsdt->oemtable), root_oemtable, sizeof (rsdt->oemtable)); rsdt->oemrev = root_oemrev; - grub_memcpy (&(rsdt->creator_id), root_creator_id, 6); + grub_memcpy (&(rsdt->creator_id), root_creator_id, sizeof (rsdt->creator_id)); rsdt->creator_rev = root_creator_rev; for (cur = acpi_tables; cur; cur = cur->next) @@ -378,7 +379,8 @@ setv1table (void) /* Create RSDP. */ rsdpv1_new = (struct grub_acpi_rsdp_v10 *) playground_ptr; playground_ptr += sizeof (struct grub_acpi_rsdp_v10); - grub_memcpy (&(rsdpv1_new->signature), "RSD PTR ", 8); + grub_memcpy (&(rsdpv1_new->signature), "RSD PTR ", + sizeof (rsdpv1_new->signature)); grub_memcpy (&(rsdpv1_new->oemid), root_oemid, sizeof (rsdpv1_new->oemid)); rsdpv1_new->revision = 0; rsdpv1_new->rsdt_addr = PTR_TO_UINT32 (rsdt_addr); diff --git a/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c index 191c4e4df..213288b52 100644 --- a/grub-core/commands/usbtest.c +++ b/grub-core/commands/usbtest.c @@ -194,6 +194,8 @@ grub_cmd_usbtest (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { + grub_usb_poll_devices (); + grub_printf ("USB devices:\n\n"); grub_usb_iterate (usb_iterate); diff --git a/grub-core/disk/dmraid_nvidia.c b/grub-core/disk/dmraid_nvidia.c index c4e3922cf..d3f45935c 100644 --- a/grub-core/disk/dmraid_nvidia.c +++ b/grub-core/disk/dmraid_nvidia.c @@ -89,7 +89,8 @@ struct grub_nv_super } __attribute__ ((packed)); static grub_err_t -grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) +grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array, + grub_disk_addr_t *start_sector) { grub_disk_addr_t sector; struct grub_nv_super sb; @@ -132,6 +133,7 @@ grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) "unsupported RAID level: %d", sb.array.raid_level); } + array->name = NULL; array->number = 0; array->total_devs = sb.array.total_volumes; array->chunk_size = sb.array.stripe_block_size; @@ -144,6 +146,8 @@ grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array) grub_memcpy (array->uuid, (char *) &sb.array.signature, sizeof (sb.array.signature)); + *start_sector = 0; + return 0; } diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c index 1b525e05f..509e9e33f 100644 --- a/grub-core/disk/loopback.c +++ b/grub-core/disk/loopback.c @@ -28,7 +28,7 @@ struct grub_loopback { char *devname; - char *filename; + grub_file_t file; int has_partitions; struct grub_loopback *next; }; @@ -63,7 +63,7 @@ delete_loopback (const char *name) *prev = dev->next; grub_free (dev->devname); - grub_free (dev->filename); + grub_file_close (dev->file); grub_free (dev); return 0; @@ -76,6 +76,7 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) struct grub_arg_list *state = state = cmd->state; grub_file_t file; struct grub_loopback *newdev; + grub_err_t ret; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); @@ -91,9 +92,6 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) if (! file) return grub_errno; - /* Close the file, the only reason for opening it is validation. */ - grub_file_close (file); - /* First try to replace the old device. */ for (newdev = loopback_list; newdev; newdev = newdev->next) if (grub_strcmp (newdev->devname, args[0]) == 0) @@ -103,10 +101,10 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) { char *newname = grub_strdup (args[1]); if (! newname) - return grub_errno; + goto fail; - grub_free (newdev->filename); - newdev->filename = newname; + grub_file_close (newdev->file); + newdev->file = file; /* Set has_partitions when `--partitions' was used. */ newdev->has_partitions = state[1].set; @@ -117,22 +115,16 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) /* Unable to replace it, make a new entry. */ newdev = grub_malloc (sizeof (struct grub_loopback)); if (! newdev) - return grub_errno; + goto fail; newdev->devname = grub_strdup (args[0]); if (! newdev->devname) { grub_free (newdev); - return grub_errno; + goto fail; } - newdev->filename = grub_strdup (args[1]); - if (! newdev->filename) - { - grub_free (newdev->devname); - grub_free (newdev); - return grub_errno; - } + newdev->file = file; /* Set has_partitions when `--partitions' was used. */ newdev->has_partitions = state[1].set; @@ -142,6 +134,11 @@ grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) loopback_list = newdev; return 0; + +fail: + ret = grub_errno; + grub_file_close (file); + return ret; } @@ -160,7 +157,6 @@ grub_loopback_iterate (int (*hook) (const char *name)) static grub_err_t grub_loopback_open (const char *name, grub_disk_t disk) { - grub_file_t file; struct grub_loopback *dev; for (dev = loopback_list; dev; dev = dev->next) @@ -170,29 +166,17 @@ grub_loopback_open (const char *name, grub_disk_t disk) if (! dev) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); - file = grub_file_open (dev->filename); - if (! file) - return grub_errno; - /* Use the filesize for the disk size, round up to a complete sector. */ - disk->total_sectors = ((file->size + GRUB_DISK_SECTOR_SIZE - 1) + disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1) / GRUB_DISK_SECTOR_SIZE); disk->id = (unsigned long) dev; disk->has_partitions = dev->has_partitions; - disk->data = file; + disk->data = dev->file; return 0; } -static void -grub_loopback_close (grub_disk_t disk) -{ - grub_file_t file = (grub_file_t) disk->data; - - grub_file_close (file); -} - static grub_err_t grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf) @@ -234,7 +218,6 @@ static struct grub_disk_dev grub_loopback_dev = .id = GRUB_DISK_DEVICE_LOOPBACK_ID, .iterate = grub_loopback_iterate, .open = grub_loopback_open, - .close = grub_loopback_close, .read = grub_loopback_read, .write = grub_loopback_write, .next = 0 diff --git a/grub-core/disk/mdraid_linux.c b/grub-core/disk/mdraid_linux.c index 306c66a8b..d5a0aad47 100644 --- a/grub-core/disk/mdraid_linux.c +++ b/grub-core/disk/mdraid_linux.c @@ -1,7 +1,7 @@ -/* mdraid_linux.c - module to handle linux softraid. */ +/* mdraid_linux.c - module to handle Linux Software RAID. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2008 Free Software Foundation, Inc. + * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -159,63 +159,254 @@ struct grub_raid_super_09 struct grub_raid_disk_09 this_disk; } __attribute__ ((packed)); -static grub_err_t -grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array) +/* + * The version-1 superblock : + * All numeric fields are little-endian. + * + * Total size: 256 bytes plus 2 per device. + * 1K allows 384 devices. + */ + +struct grub_raid_super_1x +{ + /* Constant array information - 128 bytes. */ + grub_uint32_t magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian. */ + grub_uint32_t major_version; /* 1. */ + grub_uint32_t feature_map; /* Bit 0 set if 'bitmap_offset' is meaningful. */ + grub_uint32_t pad0; /* Always set to 0 when writing. */ + + grub_uint8_t set_uuid[16]; /* User-space generated. */ + char set_name[32]; /* Set and interpreted by user-space. */ + + grub_uint64_t ctime; /* Lo 40 bits are seconds, top 24 are microseconds or 0. */ + grub_uint32_t level; /* -4 (multipath), -1 (linear), 0,1,4,5. */ + grub_uint32_t layout; /* only for raid5 and raid10 currently. */ + grub_uint64_t size; /* Used size of component devices, in 512byte sectors. */ + + grub_uint32_t chunksize; /* In 512byte sectors. */ + grub_uint32_t raid_disks; + grub_uint32_t bitmap_offset; /* Sectors after start of superblock that bitmap starts + * NOTE: signed, so bitmap can be before superblock + * only meaningful of feature_map[0] is set. + */ + + /* These are only valid with feature bit '4'. */ + grub_uint32_t new_level; /* New level we are reshaping to. */ + grub_uint64_t reshape_position; /* Next address in array-space for reshape. */ + grub_uint32_t delta_disks; /* Change in number of raid_disks. */ + grub_uint32_t new_layout; /* New layout. */ + grub_uint32_t new_chunk; /* New chunk size (512byte sectors). */ + grub_uint8_t pad1[128 - 124]; /* Set to 0 when written. */ + + /* Constant this-device information - 64 bytes. */ + grub_uint64_t data_offset; /* Sector start of data, often 0. */ + grub_uint64_t data_size; /* Sectors in this device that can be used for data. */ + grub_uint64_t super_offset; /* Sector start of this superblock. */ + grub_uint64_t recovery_offset; /* Sectors before this offset (from data_offset) have been recovered. */ + grub_uint32_t dev_number; /* Permanent identifier of this device - not role in raid. */ + grub_uint32_t cnt_corrected_read; /* Number of read errors that were corrected by re-writing. */ + grub_uint8_t device_uuid[16]; /* User-space setable, ignored by kernel. */ + grub_uint8_t devflags; /* Per-device flags. Only one defined... */ + grub_uint8_t pad2[64 - 57]; /* Set to 0 when writing. */ + + /* Array state information - 64 bytes. */ + grub_uint64_t utime; /* 40 bits second, 24 btes microseconds. */ + grub_uint64_t events; /* Incremented when superblock updated. */ + grub_uint64_t resync_offset; /* Data before this offset (from data_offset) known to be in sync. */ + grub_uint32_t sb_csum; /* Checksum upto devs[max_dev]. */ + grub_uint32_t max_dev; /* Size of devs[] array to consider. */ + grub_uint8_t pad3[64 - 32]; /* Set to 0 when writing. */ + + /* Device state information. Indexed by dev_number. + * 2 bytes per device. + * Note there are no per-device state flags. State information is rolled + * into the 'roles' value. If a device is spare or faulty, then it doesn't + * have a meaningful role. + */ + grub_uint16_t dev_roles[0]; /* Role in array, or 0xffff for a spare, or 0xfffe for faulty. */ +}; +/* Could be __attribute__ ((packed)), but since all members in this struct + are already appropriately aligned, we can omit this and avoid suboptimal + assembly in some cases. */ + +#define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */ + +static grub_err_t +grub_mdraid_detect_09 (grub_disk_addr_t sector, + struct grub_raid_super_09 *sb, + struct grub_raid_array *array, + grub_disk_addr_t *start_sector) { - grub_disk_addr_t sector; - grub_uint64_t size; - struct grub_raid_super_09 sb; grub_uint32_t *uuid; - /* The sector where the RAID superblock is stored, if available. */ - size = grub_disk_get_size (disk); - sector = NEW_SIZE_SECTORS (size); - - if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb)) - return grub_errno; - - /* Look whether there is a RAID superblock. */ - if (sb.md_magic != SB_MAGIC) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); - - /* FIXME: Also support version 1.0. */ - if (sb.major_version != 0 || sb.minor_version != 90) + if (sb->major_version != 0 || sb->minor_version != 90) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unsupported RAID version: %d.%d", - sb.major_version, sb.minor_version); + sb->major_version, sb->minor_version); - /* FIXME: Check the checksum. */ + /* FIXME: Check the checksum. */ /* Multipath. */ - if ((int) sb.level == -4) - sb.level = 1; + if ((int) sb->level == -4) + sb->level = 1; - if (sb.level != 0 && sb.level != 1 && sb.level != 4 && - sb.level != 5 && sb.level != 6 && sb.level != 10) + if (sb->level != 0 && sb->level != 1 && sb->level != 4 && + sb->level != 5 && sb->level != 6 && sb->level != 10) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported RAID level: %d", sb.level); + "unsupported RAID level: %d", sb->level); - array->number = sb.md_minor; - array->level = sb.level; - array->layout = sb.layout; - array->total_devs = sb.raid_disks; - array->disk_size = (sb.size) ? sb.size * 2 : sector; - array->chunk_size = sb.chunk_size >> 9; - array->index = sb.this_disk.number; + array->name = NULL; + array->number = sb->md_minor; + array->level = sb->level; + array->layout = sb->layout; + array->total_devs = sb->raid_disks; + array->disk_size = (sb->size) ? sb->size * 2 : sector; + array->chunk_size = sb->chunk_size >> 9; + array->index = sb->this_disk.number; array->uuid_len = 16; array->uuid = grub_malloc (16); if (!array->uuid) - return grub_errno; + return grub_errno; uuid = (grub_uint32_t *) array->uuid; - uuid[0] = sb.set_uuid0; - uuid[1] = sb.set_uuid1; - uuid[2] = sb.set_uuid2; - uuid[3] = sb.set_uuid3; + uuid[0] = sb->set_uuid0; + uuid[1] = sb->set_uuid1; + uuid[2] = sb->set_uuid2; + uuid[3] = sb->set_uuid3; + + *start_sector = 0; return 0; } +static grub_err_t +grub_mdraid_detect_1x (grub_disk_t disk, grub_disk_addr_t sector, + struct grub_raid_super_1x *sb, + struct grub_raid_array *array, + grub_disk_addr_t *start_sector) +{ + grub_uint64_t sb_size; + struct grub_raid_super_1x *real_sb; + + if (sb->major_version != 1) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID version: %d", + sb->major_version); + + /* Multipath. */ + if ((int) sb->level == -4) + sb->level = 1; + + if (sb->level != 0 && sb->level != 1 && sb->level != 4 && + sb->level != 5 && sb->level != 6 && sb->level != 10) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "Unsupported RAID level: %d", sb->level); + + /* 1.x superblocks don't have a fixed size on disk. So we have to + read it again now that we now the max device count. */ + sb_size = sizeof (struct grub_raid_super_1x) + 2 * grub_le_to_cpu32 (sb->max_dev); + real_sb = grub_malloc (sb_size); + if (! real_sb) + return grub_errno; + + if (grub_disk_read (disk, sector, 0, sb_size, real_sb)) + { + grub_free (real_sb); + return grub_errno; + } + + array->name = grub_strdup (real_sb->set_name); + if (! array->name) + { + grub_free (real_sb); + return grub_errno; + } + + array->number = 0; + array->level = grub_le_to_cpu32 (real_sb->level); + array->layout = grub_le_to_cpu32 (real_sb->layout); + array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks); + array->disk_size = grub_le_to_cpu64 (real_sb->size); + array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize); + if (grub_le_to_cpu32 (real_sb->dev_number) < + grub_le_to_cpu32 (real_sb->max_dev)) + array->index = grub_le_to_cpu16 + (real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]); + else + array->index = 0xffff; /* disk will be later not used! */ + array->uuid_len = 16; + array->uuid = grub_malloc (16); + if (!array->uuid) + { + grub_free (real_sb); + return grub_errno; + } + + grub_memcpy (array->uuid, real_sb->set_uuid, 16); + + *start_sector = real_sb->data_offset; + + grub_free (real_sb); + return 0; +} + +static grub_err_t +grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array, + grub_disk_addr_t *start_sector) +{ + grub_disk_addr_t sector; + grub_uint64_t size; + struct grub_raid_super_09 sb_09; + struct grub_raid_super_1x sb_1x; + grub_uint8_t minor_version; + + /* The sector where the mdraid 0.90 superblock is stored, if available. */ + size = grub_disk_get_size (disk); + sector = NEW_SIZE_SECTORS (size); + + if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb_09)) + return grub_errno; + + /* Look whether there is a mdraid 0.90 superblock. */ + if (sb_09.md_magic == SB_MAGIC) + return grub_mdraid_detect_09 (sector, &sb_09, array, start_sector); + + /* Check for an 1.x superblock. + * It's always aligned to a 4K boundary + * and depending on the minor version it can be: + * 0: At least 8K, but less than 12K, from end of device + * 1: At start of device + * 2: 4K from start of device. + */ + + for (minor_version = 0; minor_version < 3; ++minor_version) + { + switch (minor_version) + { + case 0: + sector = (size - 8 * 2) & ~(4 * 2 - 1); + break; + case 1: + sector = 0; + break; + case 2: + sector = 4 * 2; + break; + } + + if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x), + &sb_1x)) + return grub_errno; + + if (sb_1x.magic == SB_MAGIC) + return grub_mdraid_detect_1x (disk, sector, &sb_1x, array, + start_sector); + } + + /* Neither 0.90 nor 1.x. */ + return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid"); +} + static struct grub_raid grub_mdraid_dev = { .name = "mdraid", .detect = grub_mdraid_detect, diff --git a/grub-core/disk/raid.c b/grub-core/disk/raid.c index 2d544afdc..51a4b00e2 100644 --- a/grub-core/disk/raid.c +++ b/grub-core/disk/raid.c @@ -1,7 +1,7 @@ /* raid.c - module to read RAID arrays. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -254,7 +254,8 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, grub_errno = GRUB_ERR_NONE; err = grub_disk_read (array->device[k], - read_sector + j * far_ofs + b, + array->start_sector[k] + + read_sector + j * far_ofs + b, 0, read_size << GRUB_DISK_SECTOR_BITS, buf); @@ -366,7 +367,8 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector, grub_errno = GRUB_ERR_NONE; err = grub_disk_read (array->device[disknr], - read_sector + b, 0, + array->start_sector[disknr] + + read_sector + b, 0, read_size << GRUB_DISK_SECTOR_BITS, buf); @@ -475,12 +477,12 @@ grub_raid_write (grub_disk_t disk __attribute ((unused)), static grub_err_t insert_array (grub_disk_t disk, struct grub_raid_array *new_array, - const char *scanner_name) + grub_disk_addr_t start_sector, const char *scanner_name) { struct grub_raid_array *array = 0, *p; /* See whether the device is part of an array we have already seen a - device from. */ + device from. */ for (p = array_list; p != NULL; p = p->next) if ((p->uuid_len == new_array->uuid_len) && (! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len))) @@ -491,7 +493,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, /* Do some checks before adding the device to the array. */ /* FIXME: Check whether the update time of the superblocks are - the same. */ + the same. */ if (array->total_devs == array->nr_devs) /* We found more members of the array than the array @@ -502,7 +504,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, if (array->device[new_array->index] != NULL) /* We found multiple devices with the same number. Again, - this shouldn't happen.*/ + this shouldn't happen. */ grub_dprintf ("raid", "Found two disks with the number %d?!?", new_array->number); @@ -524,46 +526,75 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, *array = *new_array; array->nr_devs = 0; grub_memset (&array->device, 0, sizeof (array->device)); + grub_memset (&array->start_sector, 0, sizeof (array->start_sector)); - /* Check whether we don't have multiple arrays with the same number. */ - for (p = array_list; p != NULL; p = p->next) - { - if (p->number == array->number) - break; - } - - if (p) - { - /* The number is already in use, so we need to find an new number. */ - int i = 0; - - while (1) - { - for (p = array_list; p != NULL; p = p->next) - { - if (p->number == i) - break; - } - - if (!p) - { - /* We found an unused number. */ - array->number = i; - break; - } - - i++; - } - } - - array->name = grub_xasprintf ("md%d", array->number); if (! array->name) - { - grub_free (array->uuid); - grub_free (array); + { + for (p = array_list; p != NULL; p = p->next) + { + if (! p->name && p->number == array->number) + break; + } + } - return grub_errno; - } + if (array->name || p) + { + /* The number is already in use, so we need to find a new one. + (Or, in the case of named arrays, the array doesn't have its + own number, but we need one that doesn't clash for use as a key + in the disk cache. */ + int i = array->name ? 0x40000000 : 0; + + while (1) + { + for (p = array_list; p != NULL; p = p->next) + { + if (p->number == i) + break; + } + + if (! p) + { + /* We found an unused number. */ + array->number = i; + break; + } + + i++; + } + } + + /* mdraid 1.x superblocks have only a name stored not a number. + Use it directly as GRUB device. */ + if (! array->name) + { + array->name = grub_xasprintf ("md%d", array->number); + if (! array->name) + { + grub_free (array->uuid); + grub_free (array); + + return grub_errno; + } + } + else + { + /* Strip off the homehost if present. */ + char *colon = grub_strchr (array->name, ':'); + char *new_name = grub_xasprintf ("md/%s", + colon ? colon + 1 : array->name); + + if (! new_name) + { + grub_free (array->uuid); + grub_free (array); + + return grub_errno; + } + + grub_free (array->name); + array->name = new_name; + } grub_dprintf ("raid", "Found array %s (%s)\n", array->name, scanner_name); @@ -580,6 +611,7 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array, /* Add the device to the array. */ array->device[new_array->index] = disk; + array->start_sector[new_array->index] = start_sector; array->nr_devs++; return 0; @@ -621,6 +653,7 @@ grub_raid_register (grub_raid_t raid) { grub_disk_t disk; struct grub_raid_array array; + grub_disk_addr_t start_sector; grub_dprintf ("raid", "Scanning for RAID devices on disk %s\n", name); @@ -629,8 +662,8 @@ grub_raid_register (grub_raid_t raid) return 0; if ((disk->total_sectors != GRUB_ULONG_MAX) && - (! grub_raid_list->detect (disk, &array)) && - (! insert_array (disk, &array, grub_raid_list->name))) + (! grub_raid_list->detect (disk, &array, &start_sector)) && + (! insert_array (disk, &array, start_sector, grub_raid_list->name))) return 0; /* This error usually means it's not raid, no need to display diff --git a/grub-core/disk/scsi.c b/grub-core/disk/scsi.c index 5f04d9ef7..60192bef5 100644 --- a/grub-core/disk/scsi.c +++ b/grub-core/disk/scsi.c @@ -402,7 +402,7 @@ grub_scsi_open (const char *name, grub_disk_t disk) if (p->open (bus, scsi)) continue; - disk->id = grub_make_scsi_id (scsi->dev->id, bus, lun); + disk->id = grub_make_scsi_id (p->id, bus, lun); disk->data = scsi; scsi->dev = p; scsi->lun = lun; diff --git a/grub-core/disk/usbms.c b/grub-core/disk/usbms.c index 1301791e5..225761e0f 100644 --- a/grub-core/disk/usbms.c +++ b/grub-core/disk/usbms.c @@ -52,20 +52,19 @@ struct grub_usbms_dev int luns; + int config; int interface; struct grub_usb_desc_endp *in; struct grub_usb_desc_endp *out; int in_maxsz; int out_maxsz; - - struct grub_usbms_dev *next; }; typedef struct grub_usbms_dev *grub_usbms_dev_t; -static grub_usbms_dev_t grub_usbms_dev_list; - -static int devcnt; +/* FIXME: remove limit. */ +#define MAX_USBMS_DEVICES 128 +static grub_usbms_dev_t grub_usbms_devices[MAX_USBMS_DEVICES]; static grub_err_t grub_usbms_reset (grub_usb_device_t dev, int interface) @@ -74,149 +73,133 @@ grub_usbms_reset (grub_usb_device_t dev, int interface) } static void -grub_usbms_finddevs (void) +grub_usbms_detach (grub_usb_device_t usbdev, int config, int interface) { - auto int usb_iterate (grub_usb_device_t dev); + unsigned i; + for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++) + if (grub_usbms_devices[i] && grub_usbms_devices[i]->dev == usbdev + && grub_usbms_devices[i]->interface == interface + && grub_usbms_devices[i]->config == config) + { + grub_free (grub_usbms_devices[i]); + grub_usbms_devices[i] = 0; + } +} - int usb_iterate (grub_usb_device_t usbdev) +static int +grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno) +{ + struct grub_usb_desc_if *interf + = usbdev->config[configno].interf[interfno].descif; + int j; + grub_uint8_t luns = 0; + unsigned curnum; + grub_usb_err_t err; + + for (curnum = 0; curnum < ARRAY_SIZE (grub_usbms_devices); curnum++) + if (!grub_usbms_devices[curnum]) + break; + + if (curnum == ARRAY_SIZE (grub_usbms_devices)) + return 0; + + interf = usbdev->config[configno].interf[interfno].descif; + + if ((interf->subclass != GRUB_USBMS_SUBCLASS_BULK + /* Experimental support of RBC, MMC-2, UFI, SFF-8070i devices */ + && interf->subclass != GRUB_USBMS_SUBCLASS_RBC + && interf->subclass != GRUB_USBMS_SUBCLASS_MMC2 + && interf->subclass != GRUB_USBMS_SUBCLASS_UFI + && interf->subclass != GRUB_USBMS_SUBCLASS_SFF8070 ) + || interf->protocol != GRUB_USBMS_PROTOCOL_BULK) + return 0; + + grub_usbms_devices[curnum] = grub_zalloc (sizeof (struct grub_usbms_dev)); + if (! grub_usbms_devices[curnum]) + return 0; + + grub_usbms_devices[curnum]->dev = usbdev; + grub_usbms_devices[curnum]->interface = interfno; + + grub_dprintf ("usbms", "alive\n"); + + /* Iterate over all endpoints of this interface, at least a + IN and OUT bulk endpoint are required. */ + for (j = 0; j < interf->endpointcnt; j++) { - grub_usb_err_t err; - struct grub_usb_desc_device *descdev = &usbdev->descdev; - int i; + struct grub_usb_desc_endp *endp; + endp = &usbdev->config[0].interf[interfno].descendp[j]; - if (descdev->class != 0 || descdev->subclass || descdev->protocol != 0 - || descdev->configcnt == 0) - return 0; - - /* XXX: Just check configuration 0 for now. */ - for (i = 0; i < usbdev->config[0].descconf->numif; i++) + if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2) { - struct grub_usbms_dev *usbms; - struct grub_usb_desc_if *interf; - int j; - grub_uint8_t luns = 0; - - grub_dprintf ("usbms", "alive\n"); - - interf = usbdev->config[0].interf[i].descif; - - /* If this is not a USB Mass Storage device with a supported - protocol, just skip it. */ - grub_dprintf ("usbms", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n", - i, interf->class, interf->subclass, interf->protocol); - - if (interf->class != GRUB_USB_CLASS_MASS_STORAGE - || ( interf->subclass != GRUB_USBMS_SUBCLASS_BULK && - /* Experimental support of RBC, MMC-2, UFI, SFF-8070i devices */ - interf->subclass != GRUB_USBMS_SUBCLASS_RBC && - interf->subclass != GRUB_USBMS_SUBCLASS_MMC2 && - interf->subclass != GRUB_USBMS_SUBCLASS_UFI && - interf->subclass != GRUB_USBMS_SUBCLASS_SFF8070 ) - || interf->protocol != GRUB_USBMS_PROTOCOL_BULK) - { - continue; - } - - grub_dprintf ("usbms", "alive\n"); - - devcnt++; - usbms = grub_zalloc (sizeof (struct grub_usbms_dev)); - if (! usbms) - return 1; - - usbms->dev = usbdev; - usbms->interface = i; - - grub_dprintf ("usbms", "alive\n"); - - /* Iterate over all endpoints of this interface, at least a - IN and OUT bulk endpoint are required. */ - for (j = 0; j < interf->endpointcnt; j++) - { - struct grub_usb_desc_endp *endp; - endp = &usbdev->config[0].interf[i].descendp[j]; - - if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2) - { - /* Bulk IN endpoint. */ - usbms->in = endp; - /* Clear Halt is not possible yet! */ - /* grub_usb_clear_halt (usbdev, endp->endp_addr); */ - usbms->in_maxsz = endp->maxpacket; - } - else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2) - { - /* Bulk OUT endpoint. */ - usbms->out = endp; - /* Clear Halt is not possible yet! */ - /* grub_usb_clear_halt (usbdev, endp->endp_addr); */ - usbms->out_maxsz = endp->maxpacket; - } - } - - if (!usbms->in || !usbms->out) - { - grub_free (usbms); - return 0; - } - - grub_dprintf ("usbms", "alive\n"); - - /* XXX: Activate the first configuration. */ - grub_usb_set_configuration (usbdev, 1); - - /* Query the amount of LUNs. */ - err = grub_usb_control_msg (usbdev, 0xA1, 254, - 0, i, 1, (char *) &luns); - - if (err) - { - /* In case of a stall, clear the stall. */ - if (err == GRUB_USB_ERR_STALL) - { - grub_usb_clear_halt (usbdev, usbms->in->endp_addr); - grub_usb_clear_halt (usbdev, usbms->out->endp_addr); - } - /* Just set the amount of LUNs to one. */ - grub_errno = GRUB_ERR_NONE; - usbms->luns = 1; - } - else - /* luns = 0 means one LUN with ID 0 present ! */ - /* We get from device not number of LUNs but highest - * LUN number. LUNs are numbered from 0, - * i.e. number of LUNs is luns+1 ! */ - usbms->luns = luns + 1; - - grub_dprintf ("usbms", "alive\n"); - - usbms->next = grub_usbms_dev_list; - grub_usbms_dev_list = usbms; - -#if 0 /* All this part should be probably deleted. - * This make trouble on some devices if they are not in - * Phase Error state - and there they should be not in such state... - * Bulk only mass storage reset procedure should be used only - * on place and in time when it is really necessary. */ - /* Reset recovery procedure */ - /* Bulk-Only Mass Storage Reset, after the reset commands - will be accepted. */ - grub_usbms_reset (usbdev, i); - grub_usb_clear_halt (usbdev, usbms->in->endp_addr); - grub_usb_clear_halt (usbdev, usbms->out->endp_addr); -#endif - - return 0; + /* Bulk IN endpoint. */ + grub_usbms_devices[curnum]->in = endp; + /* Clear Halt is not possible yet! */ + /* grub_usb_clear_halt (usbdev, endp->endp_addr); */ + grub_usbms_devices[curnum]->in_maxsz = endp->maxpacket; } + else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2) + { + /* Bulk OUT endpoint. */ + grub_usbms_devices[curnum]->out = endp; + /* Clear Halt is not possible yet! */ + /* grub_usb_clear_halt (usbdev, endp->endp_addr); */ + grub_usbms_devices[curnum]->out_maxsz = endp->maxpacket; + } + } - grub_dprintf ("usbms", "alive\n"); + if (!grub_usbms_devices[curnum]->in || !grub_usbms_devices[curnum]->out) + { + grub_free (grub_usbms_devices[curnum]); + grub_usbms_devices[curnum] = 0; return 0; } + grub_dprintf ("usbms", "alive\n"); - grub_usb_iterate (usb_iterate); + /* XXX: Activate the first configuration. */ + grub_usb_set_configuration (usbdev, 1); + + /* Query the amount of LUNs. */ + err = grub_usb_control_msg (usbdev, 0xA1, 254, 0, interfno, 1, (char *) &luns); + + if (err) + { + /* In case of a stall, clear the stall. */ + if (err == GRUB_USB_ERR_STALL) + { + grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->in->endp_addr); + grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->out->endp_addr); + } + /* Just set the amount of LUNs to one. */ + grub_errno = GRUB_ERR_NONE; + grub_usbms_devices[curnum]->luns = 1; + } + else + /* luns = 0 means one LUN with ID 0 present ! */ + /* We get from device not number of LUNs but highest + * LUN number. LUNs are numbered from 0, + * i.e. number of LUNs is luns+1 ! */ + grub_usbms_devices[curnum]->luns = luns + 1; + grub_dprintf ("usbms", "alive\n"); + usbdev->config[configno].interf[interfno].detach_hook = grub_usbms_detach; + +#if 0 /* All this part should be probably deleted. + * This make trouble on some devices if they are not in + * Phase Error state - and there they should be not in such state... + * Bulk only mass storage reset procedure should be used only + * on place and in time when it is really necessary. */ + /* Reset recovery procedure */ + /* Bulk-Only Mass Storage Reset, after the reset commands + will be accepted. */ + grub_usbms_reset (usbdev, i); + grub_usb_clear_halt (usbdev, usbms->in->endp_addr); + grub_usb_clear_halt (usbdev, usbms->out->endp_addr); +#endif + + return 1; } @@ -224,15 +207,16 @@ grub_usbms_finddevs (void) static int grub_usbms_iterate (int (*hook) (int bus, int luns)) { - grub_usbms_dev_t p; - int cnt = 0; + unsigned i; - for (p = grub_usbms_dev_list; p; p = p->next) - { - if (hook (cnt, p->luns)) - return 1; - cnt++; - } + grub_usb_poll_devices (); + + for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++) + if (grub_usbms_devices[i]) + { + if (hook (i, grub_usbms_devices[i]->luns)) + return 1; + } return 0; } @@ -248,7 +232,6 @@ grub_usbms_transfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd, grub_usb_err_t err = GRUB_USB_ERR_NONE; grub_usb_err_t errCSW = GRUB_USB_ERR_NONE; int retrycnt = 3 + 1; - grub_size_t i; retry: retrycnt--; @@ -304,8 +287,11 @@ grub_usbms_transfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd, /* Debug print of received data. */ grub_dprintf ("usb", "buf:\n"); if (size <= 64) - for (i=0; idev, dev->out->endp_addr, size, buf); grub_dprintf ("usb", "write: %d %d\n", err, GRUB_USB_ERR_STALL); - grub_dprintf ("usb", "buf:\n"); + grub_dprintf ("usb", "First 16 bytes of sent data:\n %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[ 0], buf[ 1], buf[ 2], buf[ 3], + buf[ 4], buf[ 5], buf[ 6], buf[ 7], + buf[ 8], buf[ 9], buf[10], buf[11], + buf[12], buf[13], buf[14], buf[15]); if (err) { if (err == GRUB_USB_ERR_STALL) @@ -322,8 +312,11 @@ grub_usbms_transfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd, } /* Debug print of sent data. */ if (size <= 256) - for (i=0; inext) - { - /* Check if this is the devnumth device. */ - if (devnum == i) - { - scsi->data = p; - scsi->luns = p->luns; - return GRUB_ERR_NONE; - } + if (!grub_usbms_devices[devnum]) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, + "unknown USB Mass Storage device"); - i++; - } + scsi->data = grub_usbms_devices[devnum]; + scsi->luns = grub_usbms_devices[devnum]->luns; - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, - "not a USB Mass Storage device"); + return GRUB_ERR_NONE; } static struct grub_scsi_dev grub_usbms_dev = @@ -423,13 +408,28 @@ static struct grub_scsi_dev grub_usbms_dev = .write = grub_usbms_write }; +struct grub_usb_attach_desc attach_hook = +{ + .class = GRUB_USB_CLASS_MASS_STORAGE, + .hook = grub_usbms_attach +}; + GRUB_MOD_INIT(usbms) { - grub_usbms_finddevs (); + grub_usb_register_attach_hook_class (&attach_hook); grub_scsi_dev_register (&grub_usbms_dev); } GRUB_MOD_FINI(usbms) { + unsigned i; + for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++) + { + grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config] + .interf[grub_usbms_devices[i]->interface].detach_hook = 0; + grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config] + .interf[grub_usbms_devices[i]->interface].attached = 0; + } + grub_usb_unregister_attach_hook_class (&attach_hook); grub_scsi_dev_unregister (&grub_usbms_dev); } diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c index 5d32f5f88..8329c01a1 100644 --- a/grub-core/fs/nilfs2.c +++ b/grub-core/fs/nilfs2.c @@ -52,9 +52,9 @@ /* nilfs 1st super block posission from beginning of the partition in 512 block size */ #define NILFS_1ST_SUPER_BLOCK 2 -/* nilfs 2nd super block posission from end of the partition +/* nilfs 2nd super block posission from beginning of the partition in 512 block size */ -#define NILFS_2ND_SUPER_BLOCK 8 +#define NILFS_2ND_SUPER_BLOCK(devsize) (((devsize >> 3) - 1) << 3) struct grub_nilfs2_inode { @@ -729,7 +729,7 @@ grub_nilfs2_load_sb (struct grub_nilfs2_data *data) if (partition_size != GRUB_DISK_SIZE_UNKNOWN) { /* Read second super block. */ - grub_disk_read (disk, partition_size - NILFS_2ND_SUPER_BLOCK, 0, + grub_disk_read (disk, NILFS_2ND_SUPER_BLOCK (partition_size), 0, sizeof (struct grub_nilfs2_super_block), &sb2); /* Make sure if 2nd super block is valid. */ valid[1] = grub_nilfs2_valid_sb (&sb2); diff --git a/grub-core/kern/emu/getroot.c b/grub-core/kern/emu/getroot.c index 24b2cd486..c0a10d22b 100644 --- a/grub-core/kern/emu/getroot.c +++ b/grub-core/kern/emu/getroot.c @@ -1,7 +1,7 @@ /* getroot.c - Get root device */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009 Free Software Foundation, Inc. + * Copyright (C) 1999,2000,2001,2002,2003,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 @@ -20,14 +20,17 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include #ifdef __GNU__ #include @@ -36,6 +39,16 @@ #include #endif +#ifdef __linux__ +# include +# include +#endif + +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) +# include +# include +#endif + #include #include #include @@ -161,6 +174,58 @@ find_root_device_from_mountinfo (const char *dir) #endif /* __linux__ */ +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) +static char * +find_root_device_from_libzfs (const char *dir) +{ + char *device; + char *poolname; + char *poolfs; + + grub_find_zpool_from_dir (dir, &poolname, &poolfs); + if (! poolname) + return NULL; + + { + zpool_handle_t *zpool; + libzfs_handle_t *libzfs; + nvlist_t *nvlist; + nvlist_t **nvlist_array; + unsigned int nvlist_count; + + libzfs = grub_get_libzfs_handle (); + if (! libzfs) + return NULL; + + zpool = zpool_open (libzfs, poolname); + nvlist = zpool_get_config (zpool, NULL); + + if (nvlist_lookup_nvlist (nvlist, "vdev_tree", &nvlist) != 0) + error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")"); + + if (nvlist_lookup_nvlist_array (nvlist, "children", &nvlist_array, &nvlist_count) != 0) + error (1, errno, "nvlist_lookup_nvlist_array (\"children\")"); + + do + { + assert (nvlist_count > 0); + } while (nvlist_lookup_nvlist_array (nvlist_array[0], "children", + &nvlist_array, &nvlist_count) == 0); + + if (nvlist_lookup_string (nvlist_array[0], "path", &device) != 0) + error (1, errno, "nvlist_lookup_string (\"path\")"); + + zpool_close (zpool); + } + + free (poolname); + if (poolfs) + free (poolfs); + + return device; +} +#endif + #ifdef __MINGW32__ static char * @@ -453,6 +518,12 @@ grub_guess_root_device (const char *dir) return os_dev; #endif /* __linux__ */ +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + os_dev = find_root_device_from_libzfs (dir); + if (os_dev) + return os_dev; +#endif + if (stat (dir, &st) < 0) grub_util_error ("cannot stat `%s'", dir); @@ -516,10 +587,89 @@ grub_util_get_dev_abstraction (const char *os_dev __attribute__((unused))) return GRUB_DEV_ABSTRACTION_NONE; } +#ifdef __linux__ +static char * +get_mdadm_name (const char *os_dev) +{ + int mdadm_pipe[2]; + pid_t mdadm_pid; + char *name = NULL; + + if (pipe (mdadm_pipe) < 0) + { + grub_util_warn ("Unable to create pipe for mdadm: %s", strerror (errno)); + return NULL; + } + + mdadm_pid = fork (); + if (mdadm_pid < 0) + grub_util_warn ("Unable to fork mdadm: %s", strerror (errno)); + else if (mdadm_pid == 0) + { + /* Child. */ + char *argv[5]; + + close (mdadm_pipe[0]); + dup2 (mdadm_pipe[1], STDOUT_FILENO); + close (mdadm_pipe[1]); + + /* execvp has inconvenient types, hence the casts. None of these + strings will actually be modified. */ + argv[0] = (char *) "mdadm"; + argv[1] = (char *) "--detail"; + argv[2] = (char *) "--export"; + argv[3] = (char *) os_dev; + argv[4] = NULL; + execvp ("mdadm", argv); + exit (127); + } + else + { + /* Parent. Read mdadm's output. */ + FILE *mdadm; + char *buf = NULL; + size_t len = 0; + + close (mdadm_pipe[1]); + mdadm = fdopen (mdadm_pipe[0], "r"); + if (! mdadm) + { + grub_util_warn ("Unable to open stream from mdadm: %s", + strerror (errno)); + goto out; + } + + while (getline (&buf, &len, mdadm) > 0) + { + if (strncmp (buf, "MD_NAME=", sizeof ("MD_NAME=") - 1) == 0) + { + char *name_start, *colon; + size_t name_len; + + free (name); + name_start = buf + sizeof ("MD_NAME=") - 1; + /* Strip off the homehost if present. */ + colon = strchr (name_start, ':'); + name = strdup (colon ? colon + 1 : name_start); + name_len = strlen (name); + if (name[name_len - 1] == '\n') + name[name_len - 1] = '\0'; + } + } + +out: + close (mdadm_pipe[0]); + waitpid (mdadm_pid, NULL, 0); + } + + return name; +} +#endif /* __linux__ */ + char * grub_util_get_grub_dev (const char *os_dev) { - char *grub_dev; + char *grub_dev = NULL; switch (grub_util_get_dev_abstraction (os_dev)) { @@ -600,9 +750,36 @@ grub_util_get_grub_dev (const char *os_dev) grub_dev = xasprintf ("md%s", p); free (p); } + else if (os_dev[7] == '/') + { + /* mdraid 1.x with a free name. */ + char *p , *q; + + p = strdup (os_dev + sizeof ("/dev/md/") - 1); + + q = strchr (p, 'p'); + if (q) + *q = ','; + + grub_dev = xasprintf ("md/%s", p); + free (p); + } else grub_util_error ("unknown kind of RAID device `%s'", os_dev); +#ifdef __linux__ + { + char *mdadm_name = get_mdadm_name (os_dev); + + if (mdadm_name) + { + free (grub_dev); + grub_dev = xasprintf ("md/%s", mdadm_name); + free (mdadm_name); + } + } +#endif /* __linux__ */ + break; default: /* GRUB_DEV_ABSTRACTION_NONE */ diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c index 03ceae8f9..00b4afe2e 100644 --- a/grub-core/kern/emu/misc.c +++ b/grub-core/kern/emu/misc.c @@ -1,6 +1,25 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,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 @@ -26,6 +45,22 @@ # include #endif +#ifdef HAVE_LIBZFS +# include +#endif + +#ifdef HAVE_LIBNVPAIR +# include +#endif + +#ifdef HAVE_SYS_PARAM_H +# include +#endif + +#ifdef HAVE_SYS_MOUNT_H +# include +#endif + int verbosity; void @@ -218,23 +253,87 @@ get_win32_path (const char *path) } #endif +#ifdef HAVE_LIBZFS +static libzfs_handle_t *__libzfs_handle; + +static void +fini_libzfs (void) +{ + libzfs_fini (__libzfs_handle); +} + +libzfs_handle_t * +grub_get_libzfs_handle (void) +{ + if (! __libzfs_handle) + { + __libzfs_handle = libzfs_init (); + + if (__libzfs_handle) + atexit (fini_libzfs); + } + + return __libzfs_handle; +} +#endif /* HAVE_LIBZFS */ + +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) +/* ZFS has similar problems to those of btrfs (see above). */ +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 (strcmp (mnt.f_fstypename, "zfs") != 0) + return; + + *poolname = xstrdup (mnt.f_mntfromname); + + slash = strchr (*poolname, '/'); + if (slash) + { + *slash = '\0'; + *poolfs = xstrdup (slash + 1); + } + else + *poolfs = xstrdup (""); +} +#endif + /* This function never prints trailing slashes (so that its output can be appended a slash unconditionally). */ char * grub_make_system_path_relative_to_its_root (const char *path) { struct stat st; - char *p, *buf, *buf2, *buf3; + char *p, *buf, *buf2, *buf3, *ret; uintptr_t offset = 0; dev_t num; size_t len; +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + char *poolfs = NULL; +#endif + /* canonicalize. */ p = canonicalize_file_name (path); - if (p == NULL) grub_util_error ("failed to get canonical path of %s", path); +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + /* For ZFS sub-pool filesystems, could be extended to others (btrfs?). */ + { + char *dummy; + grub_find_zpool_from_dir (p, &dummy, &poolfs); + } +#endif + len = strlen (p) + 1; buf = xstrdup (p); free (p); @@ -313,7 +412,17 @@ grub_make_system_path_relative_to_its_root (const char *path) len--; } - return buf3; +#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR) + if (poolfs) + { + ret = xasprintf ("/%s/@%s", poolfs, buf3); + free (buf3); + } + else +#endif + ret = buf3; + + return ret; } #ifdef HAVE_DEVICE_MAPPER diff --git a/grub-core/kern/i386/qemu/init.c b/grub-core/kern/i386/qemu/init.c index 201ba3633..054dfa86b 100644 --- a/grub-core/kern/i386/qemu/init.c +++ b/grub-core/kern/i386/qemu/init.c @@ -69,10 +69,7 @@ load_palette (void) { unsigned i; for (i = 0; i < 16; i++) - { - grub_outb (i, GRUB_VGA_IO_ARX); - grub_outb (i, GRUB_VGA_IO_ARX); - } + grub_vga_write_arx (i, i); for (i = 0; i < ARRAY_SIZE (colors); i++) grub_vga_palette_write (i, colors[i].r, colors[i].g, colors[i].b); @@ -90,7 +87,7 @@ grub_qemu_init_cirrus (void) addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); class = grub_pci_read (addr); - if (((class >> 16) & 0xffff) != 0x0300) + if (((class >> 16) & 0xffff) != GRUB_PCI_CLASS_SUBCLASS_VGA) return 0; /* FIXME: chooose addresses dynamically. */ @@ -110,7 +107,7 @@ grub_qemu_init_cirrus (void) grub_pci_iterate (find_card); - grub_outb (1, 0x3c2); + grub_outb (GRUB_VGA_IO_MISC_COLOR, GRUB_VGA_IO_MISC_WRITE); load_font (); @@ -124,11 +121,11 @@ grub_qemu_init_cirrus (void) GRUB_VGA_SR_MAP_MASK_REGISTER); grub_vga_cr_write (15, GRUB_VGA_CR_CELL_HEIGHT); - grub_vga_cr_write (79, GRUB_VGA_CR_WIDTH); + grub_vga_cr_write (79, GRUB_VGA_CR_HORIZ_END); grub_vga_cr_write (40, GRUB_VGA_CR_PITCH); int vert = 25 * 16; - grub_vga_cr_write (vert & 0xff, GRUB_VGA_CR_HEIGHT); + grub_vga_cr_write (vert & 0xff, GRUB_VGA_CR_VDISPLAY_END); grub_vga_cr_write (((vert >> GRUB_VGA_CR_OVERFLOW_HEIGHT1_SHIFT) & GRUB_VGA_CR_OVERFLOW_HEIGHT1_MASK) | ((vert >> GRUB_VGA_CR_OVERFLOW_HEIGHT2_SHIFT) @@ -137,10 +134,8 @@ grub_qemu_init_cirrus (void) load_palette (); - grub_outb (0x10, 0x3c0); - grub_outb (0, 0x3c1); - grub_outb (0x14, 0x3c0); - grub_outb (0, 0x3c1); + grub_vga_write_arx (GRUB_VGA_ARX_MODE_TEXT, GRUB_VGA_ARX_MODE); + grub_vga_write_arx (0, GRUB_VGA_ARX_COLOR_SELECT); grub_vga_sr_write (GRUB_VGA_SR_CLOCKING_MODE_8_DOT_CLOCK, GRUB_VGA_SR_CLOCKING_MODE); diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c index c13c96e30..b37ef230c 100644 --- a/grub-core/kern/misc.c +++ b/grub-core/kern/misc.c @@ -518,12 +518,39 @@ grub_strndup (const char *s, grub_size_t n) } void * -grub_memset (void *s, int c, grub_size_t n) +grub_memset (void *s, int c, grub_size_t len) { - unsigned char *p = (unsigned char *) s; + void *p = s; + grub_uint8_t pattern8 = c; - while (n--) - *p++ = (unsigned char) c; + if (len >= 3 * sizeof (unsigned long)) + { + unsigned long patternl = 0; + grub_size_t i; + + for (i = 0; i < sizeof (unsigned long); i++) + patternl |= ((unsigned long) pattern8) << (8 * i); + + while (len > 0 && (((grub_addr_t) p) & (sizeof (unsigned long) - 1))) + { + *(grub_uint8_t *) p = pattern8; + p = (grub_uint8_t *) p + 1; + len--; + } + while (len >= sizeof (unsigned long)) + { + *(unsigned long *) p = patternl; + p = (unsigned long *) p + 1; + len -= sizeof (unsigned long); + } + } + + while (len > 0) + { + *(grub_uint8_t *) p = pattern8; + p = (grub_uint8_t *) p + 1; + len--; + } return s; } diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c index 2a33ac329..a2f5dd722 100644 --- a/grub-core/kern/partition.c +++ b/grub-core/kern/partition.c @@ -21,8 +21,43 @@ #include #include +#ifdef GRUB_UTIL +#include +#endif + grub_partition_map_t grub_partition_map_list; +/* + * Checks that disk->partition contains part. This function assumes that the + * start of part is relative to the start of disk->partition. Returns 1 if + * disk->partition is null. + */ +static int +grub_partition_check_containment (const grub_disk_t disk, + const grub_partition_t part) +{ + if (disk->partition == NULL) + return 1; + + if (part->start + part->len > disk->partition->len) + { + char *partname; + + partname = grub_partition_get_name (disk->partition); + grub_dprintf ("partition", "sub-partition %s%d of (%s,%s) ends after parent.\n", + part->partmap->name, part->number + 1, disk->name, partname); +#ifdef GRUB_UTIL + grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)", + disk->name, partname, part->partmap->name, part->number + 1); +#endif + grub_free (partname); + + return 0; + } + + return 1; +} + static grub_partition_t grub_partition_map_probe (const grub_partition_map_t partmap, grub_disk_t disk, int partnum) @@ -31,20 +66,21 @@ grub_partition_map_probe (const grub_partition_map_t partmap, auto int find_func (grub_disk_t d, const grub_partition_t partition); - int find_func (grub_disk_t d __attribute__ ((unused)), + int find_func (grub_disk_t dsk, const grub_partition_t partition) { - if (partnum == partition->number) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 1; + if (partnum != partition->number) + return 0; - grub_memcpy (p, partition, sizeof (*p)); - return 1; - } + if (!(grub_partition_check_containment (dsk, partition))) + return 0; - return 0; + p = (grub_partition_t) grub_malloc (sizeof (*p)); + if (! p) + return 1; + + grub_memcpy (p, partition, sizeof (*p)); + return 1; } partmap->iterate (disk, find_func); @@ -138,6 +174,10 @@ grub_partition_iterate (struct grub_disk *disk, const grub_partition_t partition) { struct grub_partition p = *partition; + + if (!(grub_partition_check_containment (dsk, partition))) + return 0; + p.parent = dsk->partition; dsk->partition = 0; if (hook (dsk, &p)) diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c index 400314d30..a9b8a520e 100644 --- a/grub-core/lib/arg.c +++ b/grub-core/lib/arg.c @@ -144,8 +144,10 @@ grub_arg_show_help (grub_extcmd_t cmd) } } - /* FIXME: add spacing back. */ - grub_xputs (_(opt->doc)); + while (spacing--) + grub_xputs (" "); + + grub_printf ("%s\n", _(opt->doc)); switch (opt->shortarg) { diff --git a/grub-core/lib/i386/relocator_asm.S b/grub-core/lib/i386/relocator_asm.S index 6b803db13..22490a3f8 100644 --- a/grub-core/lib/i386/relocator_asm.S +++ b/grub-core/lib/i386/relocator_asm.S @@ -157,11 +157,13 @@ LOCAL(cont1): andl $(~GRUB_MEMORY_CPU_CR0_PAGING_ON), %eax movl %eax, %cr0 +#ifdef __x86_64__ /* Disable amd64. */ movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx rdmsr andl $(~GRUB_MEMORY_CPU_AMD64_MSR_ON), %eax wrmsr +#endif /* Turn off PAE. */ movl %cr4, %eax diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c index 930c0cb41..6b17a47ad 100644 --- a/grub-core/loader/powerpc/ieee1275/linux.c +++ b/grub-core/loader/powerpc/ieee1275/linux.c @@ -220,7 +220,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (! elf) goto out; - if (elf->ehdr.ehdr32.e_type != ET_EXEC) + if (elf->ehdr.ehdr32.e_type != ET_EXEC && elf->ehdr.ehdr32.e_type != ET_DYN) { grub_error (GRUB_ERR_UNKNOWN_OS, "this ELF file is not of the right type"); diff --git a/grub-core/modules.def b/grub-core/modules.def index 416e20dd1..71215aba0 100644 --- a/grub-core/modules.def +++ b/grub-core/modules.def @@ -425,6 +425,13 @@ library = { cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; }; +module = { + name = cmostest; + source = commands/i386/cmostest.c; + enable = i386_pc; + enable = i386_coreboot; +}; + module = { name = iorw; source = commands/iorw.c; @@ -1367,6 +1374,7 @@ module = { source = script/execute.c; source = script/function.c; source = script/lexer.c; + source = script/argv.c; source = unidata.c; nodist = grub_script.tab.c; diff --git a/grub-core/normal/color.c b/grub-core/normal/color.c index bae082911..a16d1c2f9 100644 --- a/grub-core/normal/color.c +++ b/grub-core/normal/color.c @@ -56,22 +56,23 @@ parse_color_name (grub_uint8_t *ret, char *name) return -1; } -void -grub_parse_color_name_pair (grub_uint8_t *ret, const char *name) +int +grub_parse_color_name_pair (grub_uint8_t *color, const char *name) { + int result = 1; grub_uint8_t fg, bg; char *fg_name, *bg_name; /* nothing specified by user */ if (name == NULL) - return; + return result; fg_name = grub_strdup (name); if (fg_name == NULL) { /* "out of memory" message was printed by grub_strdup() */ grub_wait_after_message (); - return; + return result; } bg_name = grub_strchr (fg_name, '/'); @@ -97,10 +98,12 @@ grub_parse_color_name_pair (grub_uint8_t *ret, const char *name) goto free_and_return; } - *ret = (bg << 4) | fg; + *color = (bg << 4) | fg; + result = 0; free_and_return: grub_free (fg_name); + return result; } static grub_uint8_t color_normal, color_highlight; @@ -122,10 +125,10 @@ set_colors (void) /* Replace default `normal' colors with the ones specified by user (if any). */ char * -grub_env_write_color_normal (struct grub_env_var *var __attribute__ ((unused)), - const char *val) +grub_env_write_color_normal (struct grub_env_var *var, const char *val) { - grub_parse_color_name_pair (&color_normal, val); + if (grub_parse_color_name_pair (&color_normal, val)) + return 0; set_colors (); @@ -134,10 +137,10 @@ grub_env_write_color_normal (struct grub_env_var *var __attribute__ ((unused)), /* Replace default `highlight' colors with the ones specified by user (if any). */ char * -grub_env_write_color_highlight (struct grub_env_var *var __attribute__ ((unused)), - const char *val) +grub_env_write_color_highlight (struct grub_env_var *var, const char *val) { - grub_parse_color_name_pair (&color_highlight, val); + if (grub_parse_color_name_pair (&color_highlight, val)) + return 0; set_colors (); diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index d2dabdc39..cddb15216 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -678,6 +678,7 @@ static void (*grub_xputs_saved) (const char *str); GRUB_MOD_INIT(normal) { grub_context_init (); + grub_script_init (); grub_xputs_saved = grub_xputs; grub_xputs = grub_xputs_normal; @@ -707,11 +708,16 @@ GRUB_MOD_INIT(normal) /* Preserve hooks after context changes. */ grub_env_export ("color_normal"); grub_env_export ("color_highlight"); + + /* Set default color names. */ + grub_env_set ("color_normal", "white/black"); + grub_env_set ("color_highlight", "black/white"); } GRUB_MOD_FINI(normal) { grub_context_fini (); + grub_script_fini (); grub_xputs = grub_xputs_saved; diff --git a/grub-core/partmap/bsdlabel.c b/grub-core/partmap/bsdlabel.c index d28f36d07..a27b8eaec 100644 --- a/grub-core/partmap/bsdlabel.c +++ b/grub-core/partmap/bsdlabel.c @@ -24,6 +24,10 @@ #include #include +#ifdef GRUB_UTIL +#include +#endif + static struct grub_partition_map grub_bsdlabel_partition_map; @@ -37,9 +41,6 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, grub_disk_addr_t delta = 0; unsigned pos; - /* BSDLabel offsets are absolute even when it's embed inside partition. */ - delta = grub_partition_get_start (disk->partition); - /* Read the BSD label. */ if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, sizeof (label), &label)) @@ -49,30 +50,79 @@ bsdlabel_partition_map_iterate (grub_disk_t disk, if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); + /* A kludge to determine a base of be.offset. */ + if (GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION + < grub_cpu_to_le16 (label.num_partitions)) + { + struct grub_partition_bsd_entry whole_disk_be; + + pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR + * GRUB_DISK_SECTOR_SIZE + sizeof (struct grub_partition_bsd_entry) + * GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION; + + if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE, + pos % GRUB_DISK_SECTOR_SIZE, sizeof (whole_disk_be), + &whole_disk_be)) + return grub_errno; + + delta = grub_le_to_cpu32 (whole_disk_be.offset); + } + pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR * GRUB_DISK_SECTOR_SIZE; for (p.number = 0; p.number < grub_cpu_to_le16 (label.num_partitions); - p.number++) + p.number++, pos += sizeof (struct grub_partition_bsd_entry)) { struct grub_partition_bsd_entry be; + if (p.number == GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION) + continue; + p.offset = pos / GRUB_DISK_SECTOR_SIZE; p.index = pos % GRUB_DISK_SECTOR_SIZE; if (grub_disk_read (disk, p.offset, p.index, sizeof (be), &be)) return grub_errno; - p.start = grub_le_to_cpu32 (be.offset) - delta; + p.start = grub_le_to_cpu32 (be.offset); p.len = grub_le_to_cpu32 (be.size); p.partmap = &grub_bsdlabel_partition_map; - if (be.fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED) - if (hook (disk, &p)) - return grub_errno; + grub_dprintf ("partition", + "partition %d: type 0x%x, start 0x%llx, len 0x%llx\n", + p.number, be.fs_type, + (unsigned long long) p.start, + (unsigned long long) p.len); - pos += sizeof (struct grub_partition_bsd_entry); + if (p.len == 0) + continue; + + if (p.start < delta) + { +#ifdef GRUB_UTIL + char *partname; +#endif + grub_dprintf ("partition", + "partition %d: invalid start (found 0x%llx, wanted >= 0x%llx)\n", + p.number, + (unsigned long long) p.start, + (unsigned long long) delta); +#ifdef GRUB_UTIL + /* disk->partition != NULL as 0 < delta */ + partname = grub_partition_get_name (disk->partition); + grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)", + disk->name, partname, p.partmap->name, p.number + 1); + grub_free (partname); +#endif + continue; + } + + p.start -= delta; + + if (hook (disk, &p)) + return grub_errno; } return GRUB_ERR_NONE; diff --git a/grub-core/script/argv.c b/grub-core/script/argv.c new file mode 100644 index 000000000..b69ee39c5 --- /dev/null +++ b/grub-core/script/argv.c @@ -0,0 +1,133 @@ +/* argv.c - methods for constructing argument vector */ +/* + * 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 + +/* Return nearest power of two that is >= v. */ +static unsigned +round_up_exp (unsigned v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + + if (sizeof (v) > 4) + v |= v >> 32; + + v++; + v += (v == 0); + + return v; +} + +void +grub_script_argv_free (struct grub_script_argv *argv) +{ + unsigned i; + + if (argv->args) + { + for (i = 0; i < argv->argc; i++) + grub_free (argv->args[i]); + + grub_free (argv->args); + } + + argv->argc = 0; + argv->args = 0; +} + +/* Prepare for next argc. */ +int +grub_script_argv_next (struct grub_script_argv *argv) +{ + char **p = argv->args; + + if (argv->args && argv->args[argv->argc - 1] == 0) + return 0; + + p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *))); + if (! p) + return 1; + + argv->argc++; + argv->args = p; + + if (argv->argc == 1) + argv->args[0] = 0; + argv->args[argv->argc] = 0; + return 0; +} + +/* Append `s' to the last argument. */ +int +grub_script_argv_append (struct grub_script_argv *argv, const char *s) +{ + int a, b; + char *p = argv->args[argv->argc - 1]; + + if (! s) + return 0; + + a = p ? grub_strlen (p) : 0; + b = grub_strlen (s); + + p = grub_realloc (p, round_up_exp ((a + b + 1) * sizeof (char))); + if (! p) + return 1; + + grub_strcpy (p + a, s); + argv->args[argv->argc - 1] = p; + return 0; +} + +/* Split `s' and append words as multiple arguments. */ +int +grub_script_argv_split_append (struct grub_script_argv *argv, char *s) +{ + char ch; + char *p; + int errors = 0; + + if (! s) + return 0; + + while (! errors && *s) + { + p = s; + while (*s && ! grub_isspace (*s)) + s++; + + ch = *s; + *s = '\0'; + errors += grub_script_argv_append (argv, p); + *s = ch; + + while (*s && grub_isspace (*s)) + s++; + + if (*s) + errors += grub_script_argv_next (argv); + } + return errors; +} diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index 40f161267..26a46b12b 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -30,6 +30,252 @@ is sizeof (int) * 3, and one extra for a possible -ve sign. */ #define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1) +static unsigned long is_continue; +static unsigned long active_loops; +static unsigned long active_breaks; + +/* Scope for grub script functions. */ +struct grub_script_scope +{ + struct grub_script_argv argv; +}; +static struct grub_script_scope *scope = 0; + +grub_err_t +grub_script_break (grub_command_t cmd, int argc, char *argv[]) +{ + char *p = 0; + unsigned long count; + + if (argc == 0) + count = 1; + + else if ((argc > 1) || (count = grub_strtoul (argv[0], &p, 10)) == 0 || + (*p != '\0')) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad break"); + + is_continue = grub_strcmp (cmd->name, "break") ? 1 : 0; + active_breaks = grub_min (active_loops, count); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_script_shift (grub_command_t cmd __attribute__((unused)), + int argc, char *argv[]) +{ + char *p = 0; + unsigned long n = 0; + + if (! scope) + return GRUB_ERR_NONE; + + if (argc == 0) + n = 1; + + else if (argc > 1) + return GRUB_ERR_BAD_ARGUMENT; + + else + { + n = grub_strtoul (argv[0], &p, 10); + if (*p != '\0') + return GRUB_ERR_BAD_ARGUMENT; + } + + if (n > scope->argv.argc) + return GRUB_ERR_BAD_ARGUMENT; + + scope->argv.argc -= n; + scope->argv.args += n; + return GRUB_ERR_NONE; +} + +static int +grub_env_special (const char *name) +{ + if (grub_isdigit (name[0]) || + grub_strcmp (name, "#") == 0 || + grub_strcmp (name, "*") == 0 || + grub_strcmp (name, "@") == 0) + return 1; + return 0; +} + +static char ** +grub_script_env_get (const char *name, grub_script_arg_type_t type) +{ + struct grub_script_argv result = { 0, 0 }; + + if (grub_script_argv_next (&result)) + goto fail; + + if (! grub_env_special (name)) + { + char *v = grub_env_get (name); + if (v && v[0]) + { + if (type == GRUB_SCRIPT_ARG_TYPE_VAR) + { + if (grub_script_argv_split_append (&result, v)) + goto fail; + } + else + if (grub_script_argv_append (&result, v)) + goto fail; + } + } + else if (! scope) + { + if (grub_script_argv_append (&result, 0)) + goto fail; + } + else if (grub_strcmp (name, "#") == 0) + { + char buffer[ERRNO_DIGITS_MAX + 1]; + grub_snprintf (buffer, sizeof (buffer), "%u", scope->argv.argc); + if (grub_script_argv_append (&result, buffer)) + goto fail; + } + else if (grub_strcmp (name, "*") == 0) + { + unsigned i; + + for (i = 0; i < scope->argv.argc; i++) + if (type == GRUB_SCRIPT_ARG_TYPE_VAR) + { + if (i != 0 && grub_script_argv_next (&result)) + goto fail; + + if (grub_script_argv_split_append (&result, scope->argv.args[i])) + goto fail; + } + else + { + if (i != 0 && grub_script_argv_append (&result, " ")) + goto fail; + + if (grub_script_argv_append (&result, scope->argv.args[i])) + goto fail; + } + } + else if (grub_strcmp (name, "@") == 0) + { + unsigned i; + + for (i = 0; i < scope->argv.argc; i++) + { + if (i != 0 && grub_script_argv_next (&result)) + goto fail; + + if (type == GRUB_SCRIPT_ARG_TYPE_VAR) + { + if (grub_script_argv_split_append (&result, scope->argv.args[i])) + goto fail; + } + else + if (grub_script_argv_append (&result, scope->argv.args[i])) + goto fail; + } + } + else + { + unsigned long num = grub_strtoul (name, 0, 10); + if (num == 0) + ; /* XXX no file name, for now. */ + + else if (num <= scope->argv.argc) + { + if (type == GRUB_SCRIPT_ARG_TYPE_VAR) + { + if (grub_script_argv_split_append (&result, + scope->argv.args[num - 1])) + goto fail; + } + else + if (grub_script_argv_append (&result, scope->argv.args[num - 1])) + goto fail; + } + } + + return result.args; + + fail: + + grub_script_argv_free (&result); + return 0; +} + +static grub_err_t +grub_script_env_set (const char *name, const char *val) +{ + if (grub_env_special (name)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad variable name"); + + return grub_env_set (name, val); +} + +/* Expand arguments in ARGLIST into multiple arguments. */ +static int +grub_script_arglist_to_argv (struct grub_script_arglist *arglist, + struct grub_script_argv *argv) +{ + int i; + char **values = 0; + struct grub_script_arg *arg = 0; + struct grub_script_argv result = { 0, 0 }; + + for (; arglist && arglist->arg; arglist = arglist->next) + { + if (grub_script_argv_next (&result)) + goto fail; + + arg = arglist->arg; + while (arg) + { + switch (arg->type) + { + case GRUB_SCRIPT_ARG_TYPE_VAR: + case GRUB_SCRIPT_ARG_TYPE_DQVAR: + values = grub_script_env_get (arg->str, arg->type); + for (i = 0; values && values[i]; i++) + { + if (i != 0 && grub_script_argv_next (&result)) + goto fail; + + if (grub_script_argv_append (&result, values[i])) + goto fail; + } + grub_free (values); + break; + + case GRUB_SCRIPT_ARG_TYPE_TEXT: + if (grub_strlen (arg->str) && + grub_script_argv_append (&result, arg->str)) + goto fail; + break; + + case GRUB_SCRIPT_ARG_TYPE_DQSTR: + case GRUB_SCRIPT_ARG_TYPE_SQSTR: + if (grub_script_argv_append (&result, arg->str)) + goto fail; + break; + } + arg = arg->next; + } + } + + if (! result.args[result.argc - 1]) + result.argc--; + + *argv = result; + return 0; + + fail: + + grub_script_argv_free (&result); + return 1; +} + static grub_err_t grub_script_execute_cmd (struct grub_script_cmd *cmd) { @@ -46,149 +292,27 @@ grub_script_execute_cmd (struct grub_script_cmd *cmd) return ret; } -#define ARG_ALLOCATION_UNIT (32 * sizeof (char)) -#define ARGV_ALLOCATION_UNIT (8 * sizeof (void*)) - -/* Expand arguments in ARGLIST into multiple arguments. */ -char ** -grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count) +/* Execute a function call. */ +grub_err_t +grub_script_function_call (grub_script_function_t func, int argc, char **args) { - int i; - int oom; - int argc; - int empty; - char *ptr; - char **argv; - char *value; - struct grub_script_arg *arg; + grub_err_t ret = 0; + unsigned long loops = active_loops; + struct grub_script_scope *old_scope; + struct grub_script_scope new_scope; - auto void push (char *str); - void push (char *str) - { - char **p; + active_loops = 0; + new_scope.argv.argc = argc; + new_scope.argv.args = args; - if (oom) - return; + old_scope = scope; + scope = &new_scope; - p = grub_realloc (argv, ALIGN_UP (sizeof(char*) * (argc + 1), ARGV_ALLOCATION_UNIT)); - if (!p) - oom = 1; - else - { - p[argc++] = str; - argv = p; - } - } + ret = grub_script_execute (func->func); - auto char* append (const char *str, grub_size_t nchar); - char* append (const char *str, grub_size_t nchar) - { - int len; - int old; - char *p; - - if (oom || !str) - return 0; - - len = nchar ?: grub_strlen (str); - old = argv[argc - 1] ? grub_strlen (argv[argc - 1]) : 0; - p = grub_realloc (argv[argc - 1], ALIGN_UP(old + len + 1, ARG_ALLOCATION_UNIT)); - - if (p) - { - grub_strncpy (p + old, str, len); - p[old + len] = '\0'; - } - else - { - oom = 1; - grub_free (argv[argc - 1]); - } - argv[argc - 1] = p; - return argv[argc - 1]; - } - - /* Move *STR to the begining of next word, but return current word. */ - auto char* move_to_next (char **str); - char* move_to_next (char **str) - { - char *end; - char *start; - - if (oom || !str || !*str) - return 0; - - start = *str; - while (*start && grub_isspace (*start)) start++; - if (*start == '\0') - return 0; - - end = start + 1; - while (*end && !grub_isspace (*end)) end++; - - *str = end; - return start; - } - - oom = 0; - argv = 0; - argc = 0; - push (0); - for (; arglist; arglist = arglist->next) - { - empty = 1; - arg = arglist->arg; - while (arg) - { - switch (arg->type) - { - case GRUB_SCRIPT_ARG_TYPE_VAR: - value = grub_env_get (arg->str); - while (value && *value && (ptr = move_to_next(&value))) - { - empty = 0; - append (ptr, value - ptr); - if (*value) push(0); - } - break; - - case GRUB_SCRIPT_ARG_TYPE_TEXT: - if (grub_strlen (arg->str) > 0) - { - empty = 0; - append (arg->str, 0); - } - break; - - case GRUB_SCRIPT_ARG_TYPE_DQSTR: - case GRUB_SCRIPT_ARG_TYPE_SQSTR: - empty = 0; - append (arg->str, 0); - break; - - case GRUB_SCRIPT_ARG_TYPE_DQVAR: - empty = 0; - append (grub_env_get (arg->str), 0); - break; - } - arg = arg->next; - } - if (!empty) - push (0); - } - - if (oom) - { - for (i = 0; i < argc; i++) - grub_free (argv[i]); - grub_free (argv); - argv = 0; - } - - if (argv) - *count = argc - 1; - - return argv; + active_loops = loops; + scope = old_scope; + return ret; } /* Execute a single command line. */ @@ -196,21 +320,18 @@ grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd) { struct grub_script_cmdline *cmdline = (struct grub_script_cmdline *) cmd; - char **args = 0; - int i = 0; grub_command_t grubcmd; grub_err_t ret = 0; - int argcount = 0; grub_script_function_t func = 0; char errnobuf[18]; char *cmdname; + struct grub_script_argv argv = { 0, 0 }; /* Lookup the command. */ - args = grub_script_execute_arglist_to_argv (cmdline->arglist, &argcount); - if (!args) + if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0]) return grub_errno; - cmdname = args[0]; + cmdname = argv.args[0]; grubcmd = grub_command_find (cmdname); if (! grubcmd) { @@ -232,13 +353,14 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) /* Create two strings and set the variable. */ *eq = '\0'; eq++; - grub_env_set (assign, eq); + grub_script_env_set (assign, eq); } grub_free (assign); grub_snprintf (errnobuf, sizeof (errnobuf), "%d", grub_errno); - grub_env_set ("?", errnobuf); + grub_script_env_set ("?", errnobuf); + grub_script_argv_free (&argv); grub_print_error (); return 0; @@ -247,14 +369,12 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) /* Execute the GRUB command or function. */ if (grubcmd) - ret = (grubcmd->func) (grubcmd, argcount - 1, args + 1); + ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1); else - ret = grub_script_function_call (func, argcount - 1, args + 1); + ret = grub_script_function_call (func, argv.argc - 1, argv.args + 1); /* Free arguments. */ - for (i = 0; i < argcount; i++) - grub_free (args[i]); - grub_free (args); + grub_script_argv_free (&argv); if (grub_errno == GRUB_ERR_TEST_FAILURE) grub_errno = GRUB_ERR_NONE; @@ -269,13 +389,13 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) /* Execute a block of one or more commands. */ grub_err_t -grub_script_execute_cmdblock (struct grub_script_cmd *cmd) +grub_script_execute_cmdlist (struct grub_script_cmd *list) { int ret = 0; - struct grub_script_cmdblock *cmdblock = (struct grub_script_cmdblock *) cmd; + struct grub_script_cmd *cmd; /* Loop over every command and execute it. */ - for (cmd = cmdblock->cmdlist; cmd; cmd = cmd->next) + for (cmd = list->next; cmd && ! active_breaks; cmd = cmd->next) ret = grub_script_execute_cmd (cmd); return ret; @@ -307,25 +427,34 @@ grub_script_execute_cmdif (struct grub_script_cmd *cmd) grub_err_t grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { - int i; - int result; - char **args; - int argcount; + unsigned i; + grub_err_t result; + struct grub_script_argv argv = { 0, 0 }; + struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd; - args = grub_script_execute_arglist_to_argv (cmdfor->words, &argcount); - if (!args) + if (grub_script_arglist_to_argv (cmdfor->words, &argv)) return grub_errno; + active_loops++; result = 0; - for (i = 0; i < argcount; i++) + for (i = 0; i < argv.argc; i++) { - grub_env_set (cmdfor->name->str, args[i]); - result = grub_script_execute_cmd (cmdfor->list); - grub_free (args[i]); + if (is_continue && active_breaks == 1) + active_breaks = 0; + + if (! active_breaks) + { + grub_script_env_set (cmdfor->name->str, argv.args[i]); + result = grub_script_execute_cmd (cmdfor->list); + } } - grub_free (args); + if (active_breaks) + active_breaks--; + + active_loops--; + grub_script_argv_free (&argv); return result; } @@ -337,6 +466,7 @@ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd) int result; struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd; + active_loops++; result = 0; do { cond = grub_script_execute_cmd (cmdwhile->cond); @@ -344,8 +474,19 @@ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd) break; result = grub_script_execute_cmd (cmdwhile->list); + + if (active_breaks == 1 && is_continue) + active_breaks = 0; + + if (active_breaks) + break; + } while (1); /* XXX Put a check for ^C here */ + if (active_breaks) + active_breaks--; + + active_loops--; return result; } @@ -354,26 +495,20 @@ grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd) { struct grub_script_cmd_menuentry *cmd_menuentry; - char **args = 0; - int argcount = 0; - int i = 0; + struct grub_script_argv argv = { 0, 0 }; cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd; if (cmd_menuentry->arglist) { - args = grub_script_execute_arglist_to_argv (cmd_menuentry->arglist, &argcount); - if (!args) + if (grub_script_arglist_to_argv (cmd_menuentry->arglist, &argv)) return grub_errno; } - grub_normal_add_menu_entry (argcount, (const char **) args, + grub_normal_add_menu_entry (argv.argc, (const char **) argv.args, cmd_menuentry->sourcecode); - /* Free arguments. */ - for (i = 0; i < argcount; i++) - grub_free (args[i]); - grub_free (args); + grub_script_argv_free (&argv); return grub_errno; } diff --git a/grub-core/script/function.c b/grub-core/script/function.c index 810c65233..47b236652 100644 --- a/grub-core/script/function.c +++ b/grub-core/script/function.c @@ -103,12 +103,3 @@ grub_script_function_find (char *functionname) return func; } - -int -grub_script_function_call (grub_script_function_t func, - int argc __attribute__((unused)), - char **args __attribute__((unused))) -{ - /* XXX: Arguments are not supported yet. */ - return grub_script_execute (func->func); -} diff --git a/grub-core/script/main.c b/grub-core/script/main.c index 752a8cd8a..ff714d060 100644 --- a/grub-core/script/main.c +++ b/grub-core/script/main.c @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -39,3 +40,34 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline) return grub_errno; } + +static grub_command_t cmd_break; +static grub_command_t cmd_continue; +static grub_command_t cmd_shift; + +void +grub_script_init (void) +{ + cmd_break = grub_register_command ("break", grub_script_break, + N_("[n]"), N_("Exit from loops")); + cmd_continue = grub_register_command ("continue", grub_script_break, + N_("[n]"), N_("Continue loops")); + cmd_shift = grub_register_command ("shift", grub_script_shift, + N_("[n]"), N_("Shift positional parameters.")); +} + +void +grub_script_fini (void) +{ + if (cmd_break) + grub_unregister_command (cmd_break); + cmd_break = 0; + + if (cmd_continue) + grub_unregister_command (cmd_continue); + cmd_continue = 0; + + if (cmd_shift) + grub_unregister_command (cmd_shift); + cmd_shift = 0; +} diff --git a/grub-core/script/parser.y b/grub-core/script/parser.y index e85ba624d..99cd2ee31 100644 --- a/grub-core/script/parser.y +++ b/grub-core/script/parser.y @@ -97,9 +97,7 @@ script: newlines0 } | script statement delimiter newlines0 { - struct grub_script_cmdblock *cmdblock; - cmdblock = (struct grub_script_cmdblock *) $1; - $$ = grub_script_add_cmd (state, cmdblock, $2); + $$ = grub_script_append_cmd (state, $1, $2); } | error { @@ -185,13 +183,11 @@ command: grubcmd { $$ = $1; } /* A list of commands. */ commands1: newlines0 command { - $$ = grub_script_add_cmd (state, 0, $2); + $$ = grub_script_append_cmd (state, 0, $2); } | commands1 delimiters1 command { - struct grub_script_cmdblock *cmdblock; - cmdblock = (struct grub_script_cmdblock *) $1; - $$ = grub_script_add_cmd (state, cmdblock, $3); + $$ = grub_script_append_cmd (state, $1, $3); } ; diff --git a/grub-core/script/script.c b/grub-core/script/script.c index 4c87d9491..9cee40dcb 100644 --- a/grub-core/script/script.c +++ b/grub-core/script/script.c @@ -291,46 +291,40 @@ grub_script_create_cmdmenu (struct grub_parser_param *state, return (struct grub_script_cmd *) cmd; } -/* Create a block of commands. CMD contains the command that should - be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new - cmdblock will be created. */ +/* 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. */ struct grub_script_cmd * -grub_script_add_cmd (struct grub_parser_param *state, - struct grub_script_cmdblock *cmdblock, - struct grub_script_cmd *cmd) +grub_script_append_cmd (struct grub_parser_param *state, + struct grub_script_cmd *list, + struct grub_script_cmd *last) { struct grub_script_cmd *ptr; - grub_dprintf ("scripting", "cmdblock\n"); + grub_dprintf ("scripting", "append command\n"); - if (!cmd) - return (struct grub_script_cmd *) cmdblock; + if (! last) + return list; - if (!cmdblock) + if (! list) { - cmdblock = grub_script_malloc (state, sizeof (*cmdblock)); - if (!cmdblock) + list = grub_script_malloc (state, sizeof (*list)); + if (! list) return 0; - cmdblock->cmd.exec = grub_script_execute_cmdblock; - cmdblock->cmd.next = 0; - cmdblock->cmdlist = cmd; - cmd->next = 0; + list->exec = grub_script_execute_cmdlist; + list->next = last; } else { - if (!cmdblock->cmdlist) - cmdblock->cmdlist = cmd; - else - { - ptr = cmdblock->cmdlist; - while (ptr->next) - ptr = ptr->next; - ptr->next = cmd; - } + ptr = list; + while (ptr->next) + ptr = ptr->next; + + ptr->next = last; } - return (struct grub_script_cmd *) cmdblock; + return list; } diff --git a/grub-core/script/yylex.l b/grub-core/script/yylex.l index 7d4ea9e4e..45760c158 100644 --- a/grub-core/script/yylex.l +++ b/grub-core/script/yylex.l @@ -116,10 +116,11 @@ COMMENT #.*$ CHAR [^{}|&$;<> \t\n\'\"\\] DIGITS [[:digit:]]+ -NAME [[:alpha:]_][[:alnum:][:digit:]_]* +NAME [[:alpha:]_][[:alnum:]_]* ESC \\. -VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|$\?|$\{\?\} +SPECIAL \?|\#|\*|\@ +VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\} DQSTR \"([^\\\"]|{ESC})*\" SQSTR \'[^\']*\' WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ @@ -221,7 +222,7 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ } { - \? | + {SPECIAL} | {DIGITS} | {NAME} { COPY (yytext, yyleng); @@ -231,7 +232,7 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ else ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR); } - \{\?\} | + \{{SPECIAL}\} | \{{DIGITS}\} | \{{NAME}\} { yytext[yyleng - 1] = '\0'; diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c index d3240590b..dca002910 100644 --- a/grub-core/term/efi/console.c +++ b/grub-core/term/efi/console.c @@ -311,6 +311,20 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), efi_call_2 (o->enable_cursor, o, on); } +static grub_err_t +grub_efi_console_init (struct grub_term_output *term) +{ + grub_console_setcursor (term, 1); + return 0; +} + +static grub_err_t +grub_efi_console_fini (struct grub_term_output *term) +{ + grub_console_setcursor (term, 0); + return 0; +} + static struct grub_term_input grub_console_term_input = { .name = "console", @@ -321,6 +335,8 @@ static struct grub_term_input grub_console_term_input = static struct grub_term_output grub_console_term_output = { .name = "console", + .init = grub_efi_console_init, + .fini = grub_efi_console_fini, .putchar = grub_console_putchar, .getwh = grub_console_getwh, .getxy = grub_console_getxy, diff --git a/grub-core/video/cirrus.c b/grub-core/video/cirrus.c index ccbab9d15..b8b0142ad 100644 --- a/grub-core/video/cirrus.c +++ b/grub-core/video/cirrus.c @@ -334,43 +334,26 @@ grub_video_cirrus_setup (unsigned int width, unsigned int height, } { - int pitch_reg, overflow_reg = 0, line_compare = 0x3ff; + struct grub_video_hw_config config = { + .pitch = pitch / GRUB_VGA_CR_PITCH_DIVISOR, + .line_compare = 0x3ff, + .vdisplay_end = height - 1, + .horizontal_end = width / GRUB_VGA_CR_WIDTH_DIVISOR + }; grub_uint8_t sr_ext = 0, hidden_dac = 0; - pitch_reg = pitch / GRUB_VGA_CR_PITCH_DIVISOR; - + grub_vga_set_geometry (&config, grub_vga_cr_write); + grub_vga_gr_write (GRUB_VGA_GR_MODE_256_COLOR | GRUB_VGA_GR_MODE_READ_MODE1, GRUB_VGA_GR_MODE); grub_vga_gr_write (GRUB_VGA_GR_GR6_GRAPHICS_MODE, GRUB_VGA_GR_GR6); grub_vga_sr_write (GRUB_VGA_SR_MEMORY_MODE_NORMAL, GRUB_VGA_SR_MEMORY_MODE); - /* Disable CR0-7 write protection. */ - grub_vga_cr_write (0, GRUB_VGA_CR_VSYNC_END); - - grub_vga_cr_write (width / GRUB_VGA_CR_WIDTH_DIVISOR - 1, - GRUB_VGA_CR_WIDTH); - grub_vga_cr_write ((height - 1) & 0xff, GRUB_VGA_CR_HEIGHT); - overflow_reg |= (((height - 1) >> GRUB_VGA_CR_OVERFLOW_HEIGHT1_SHIFT) & - GRUB_VGA_CR_OVERFLOW_HEIGHT1_MASK) - | (((height - 1) >> GRUB_VGA_CR_OVERFLOW_HEIGHT2_SHIFT) & - GRUB_VGA_CR_OVERFLOW_HEIGHT2_MASK); - - grub_vga_cr_write (pitch_reg & 0xff, GRUB_VGA_CR_PITCH); - - grub_vga_cr_write (line_compare & 0xff, GRUB_VGA_CR_LINE_COMPARE); - overflow_reg |= (line_compare >> GRUB_VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT) - & GRUB_VGA_CR_OVERFLOW_LINE_COMPARE_MASK; - - grub_vga_cr_write (overflow_reg, GRUB_VGA_CR_OVERFLOW); - - grub_vga_cr_write ((pitch_reg >> CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT) + grub_vga_cr_write ((config.pitch >> CIRRUS_CR_EXTENDED_DISPLAY_PITCH_SHIFT) & CIRRUS_CR_EXTENDED_DISPLAY_PITCH_MASK, CIRRUS_CR_EXTENDED_DISPLAY); - grub_vga_cr_write ((line_compare >> GRUB_VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT) - & GRUB_VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK, GRUB_VGA_CR_CELL_HEIGHT); - grub_vga_cr_write (GRUB_VGA_CR_MODE_TIMING_ENABLE | GRUB_VGA_CR_MODE_BYTE_MODE | GRUB_VGA_CR_MODE_NO_HERCULES | GRUB_VGA_CR_MODE_NO_CGA, diff --git a/grub-core/video/sm712.c b/grub-core/video/sm712.c index a58032c42..60f2c9089 100644 --- a/grub-core/video/sm712.c +++ b/grub-core/video/sm712.c @@ -26,10 +26,168 @@ #include #include #include +#include #include "sm712_init.c" #define GRUB_SM712_TOTAL_MEMORY_SPACE 0x700400 +#define GRUB_SM712_REG_BASE 0x700000 +#define GRUB_SM712_PCIID 0x0712126f + +enum + { + GRUB_SM712_SR_TV_CONTROL = 0x65, + GRUB_SM712_SR_RAM_LUT = 0x66, + GRUB_SM712_SR_CLOCK_CONTROL1 = 0x68, + GRUB_SM712_SR_CLOCK_CONTROL2 = 0x69, + GRUB_SM712_SR_VCLK_NUM = 0x6c, + GRUB_SM712_SR_VCLK_DENOM = 0x6d, + GRUB_SM712_SR_VCLK2_NUM = 0x6e, + GRUB_SM712_SR_VCLK2_DENOM = 0x6f, + GRUB_SM712_SR_POPUP_ICON_LOW = 0x80, + GRUB_SM712_SR_POPUP_ICON_HIGH = 0x81, + GRUB_SM712_SR_POPUP_ICON_CTRL = 0x82, + GRUB_SM712_SR_POPUP_ICON_COLOR1 = 0x84, + GRUB_SM712_SR_POPUP_ICON_COLOR2 = 0x85, + GRUB_SM712_SR_POPUP_ICON_COLOR3 = 0x86, + + GRUB_SM712_SR_HW_CURSOR_UPPER_LEFT_X_LOW = 0x88, + GRUB_SM712_SR_HW_CURSOR_UPPER_LEFT_X_HIGH = 0x89, + GRUB_SM712_SR_HW_CURSOR_UPPER_LEFT_Y_LOW = 0x8a, + GRUB_SM712_SR_HW_CURSOR_UPPER_LEFT_Y_HIGH = 0x8b, + GRUB_SM712_SR_HW_CURSOR_FG_COLOR = 0x8c, + GRUB_SM712_SR_HW_CURSOR_BG_COLOR = 0x8d, + + GRUB_SM712_SR_POPUP_ICON_X_LOW = 0x90, + GRUB_SM712_SR_POPUP_ICON_X_HIGH = 0x91, + GRUB_SM712_SR_POPUP_ICON_Y_LOW = 0x92, + GRUB_SM712_SR_POPUP_ICON_Y_HIGH = 0x93, + GRUB_SM712_SR_PANEL_HW_VIDEO_CONTROL = 0xa0, + GRUB_SM712_SR_PANEL_HW_VIDEO_COLOR_KEY_LOW = 0xa1, + GRUB_SM712_SR_PANEL_HW_VIDEO_COLOR_KEY_HIGH = 0xa2, + GRUB_SM712_SR_PANEL_HW_VIDEO_COLOR_KEY_MASK_LOW = 0xa3, + GRUB_SM712_SR_PANEL_HW_VIDEO_COLOR_KEY_MASK_HIGH = 0xa4, + GRUB_SM712_SR_PANEL_HW_VIDEO_RED_CONSTANT = 0xa5, + GRUB_SM712_SR_PANEL_HW_VIDEO_GREEN_CONSTANT = 0xa6, + GRUB_SM712_SR_PANEL_HW_VIDEO_BLUE_CONSTANT = 0xa7, + GRUB_SM712_SR_PANEL_HW_VIDEO_TOP_BOUNDARY = 0xa8, + GRUB_SM712_SR_PANEL_HW_VIDEO_LEFT_BOUNDARY = 0xa9, + GRUB_SM712_SR_PANEL_HW_VIDEO_BOTTOM_BOUNDARY = 0xaa, + GRUB_SM712_SR_PANEL_HW_VIDEO_RIGHT_BOUNDARY = 0xab, + GRUB_SM712_SR_PANEL_HW_VIDEO_TOP_LEFT_OVERFLOW_BOUNDARY = 0xac, + GRUB_SM712_SR_PANEL_HW_VIDEO_BOTTOM_RIGHT_OVERFLOW_BOUNDARY = 0xad, + GRUB_SM712_SR_PANEL_HW_VIDEO_VERTICAL_STRETCH_FACTOR = 0xae, + GRUB_SM712_SR_PANEL_HW_VIDEO_HORIZONTAL_STRETCH_FACTOR = 0xaf, + }; +enum + { + GRUB_SM712_SR_TV_CRT_SRAM = 0x00, + GRUB_SM712_SR_TV_LCD_SRAM = 0x08 + }; +enum + { + GRUB_SM712_SR_TV_ALT_CLOCK = 0x00, + GRUB_SM712_SR_TV_FREE_RUN_CLOCK = 0x04 + }; +enum + { + GRUB_SM712_SR_TV_CLOCK_CKIN_NTSC = 0x00, + GRUB_SM712_SR_TV_CLOCK_REFCLK_PAL = 0x04 + }; +enum + { + GRUB_SM712_SR_TV_HSYNC = 0x00, + GRUB_SM712_SR_TV_COMPOSITE_HSYNC = 0x01 + }; +enum + { + GRUB_SM712_SR_RAM_LUT_NORMAL = 0, + GRUB_SM712_SR_RAM_LUT_LCD_RAM_OFF = 0x80, + GRUB_SM712_SR_RAM_LUT_CRT_RAM_OFF = 0x40, + GRUB_SM712_SR_RAM_LUT_LCD_RAM_NO_WRITE = 0x20, + GRUB_SM712_SR_RAM_LUT_CRT_RAM_NO_WRITE = 0x10, + GRUB_SM712_SR_RAM_LUT_CRT_8BIT = 0x08, + GRUB_SM712_SR_RAM_LUT_CRT_GAMMA = 0x04 + }; + +enum + { + GRUB_SM712_SR_CLOCK_CONTROL1_VCLK_FROM_CCR = 0x40, + GRUB_SM712_SR_CLOCK_CONTROL1_8DOT_CLOCK = 0x10, + }; + +enum + { + GRUB_SM712_SR_CLOCK_CONTROL2_PROGRAM_VCLOCK = 0x03 + }; + +#define GRUB_SM712_SR_POPUP_ICON_HIGH_MASK 0x7 +#define GRUB_SM712_SR_POPUP_ICON_HIGH_HW_CURSOR_EN 0x80 + enum + { + GRUB_SM712_SR_POPUP_ICON_CTRL_DISABLED = 0, + GRUB_SM712_SR_POPUP_ICON_CTRL_ZOOM_ENABLED = 0x40, + GRUB_SM712_SR_POPUP_ICON_CTRL_ENABLED = 0x80 + }; +#define RGB332_BLACK 0 +#define RGB332_WHITE 0xff + + enum + { + GRUB_SM712_CR_OVERFLOW_INTERLACE = 0x30, + GRUB_SM712_CR_INTERLACE_RETRACE = 0x31, + GRUB_SM712_CR_TV_VDISPLAY_START = 0x32, + GRUB_SM712_CR_TV_VDISPLAY_END_HIGH = 0x33, + GRUB_SM712_CR_TV_VDISPLAY_END_LOW = 0x34, + GRUB_SM712_CR_DDA_CONTROL_LOW = 0x35, + GRUB_SM712_CR_DDA_CONTROL_HIGH = 0x36, + GRUB_SM712_CR_TV_EQUALIZER = 0x38, + GRUB_SM712_CR_TV_SERRATION = 0x39, + GRUB_SM712_CR_HSYNC_CTRL = 0x3a, + GRUB_SM712_CR_DEBUG = 0x3c, + GRUB_SM712_CR_SHADOW_VGA_HTOTAL = 0x40, + GRUB_SM712_CR_SHADOW_VGA_HBLANK_START = 0x41, + GRUB_SM712_CR_SHADOW_VGA_HBLANK_END = 0x42, + GRUB_SM712_CR_SHADOW_VGA_HRETRACE_START = 0x43, + GRUB_SM712_CR_SHADOW_VGA_HRETRACE_END = 0x44, + GRUB_SM712_CR_SHADOW_VGA_VERTICAL_TOTAL = 0x45, + GRUB_SM712_CR_SHADOW_VGA_VBLANK_START = 0x46, + GRUB_SM712_CR_SHADOW_VGA_VBLANK_END = 0x47, + GRUB_SM712_CR_SHADOW_VGA_VRETRACE_START = 0x48, + GRUB_SM712_CR_SHADOW_VGA_VRETRACE_END = 0x49, + GRUB_SM712_CR_SHADOW_VGA_OVERFLOW = 0x4a, + GRUB_SM712_CR_SHADOW_VGA_CELL_HEIGHT = 0x4b, + GRUB_SM712_CR_SHADOW_VGA_HDISPLAY_END = 0x4c, + GRUB_SM712_CR_SHADOW_VGA_VDISPLAY_END = 0x4d, + GRUB_SM712_CR_DDA_LOOKUP_REG3_START = 0x90, + GRUB_SM712_CR_DDA_LOOKUP_REG2_START = 0x91, + GRUB_SM712_CR_DDA_LOOKUP_REG1_START = 0xa0, + GRUB_SM712_CR_VCENTERING_OFFSET = 0xa6, + GRUB_SM712_CR_HCENTERING_OFFSET = 0xa7, + }; + +#define GRUB_SM712_CR_DEBUG_NONE 0 + +#define SM712_DDA_REG3_COMPARE_SHIFT 2 +#define SM712_DDA_REG3_COMPARE_MASK 0xfc +#define SM712_DDA_REG3_DDA_SHIFT 8 +#define SM712_DDA_REG3_DDA_MASK 0x3 +#define SM712_DDA_REG2_DDA_MASK 0xff +#define SM712_DDA_REG2_VCENTER_MASK 0x3f + +static struct +{ + grub_uint8_t compare; + grub_uint16_t dda; + grub_uint8_t vcentering; +} dda_lookups[] = { + { 21, 469, 2}, + { 23, 477, 2}, + { 33, 535, 2}, + { 35, 682, 21}, + { 34, 675, 2}, + { 55, 683, 6}, +}; static struct { @@ -42,6 +200,7 @@ static struct grub_pci_device_t dev; } framebuffer; +#ifndef TEST static grub_err_t grub_video_sm712_video_init (void) { @@ -60,6 +219,118 @@ grub_video_sm712_video_fini (void) return grub_video_fb_fini (); } +#endif + +static inline void +grub_sm712_write_reg (grub_uint8_t val, grub_uint16_t addr) +{ +#ifdef TEST + printf (" {1, 0x%x, 0x%x},\n", addr, val); +#else + *(volatile grub_uint8_t *) (framebuffer.ptr + GRUB_SM712_REG_BASE + + addr) = val; +#endif +} + +static inline grub_uint8_t +grub_sm712_read_reg (grub_uint16_t addr) +{ +#ifdef TEST + printf (" {-1, 0x%x, 0x5},\n", addr); +#else + return *(volatile grub_uint8_t *) (framebuffer.ptr + GRUB_SM712_REG_BASE + + addr); +#endif +} + +static inline grub_uint8_t +grub_sm712_sr_read (grub_uint8_t addr) +{ + grub_sm712_write_reg (addr, GRUB_VGA_IO_SR_INDEX); + return grub_sm712_read_reg (GRUB_VGA_IO_SR_DATA); +} + +static inline void +grub_sm712_sr_write (grub_uint8_t val, grub_uint8_t addr) +{ + grub_sm712_write_reg (addr, GRUB_VGA_IO_SR_INDEX); + grub_sm712_write_reg (val, GRUB_VGA_IO_SR_DATA); +} + +static inline void +grub_sm712_gr_write (grub_uint8_t val, grub_uint8_t addr) +{ + grub_sm712_write_reg (addr, GRUB_VGA_IO_GR_INDEX); + grub_sm712_write_reg (val, GRUB_VGA_IO_GR_DATA); +} + +static inline void +grub_sm712_cr_write (grub_uint8_t val, grub_uint8_t addr) +{ + grub_sm712_write_reg (addr, GRUB_VGA_IO_CR_INDEX); + grub_sm712_write_reg (val, GRUB_VGA_IO_CR_DATA); +} + +static inline void +grub_sm712_write_arx (grub_uint8_t val, grub_uint8_t addr) +{ + grub_sm712_read_reg (GRUB_VGA_IO_INPUT_STATUS1_REGISTER); + grub_sm712_write_reg (addr, GRUB_VGA_IO_ARX); + grub_sm712_read_reg (GRUB_VGA_IO_ARX_READ); + grub_sm712_write_reg (val, GRUB_VGA_IO_ARX); +} + +static inline void +grub_sm712_cr_shadow_write (grub_uint8_t val, grub_uint8_t addr) +{ + grub_uint8_t mapping[] = + { + [GRUB_VGA_CR_HTOTAL] = GRUB_SM712_CR_SHADOW_VGA_HTOTAL, + [GRUB_VGA_CR_HORIZ_END] = 0xff, + [GRUB_VGA_CR_HBLANK_START] = GRUB_SM712_CR_SHADOW_VGA_HBLANK_START, + [GRUB_VGA_CR_HBLANK_END] = GRUB_SM712_CR_SHADOW_VGA_HBLANK_END, + [GRUB_VGA_CR_HORIZ_SYNC_PULSE_START] = GRUB_SM712_CR_SHADOW_VGA_HRETRACE_START, + [GRUB_VGA_CR_HORIZ_SYNC_PULSE_END] = GRUB_SM712_CR_SHADOW_VGA_HRETRACE_END, + [GRUB_VGA_CR_VERT_TOTAL] = GRUB_SM712_CR_SHADOW_VGA_VERTICAL_TOTAL, + [GRUB_VGA_CR_OVERFLOW] = GRUB_SM712_CR_SHADOW_VGA_OVERFLOW, + [GRUB_VGA_CR_BYTE_PANNING] = 0xff, + [GRUB_VGA_CR_CELL_HEIGHT] = GRUB_SM712_CR_SHADOW_VGA_CELL_HEIGHT, + [GRUB_VGA_CR_CURSOR_START] = 0xff, + [GRUB_VGA_CR_CURSOR_END] = 0xff, + [GRUB_VGA_CR_START_ADDR_HIGH_REGISTER] = 0xff, + [GRUB_VGA_CR_START_ADDR_LOW_REGISTER] = 0xff, + [GRUB_VGA_CR_CURSOR_ADDR_HIGH] = 0xff, + [GRUB_VGA_CR_CURSOR_ADDR_LOW] = 0xff, + [GRUB_VGA_CR_VSYNC_START] = GRUB_SM712_CR_SHADOW_VGA_VRETRACE_START, + [GRUB_VGA_CR_VSYNC_END] = GRUB_SM712_CR_SHADOW_VGA_VRETRACE_END, + [GRUB_VGA_CR_VDISPLAY_END] = GRUB_SM712_CR_SHADOW_VGA_VDISPLAY_END, + [GRUB_VGA_CR_PITCH] = GRUB_SM712_CR_SHADOW_VGA_HDISPLAY_END, + [GRUB_VGA_CR_UNDERLINE_LOCATION] = 0xff, + + [GRUB_VGA_CR_VERTICAL_BLANK_START] = GRUB_SM712_CR_SHADOW_VGA_VBLANK_START, + [GRUB_VGA_CR_VERTICAL_BLANK_END] = GRUB_SM712_CR_SHADOW_VGA_VBLANK_END, + [GRUB_VGA_CR_MODE] = 0xff, + [GRUB_VGA_CR_LINE_COMPARE] = 0xff + }; + if (addr >= ARRAY_SIZE (mapping) || mapping[addr] == 0xff) + return; + grub_sm712_cr_write (val, mapping[addr]); +} + +static inline void +grub_sm712_write_dda_lookup (int idx, grub_uint8_t compare, grub_uint16_t dda, + grub_uint8_t vcentering) +{ + grub_sm712_cr_write (((compare << SM712_DDA_REG3_COMPARE_SHIFT) + & SM712_DDA_REG3_COMPARE_MASK) + | ((dda >> SM712_DDA_REG3_DDA_SHIFT) + & SM712_DDA_REG3_DDA_MASK), + GRUB_SM712_CR_DDA_LOOKUP_REG3_START + 2 * idx); + grub_sm712_cr_write (dda & SM712_DDA_REG2_DDA_MASK, + GRUB_SM712_CR_DDA_LOOKUP_REG2_START + 2 * idx); + grub_sm712_cr_write (vcentering & SM712_DDA_REG2_VCENTER_MASK, + GRUB_SM712_CR_DDA_LOOKUP_REG1_START + idx); +} static grub_err_t grub_video_sm712_setup (unsigned int width, unsigned int height, @@ -70,6 +341,7 @@ grub_video_sm712_setup (unsigned int width, unsigned int height, int found = 0; unsigned i; +#ifndef TEST auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused))); int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ ((unused))) { @@ -79,7 +351,8 @@ grub_video_sm712_setup (unsigned int width, unsigned int height, addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); class = grub_pci_read (addr); - if (((class >> 16) & 0xffff) != 0x0300 || pciid != 0x0712126f) + if (((class >> 16) & 0xffff) != GRUB_PCI_CLASS_SUBCLASS_VGA + || pciid != GRUB_SM712_PCIID) return 0; found = 1; @@ -103,7 +376,7 @@ grub_video_sm712_setup (unsigned int width, unsigned int height, grub_pci_iterate (find_card); if (!found) return grub_error (GRUB_ERR_IO, "Couldn't find graphics card"); - +#endif /* Fill mode info details. */ framebuffer.mode_info.width = 1024; framebuffer.mode_info.height = 600; @@ -120,8 +393,12 @@ grub_video_sm712_setup (unsigned int width, unsigned int height, framebuffer.mode_info.blue_field_pos = 0; framebuffer.mode_info.reserved_mask_size = 0; framebuffer.mode_info.reserved_field_pos = 0; - framebuffer.mode_info.blit_format = grub_video_get_blit_format (&framebuffer.mode_info); +#ifndef TEST + framebuffer.mode_info.blit_format + = grub_video_get_blit_format (&framebuffer.mode_info); +#endif +#ifndef TEST if (found && framebuffer.base == 0) { grub_pci_address_t addr; @@ -139,47 +416,280 @@ grub_video_sm712_setup (unsigned int width, unsigned int height, addr = grub_pci_make_address (framebuffer.dev, GRUB_PCI_REG_COMMAND); grub_pci_write (addr, 0x7); } +#endif /* We can safely discard volatile attribute. */ +#ifndef TEST framebuffer.ptr = (void *) grub_pci_device_map_range (framebuffer.dev, framebuffer.base, GRUB_SM712_TOTAL_MEMORY_SPACE); +#endif framebuffer.mapped = 1; /* Initialise SM712. */ - grub_outb (0x18, GRUB_MACHINE_PCI_IO_BASE + 0x3c4); - grub_outb (0x11, GRUB_MACHINE_PCI_IO_BASE + 0x3c5); +#ifndef TEST + /* FIXME */ + grub_vga_sr_write (0x11, 0x18); +#endif +#ifndef TEST /* Prevent garbage from appearing on the screen. */ grub_memset (framebuffer.ptr, 0, framebuffer.mode_info.height * framebuffer.mode_info.pitch); +#endif - for (i = 0; i < ARRAY_SIZE (sm712_init); i++) - switch (sm712_init[i].directive) + /* FIXME */ + grub_sm712_sr_write (0, 0x21); + grub_sm712_sr_write (0x7a, 0x62); + grub_sm712_sr_write (0x16, 0x6a); + grub_sm712_sr_write (0x2, 0x6b); + grub_sm712_write_reg (0, GRUB_VGA_IO_PIXEL_MASK); + grub_sm712_sr_write (GRUB_VGA_SR_RESET_ASYNC, GRUB_VGA_SR_RESET); + grub_sm712_write_reg (GRUB_VGA_IO_MISC_NEGATIVE_VERT_POLARITY + | GRUB_VGA_IO_MISC_NEGATIVE_HORIZ_POLARITY + | GRUB_VGA_IO_MISC_UPPER_64K + | GRUB_VGA_IO_MISC_EXTERNAL_CLOCK_0 + | GRUB_VGA_IO_MISC_ENABLE_VRAM_ACCESS + | GRUB_VGA_IO_MISC_COLOR, GRUB_VGA_IO_MISC_WRITE); + grub_sm712_sr_write (GRUB_VGA_SR_RESET_ASYNC | GRUB_VGA_SR_RESET_SYNC, + GRUB_VGA_SR_RESET); + grub_sm712_sr_write (GRUB_VGA_SR_CLOCKING_MODE_8_DOT_CLOCK, + GRUB_VGA_SR_CLOCKING_MODE); + grub_sm712_sr_write (GRUB_VGA_ALL_PLANES, GRUB_VGA_SR_MAP_MASK_REGISTER); + grub_sm712_sr_write (0, GRUB_VGA_SR_CHAR_MAP_SELECT); + grub_sm712_sr_write (GRUB_VGA_SR_MEMORY_MODE_CHAIN4 + | GRUB_VGA_SR_MEMORY_MODE_SEQUENTIAL_ADDRESSING + | GRUB_VGA_SR_MEMORY_MODE_EXTERNAL_VIDEO_MEMORY, + GRUB_VGA_SR_MEMORY_MODE); + + for (i = 0; i < ARRAY_SIZE (sm712_sr_seq1); i++) + grub_sm712_sr_write (sm712_sr_seq1[i], 0x10 + i); + + for (i = 0; i < ARRAY_SIZE (sm712_sr_seq2); i++) + grub_sm712_sr_write (sm712_sr_seq2[i], 0x30 + i); + + /* Undocumented. */ + grub_sm712_sr_write (0x1a, 0x63); + /* Undocumented. */ + grub_sm712_sr_write (0x1a, 0x64); + + grub_sm712_sr_write (GRUB_SM712_SR_TV_CRT_SRAM | GRUB_SM712_SR_TV_ALT_CLOCK + | GRUB_SM712_SR_TV_CLOCK_CKIN_NTSC + | GRUB_SM712_SR_TV_HSYNC, + GRUB_SM712_SR_TV_CONTROL); + + grub_sm712_sr_write (GRUB_SM712_SR_RAM_LUT_NORMAL, GRUB_SM712_SR_RAM_LUT); + + /* Undocumented. */ + grub_sm712_sr_write (0x00, 0x67); + + grub_sm712_sr_write (GRUB_SM712_SR_CLOCK_CONTROL1_VCLK_FROM_CCR + | GRUB_SM712_SR_CLOCK_CONTROL1_8DOT_CLOCK, + GRUB_SM712_SR_CLOCK_CONTROL1); + grub_sm712_sr_write (GRUB_SM712_SR_CLOCK_CONTROL2_PROGRAM_VCLOCK, + GRUB_SM712_SR_CLOCK_CONTROL2); + + grub_sm712_sr_write (82, GRUB_SM712_SR_VCLK_NUM); + grub_sm712_sr_write (137, GRUB_SM712_SR_VCLK_DENOM); + + grub_sm712_sr_write (9, GRUB_SM712_SR_VCLK2_NUM); + grub_sm712_sr_write (2, GRUB_SM712_SR_VCLK2_DENOM); + /* FIXME */ + grub_sm712_sr_write (0x04, 0x70); + /* FIXME */ + grub_sm712_sr_write (0x45, 0x71); + /* Undocumented */ + grub_sm712_sr_write (0x30, 0x72); + /* Undocumented */ + grub_sm712_sr_write (0x30, 0x73); + /* Undocumented */ + grub_sm712_sr_write (0x40, 0x74); + /* Undocumented */ + grub_sm712_sr_write (0x20, 0x75); + + grub_sm712_sr_write (0xff, GRUB_SM712_SR_POPUP_ICON_LOW); + grub_sm712_sr_write (GRUB_SM712_SR_POPUP_ICON_HIGH_MASK, + GRUB_SM712_SR_POPUP_ICON_HIGH); + grub_sm712_sr_write (GRUB_SM712_SR_POPUP_ICON_CTRL_DISABLED, + GRUB_SM712_SR_POPUP_ICON_CTRL); + /* Undocumented */ + grub_sm712_sr_write (0x0, 0x83); + + grub_sm712_sr_write (8, GRUB_SM712_SR_POPUP_ICON_COLOR1); + grub_sm712_sr_write (0, GRUB_SM712_SR_POPUP_ICON_COLOR2); + grub_sm712_sr_write (0x42, GRUB_SM712_SR_POPUP_ICON_COLOR3); + + /* Undocumented */ + grub_sm712_sr_write (0x3a, 0x87); + + /* Why theese coordinates? */ + grub_sm712_sr_write (0x59, GRUB_SM712_SR_HW_CURSOR_UPPER_LEFT_X_LOW); + grub_sm712_sr_write (0x02, GRUB_SM712_SR_HW_CURSOR_UPPER_LEFT_X_HIGH); + grub_sm712_sr_write (0x44, GRUB_SM712_SR_HW_CURSOR_UPPER_LEFT_Y_LOW); + grub_sm712_sr_write (0x02, GRUB_SM712_SR_HW_CURSOR_UPPER_LEFT_Y_HIGH); + + grub_sm712_sr_write (RGB332_BLACK, GRUB_SM712_SR_HW_CURSOR_FG_COLOR); + grub_sm712_sr_write (RGB332_WHITE, GRUB_SM712_SR_HW_CURSOR_BG_COLOR); + + /* Undocumented */ + grub_sm712_sr_write (0x3a, 0x8e); + grub_sm712_sr_write (0x3a, 0x8f); + + grub_sm712_sr_write (0, GRUB_SM712_SR_POPUP_ICON_X_LOW); + grub_sm712_sr_write (0, GRUB_SM712_SR_POPUP_ICON_X_HIGH); + grub_sm712_sr_write (0, GRUB_SM712_SR_POPUP_ICON_Y_LOW); + grub_sm712_sr_write (0, GRUB_SM712_SR_POPUP_ICON_Y_HIGH); + + grub_sm712_sr_write (0, GRUB_SM712_SR_PANEL_HW_VIDEO_CONTROL); + grub_sm712_sr_write (0x10, GRUB_SM712_SR_PANEL_HW_VIDEO_COLOR_KEY_LOW); + grub_sm712_sr_write (0x08, GRUB_SM712_SR_PANEL_HW_VIDEO_COLOR_KEY_HIGH); + grub_sm712_sr_write (0x00, GRUB_SM712_SR_PANEL_HW_VIDEO_COLOR_KEY_MASK_LOW); + grub_sm712_sr_write (0x02, GRUB_SM712_SR_PANEL_HW_VIDEO_COLOR_KEY_MASK_HIGH); + grub_sm712_sr_write (0xed, GRUB_SM712_SR_PANEL_HW_VIDEO_RED_CONSTANT); + grub_sm712_sr_write (0xed, GRUB_SM712_SR_PANEL_HW_VIDEO_GREEN_CONSTANT); + grub_sm712_sr_write (0xed, GRUB_SM712_SR_PANEL_HW_VIDEO_BLUE_CONSTANT); + + grub_sm712_sr_write (0x7b, GRUB_SM712_SR_PANEL_HW_VIDEO_TOP_BOUNDARY); + grub_sm712_sr_write (0xfb, GRUB_SM712_SR_PANEL_HW_VIDEO_LEFT_BOUNDARY); + grub_sm712_sr_write (0xff, GRUB_SM712_SR_PANEL_HW_VIDEO_BOTTOM_BOUNDARY); + grub_sm712_sr_write (0xff, GRUB_SM712_SR_PANEL_HW_VIDEO_RIGHT_BOUNDARY); + /* Doesn't match documentation? */ + grub_sm712_sr_write (0x97, GRUB_SM712_SR_PANEL_HW_VIDEO_TOP_LEFT_OVERFLOW_BOUNDARY); + grub_sm712_sr_write (0xef, GRUB_SM712_SR_PANEL_HW_VIDEO_BOTTOM_RIGHT_OVERFLOW_BOUNDARY); + + grub_sm712_sr_write (0xbf, GRUB_SM712_SR_PANEL_HW_VIDEO_VERTICAL_STRETCH_FACTOR); + grub_sm712_sr_write (0xdf, GRUB_SM712_SR_PANEL_HW_VIDEO_HORIZONTAL_STRETCH_FACTOR); + + grub_sm712_gr_write (GRUB_VGA_NO_PLANES, GRUB_VGA_GR_SET_RESET_PLANE); + grub_sm712_gr_write (GRUB_VGA_NO_PLANES, GRUB_VGA_GR_SET_RESET_PLANE_ENABLE); + grub_sm712_gr_write (GRUB_VGA_NO_PLANES, GRUB_VGA_GR_COLOR_COMPARE); + grub_sm712_gr_write (GRUB_VGA_GR_DATA_ROTATE_NOP, GRUB_VGA_GR_DATA_ROTATE); + grub_sm712_gr_write (GRUB_VGA_NO_PLANES, GRUB_VGA_GR_READ_MAP_REGISTER); + grub_sm712_gr_write (GRUB_VGA_GR_MODE_256_COLOR, GRUB_VGA_GR_MODE); + grub_sm712_gr_write (GRUB_VGA_GR_GR6_MMAP_A0 + | GRUB_VGA_GR_GR6_GRAPHICS_MODE, GRUB_VGA_GR_GR6); + grub_sm712_gr_write (GRUB_VGA_ALL_PLANES, GRUB_VGA_GR_COLOR_COMPARE_DISABLE); + grub_sm712_gr_write (0xff, GRUB_VGA_GR_BITMASK); + + /* Write palette mapping. */ + for (i = 0; i < 16; i++) + grub_sm712_write_arx (i, i); + + grub_sm712_write_arx (GRUB_VGA_ARX_MODE_ENABLE_256COLOR + | GRUB_VGA_ARX_MODE_GRAPHICS, GRUB_VGA_ARX_MODE); + grub_sm712_write_arx (0, GRUB_VGA_ARX_OVERSCAN); + grub_sm712_write_arx (GRUB_VGA_ALL_PLANES, GRUB_VGA_ARX_COLOR_PLANE_ENABLE); + grub_sm712_write_arx (0, GRUB_VGA_ARX_HORIZONTAL_PANNING); + grub_sm712_write_arx (0, GRUB_VGA_ARX_COLOR_SELECT); + + /* FIXME: compute this generically. */ + { + struct grub_video_hw_config config = { - case 1: - *(volatile grub_uint8_t *) ((char *) framebuffer.ptr - + sm712_init[i].addr) = sm712_init[i].val; - break; - case -1: - { - grub_uint8_t val = *(volatile grub_uint8_t *) - ((char *) framebuffer.ptr + sm712_init[i].addr); - (void) val; - } - break; - case 2: - *(volatile grub_uint16_t *) ((char *) framebuffer.ptr - + sm712_init[i].addr) = sm712_init[i].val; - break; - case 4: - *(volatile grub_uint32_t *) ((char *) framebuffer.ptr - + sm712_init[i].addr) = sm712_init[i].val; - break; - } + .vertical_total = 806, + .vertical_blank_start = 0x300, + .vertical_blank_end = 0, + .vertical_sync_start = 0x303, + .vertical_sync_end = 0x9, + .line_compare = 0x3ff, + .vdisplay_end = 0x300, + .pitch = 0x80, + .horizontal_total = 164, + .horizontal_end = 128, + .horizontal_blank_start = 128, + .horizontal_blank_end = 0, + .horizontal_sync_pulse_start = 133, + .horizontal_sync_pulse_end = 22 + }; + grub_vga_set_geometry (&config, grub_sm712_cr_write); + config.horizontal_sync_pulse_start = 134; + config.horizontal_sync_pulse_end = 21; + config.vertical_sync_start = 0x301; + config.vertical_sync_end = 0x0; + config.line_compare = 0x0ff; + config.vdisplay_end = 0x258; + config.pitch = 0x7f; + grub_vga_set_geometry (&config, grub_sm712_cr_shadow_write); + } - err = grub_video_fb_create_render_target_from_pointer (&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr); + grub_sm712_cr_write (GRUB_VGA_CR_BYTE_PANNING_NORMAL, + GRUB_VGA_CR_BYTE_PANNING); + grub_sm712_cr_write (0, GRUB_VGA_CR_CURSOR_START); + grub_sm712_cr_write (0, GRUB_VGA_CR_CURSOR_END); + grub_sm712_cr_write (0, GRUB_VGA_CR_START_ADDR_HIGH_REGISTER); + grub_sm712_cr_write (0, GRUB_VGA_CR_START_ADDR_LOW_REGISTER); + grub_sm712_cr_write (0, GRUB_VGA_CR_CURSOR_ADDR_HIGH); + grub_sm712_cr_write (0, GRUB_VGA_CR_CURSOR_ADDR_LOW); + grub_sm712_cr_write (GRUB_VGA_CR_UNDERLINE_LOCATION_DWORD_MODE, + GRUB_VGA_CR_UNDERLINE_LOCATION); + grub_sm712_cr_write (GRUB_VGA_CR_MODE_ADDRESS_WRAP + | GRUB_VGA_CR_MODE_BYTE_MODE + | GRUB_VGA_CR_MODE_TIMING_ENABLE + | GRUB_VGA_CR_MODE_NO_CGA + | GRUB_VGA_CR_MODE_NO_HERCULES, + GRUB_VGA_CR_MODE); + + grub_sm712_cr_write (0, GRUB_SM712_CR_OVERFLOW_INTERLACE); + grub_sm712_cr_write (0, GRUB_SM712_CR_INTERLACE_RETRACE); + grub_sm712_cr_write (0, GRUB_SM712_CR_TV_VDISPLAY_START); + grub_sm712_cr_write (0, GRUB_SM712_CR_TV_VDISPLAY_END_HIGH); + grub_sm712_cr_write (0, GRUB_SM712_CR_TV_VDISPLAY_END_LOW); + grub_sm712_cr_write (0x80, GRUB_SM712_CR_DDA_CONTROL_LOW); + grub_sm712_cr_write (0x02, GRUB_SM712_CR_DDA_CONTROL_HIGH); + + /* Undocumented */ + grub_sm712_cr_write (0x20, 0x37); + + grub_sm712_cr_write (0, GRUB_SM712_CR_TV_EQUALIZER); + grub_sm712_cr_write (0, GRUB_SM712_CR_TV_SERRATION); + grub_sm712_cr_write (0, GRUB_SM712_CR_HSYNC_CTRL); + + /* Undocumented */ + grub_sm712_cr_write (0x40, 0x3b); + + grub_sm712_cr_write (GRUB_SM712_CR_DEBUG_NONE, GRUB_SM712_CR_DEBUG); + + /* Undocumented */ + grub_sm712_cr_write (0xff, 0x3d); + grub_sm712_cr_write (0x46, 0x3e); + grub_sm712_cr_write (0x91, 0x3f); + + for (i = 0; i < ARRAY_SIZE (dda_lookups); i++) + grub_sm712_write_dda_lookup (i, dda_lookups[i].compare, dda_lookups[i].dda, + dda_lookups[i].vcentering); + + /* Undocumented */ + grub_sm712_cr_write (0, 0x9c); + grub_sm712_cr_write (0, 0x9d); + grub_sm712_cr_write (0, 0x9e); + grub_sm712_cr_write (0, 0x9f); + + grub_sm712_cr_write (0, GRUB_SM712_CR_VCENTERING_OFFSET); + grub_sm712_cr_write (0, GRUB_SM712_CR_HCENTERING_OFFSET); + + grub_sm712_write_reg (GRUB_VGA_IO_MISC_NEGATIVE_HORIZ_POLARITY + | GRUB_VGA_IO_MISC_UPPER_64K + | GRUB_VGA_IO_MISC_28MHZ + | GRUB_VGA_IO_MISC_ENABLE_VRAM_ACCESS + | GRUB_VGA_IO_MISC_COLOR, + GRUB_VGA_IO_MISC_WRITE); + +#ifndef TEST + /* Undocumented? */ + *(volatile grub_uint32_t *) ((char *) framebuffer.ptr + 0x40c00c) = 0; + *(volatile grub_uint32_t *) ((char *) framebuffer.ptr + 0x40c040) = 0; + *(volatile grub_uint32_t *) ((char *) framebuffer.ptr + 0x40c000) = 0x20000; + *(volatile grub_uint32_t *) ((char *) framebuffer.ptr + 0x40c010) = 0x1020100; +#endif + + (void) grub_sm712_sr_read (0x16); + +#ifndef TEST + err = grub_video_fb_create_render_target_from_pointer (&framebuffer + .render_target, + &framebuffer.mode_info, + framebuffer.ptr); if (err) return err; @@ -192,9 +702,12 @@ grub_video_sm712_setup (unsigned int width, unsigned int height, /* Copy default palette to initialize emulated palette. */ err = grub_video_fb_set_palette (0, GRUB_VIDEO_FBSTD_NUMCOLORS, grub_video_fbstd_colors); +#endif return err; } +#ifndef TEST + static grub_err_t grub_video_sm712_swap_buffers (void) { @@ -223,7 +736,6 @@ grub_video_sm712_get_info_and_fini (struct grub_video_mode_info *mode_info, return GRUB_ERR_NONE; } - static struct grub_video_adapter grub_video_sm712_adapter = { .name = "SM712 Video Driver", @@ -266,3 +778,10 @@ GRUB_MOD_FINI(video_sm712) { grub_video_unregister (&grub_video_sm712_adapter); } +#else +int +main () +{ + grub_video_sm712_setup (1024, 600, 0, 0); +} +#endif diff --git a/grub-core/video/sm712_init.c b/grub-core/video/sm712_init.c index 02c64c453..cdb0b7383 100644 --- a/grub-core/video/sm712_init.c +++ b/grub-core/video/sm712_init.c @@ -1,546 +1,14 @@ /* Following sequence is a capture of sm712 initialisation sequence. */ -static struct -{ - int directive; - grub_uint32_t addr; - grub_uint32_t val; -} sm712_init[] = -{ - {1, 0x7003c4, 0x21}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x62}, - {1, 0x7003c5, 0x7a}, - {1, 0x7003c4, 0x6a}, - {1, 0x7003c5, 0x16}, - {1, 0x7003c4, 0x6b}, - {1, 0x7003c5, 0x2}, - {1, 0x7003c6, 0x0}, - {1, 0x7003c4, 0x0}, - {1, 0x7003c5, 0x1}, - {1, 0x7003c2, 0xeb}, - {1, 0x7003c4, 0x0}, - {1, 0x7003c5, 0x3}, - {1, 0x7003c4, 0x1}, - {1, 0x7003c5, 0x1}, - {1, 0x7003c4, 0x2}, - {1, 0x7003c5, 0xf}, - {1, 0x7003c4, 0x3}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x4}, - {1, 0x7003c5, 0xe}, - {1, 0x7003c4, 0x10}, - {1, 0x7003c5, 0xc8}, - {1, 0x7003c4, 0x11}, - {1, 0x7003c5, 0x40}, - {1, 0x7003c4, 0x12}, - {1, 0x7003c5, 0x14}, - {1, 0x7003c4, 0x13}, - {1, 0x7003c5, 0x60}, - {1, 0x7003c4, 0x14}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x15}, - {1, 0x7003c5, 0xa}, - {1, 0x7003c4, 0x16}, - {1, 0x7003c5, 0x92}, - {1, 0x7003c4, 0x17}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x18}, - {1, 0x7003c5, 0x51}, - {1, 0x7003c4, 0x19}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x1a}, - {1, 0x7003c5, 0x1}, - {1, 0x7003c4, 0x1b}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x1c}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x1d}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x1e}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x1f}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x20}, - {1, 0x7003c5, 0xc4}, - {1, 0x7003c4, 0x21}, - {1, 0x7003c5, 0x30}, - {1, 0x7003c4, 0x22}, - {1, 0x7003c5, 0x2}, - {1, 0x7003c4, 0x23}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x24}, - {1, 0x7003c5, 0x1}, - {1, 0x7003c4, 0x30}, - {1, 0x7003c5, 0x28}, - {1, 0x7003c4, 0x31}, - {1, 0x7003c5, 0x3}, - {1, 0x7003c4, 0x32}, - {1, 0x7003c5, 0x24}, - {1, 0x7003c4, 0x33}, - {1, 0x7003c5, 0x9}, - {1, 0x7003c4, 0x34}, - {1, 0x7003c5, 0xc0}, - {1, 0x7003c4, 0x35}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x36}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x37}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x38}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x39}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x3a}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x3b}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x3c}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x3d}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x3e}, - {1, 0x7003c5, 0x3}, - {1, 0x7003c4, 0x3f}, - {1, 0x7003c5, 0xff}, - {1, 0x7003c4, 0x40}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x41}, - {1, 0x7003c5, 0xfc}, - {1, 0x7003c4, 0x42}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x43}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x44}, - {1, 0x7003c5, 0x20}, - {1, 0x7003c4, 0x45}, - {1, 0x7003c5, 0x18}, - {1, 0x7003c4, 0x46}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x47}, - {1, 0x7003c5, 0xfc}, - {1, 0x7003c4, 0x48}, - {1, 0x7003c5, 0x20}, - {1, 0x7003c4, 0x49}, - {1, 0x7003c5, 0xc}, - {1, 0x7003c4, 0x4a}, - {1, 0x7003c5, 0x44}, - {1, 0x7003c4, 0x4b}, - {1, 0x7003c5, 0x20}, - {1, 0x7003c4, 0x4c}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x4d}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x4e}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x4f}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x50}, - {1, 0x7003c5, 0x6}, - {1, 0x7003c4, 0x51}, - {1, 0x7003c5, 0x68}, - {1, 0x7003c4, 0x52}, - {1, 0x7003c5, 0xa7}, - {1, 0x7003c4, 0x53}, - {1, 0x7003c5, 0x7f}, - {1, 0x7003c4, 0x54}, - {1, 0x7003c5, 0x83}, - {1, 0x7003c4, 0x55}, - {1, 0x7003c5, 0x24}, - {1, 0x7003c4, 0x56}, - {1, 0x7003c5, 0xff}, - {1, 0x7003c4, 0x57}, - {1, 0x7003c5, 0x3}, - {1, 0x7003c4, 0x58}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x59}, - {1, 0x7003c5, 0x60}, - {1, 0x7003c4, 0x5a}, - {1, 0x7003c5, 0x59}, - {1, 0x7003c4, 0x5b}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x5c}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x5d}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x5e}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x5f}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x60}, - {1, 0x7003c5, 0x1}, - {1, 0x7003c4, 0x61}, - {1, 0x7003c5, 0x80}, - {1, 0x7003c4, 0x63}, - {1, 0x7003c5, 0x1a}, - {1, 0x7003c4, 0x64}, - {1, 0x7003c5, 0x1a}, - {1, 0x7003c4, 0x65}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x66}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x67}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x68}, - {1, 0x7003c5, 0x50}, - {1, 0x7003c4, 0x69}, - {1, 0x7003c5, 0x3}, - {1, 0x7003c4, 0x6c}, - {1, 0x7003c5, 0x52}, - {1, 0x7003c4, 0x6d}, - {1, 0x7003c5, 0x89}, - {1, 0x7003c4, 0x6e}, - {1, 0x7003c5, 0x9}, - {1, 0x7003c4, 0x6f}, - {1, 0x7003c5, 0x2}, - {1, 0x7003c4, 0x70}, - {1, 0x7003c5, 0x4}, - {1, 0x7003c4, 0x71}, - {1, 0x7003c5, 0x45}, - {1, 0x7003c4, 0x72}, - {1, 0x7003c5, 0x30}, - {1, 0x7003c4, 0x73}, - {1, 0x7003c5, 0x30}, - {1, 0x7003c4, 0x74}, - {1, 0x7003c5, 0x40}, - {1, 0x7003c4, 0x75}, - {1, 0x7003c5, 0x20}, - {1, 0x7003c4, 0x80}, - {1, 0x7003c5, 0xff}, - {1, 0x7003c4, 0x81}, - {1, 0x7003c5, 0x7}, - {1, 0x7003c4, 0x82}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x83}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x84}, - {1, 0x7003c5, 0x8}, - {1, 0x7003c4, 0x85}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x86}, - {1, 0x7003c5, 0x42}, - {1, 0x7003c4, 0x87}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x88}, - {1, 0x7003c5, 0x59}, - {1, 0x7003c4, 0x89}, - {1, 0x7003c5, 0x2}, - {1, 0x7003c4, 0x8a}, - {1, 0x7003c5, 0x44}, - {1, 0x7003c4, 0x8b}, - {1, 0x7003c5, 0x2}, - {1, 0x7003c4, 0x8c}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x8d}, - {1, 0x7003c5, 0xff}, - {1, 0x7003c4, 0x8e}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x8f}, - {1, 0x7003c5, 0x3a}, - {1, 0x7003c4, 0x90}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x91}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x92}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0x93}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0xa0}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0xa1}, - {1, 0x7003c5, 0x10}, - {1, 0x7003c4, 0xa2}, - {1, 0x7003c5, 0x8}, - {1, 0x7003c4, 0xa3}, - {1, 0x7003c5, 0x0}, - {1, 0x7003c4, 0xa4}, - {1, 0x7003c5, 0x2}, - {1, 0x7003c4, 0xa5}, - {1, 0x7003c5, 0xed}, - {1, 0x7003c4, 0xa6}, - {1, 0x7003c5, 0xed}, - {1, 0x7003c4, 0xa7}, - {1, 0x7003c5, 0xed}, - {1, 0x7003c4, 0xa8}, - {1, 0x7003c5, 0x7b}, - {1, 0x7003c4, 0xa9}, - {1, 0x7003c5, 0xfb}, - {1, 0x7003c4, 0xaa}, - {1, 0x7003c5, 0xff}, - {1, 0x7003c4, 0xab}, - {1, 0x7003c5, 0xff}, - {1, 0x7003c4, 0xac}, - {1, 0x7003c5, 0x97}, - {1, 0x7003c4, 0xad}, - {1, 0x7003c5, 0xef}, - {1, 0x7003c4, 0xae}, - {1, 0x7003c5, 0xbf}, - {1, 0x7003c4, 0xaf}, - {1, 0x7003c5, 0xdf}, - {1, 0x7003ce, 0x0}, - {1, 0x7003cf, 0x0}, - {1, 0x7003ce, 0x1}, - {1, 0x7003cf, 0x0}, - {1, 0x7003ce, 0x2}, - {1, 0x7003cf, 0x0}, - {1, 0x7003ce, 0x3}, - {1, 0x7003cf, 0x0}, - {1, 0x7003ce, 0x4}, - {1, 0x7003cf, 0x0}, - {1, 0x7003ce, 0x5}, - {1, 0x7003cf, 0x40}, - {1, 0x7003ce, 0x6}, - {1, 0x7003cf, 0x5}, - {1, 0x7003ce, 0x7}, - {1, 0x7003cf, 0xf}, - {1, 0x7003ce, 0x8}, - {1, 0x7003cf, 0xff}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x0}, - {-1, 0x7003c1, 0x3e}, - {1, 0x7003c0, 0x0}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x1}, - {-1, 0x7003c1, 0x3b}, - {1, 0x7003c0, 0x1}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x2}, - {-1, 0x7003c1, 0x3f}, - {1, 0x7003c0, 0x2}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x3}, - {-1, 0x7003c1, 0x3f}, - {1, 0x7003c0, 0x3}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x4}, - {-1, 0x7003c1, 0x3b}, - {1, 0x7003c0, 0x4}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x5}, - {-1, 0x7003c1, 0x2f}, - {1, 0x7003c0, 0x5}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x6}, - {-1, 0x7003c1, 0x3f}, - {1, 0x7003c0, 0x6}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x7}, - {-1, 0x7003c1, 0x3f}, - {1, 0x7003c0, 0x7}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x8}, - {-1, 0x7003c1, 0x3f}, - {1, 0x7003c0, 0x8}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x9}, - {-1, 0x7003c1, 0x3d}, - {1, 0x7003c0, 0x9}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0xa}, - {-1, 0x7003c1, 0x1f}, - {1, 0x7003c0, 0xa}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0xb}, - {-1, 0x7003c1, 0x1f}, - {1, 0x7003c0, 0xb}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0xc}, - {-1, 0x7003c1, 0x3f}, - {1, 0x7003c0, 0xc}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0xd}, - {-1, 0x7003c1, 0x3f}, - {1, 0x7003c0, 0xd}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0xe}, - {-1, 0x7003c1, 0x3f}, - {1, 0x7003c0, 0xe}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0xf}, - {-1, 0x7003c1, 0x2e}, - {1, 0x7003c0, 0xf}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x10}, - {-1, 0x7003c1, 0x0}, - {1, 0x7003c0, 0x41}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x11}, - {-1, 0x7003c1, 0x0}, - {1, 0x7003c0, 0x0}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x12}, - {-1, 0x7003c1, 0x0}, - {1, 0x7003c0, 0xf}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x13}, - {-1, 0x7003c1, 0x0}, - {1, 0x7003c0, 0x0}, - {-1, 0x7003da, 0x5}, - {1, 0x7003c0, 0x14}, - {-1, 0x7003c1, 0x0}, - {1, 0x7003c0, 0x0}, - {1, 0x7003d4, 0x0}, - {1, 0x7003d5, 0xa3}, - {1, 0x7003d4, 0x1}, - {1, 0x7003d5, 0x7f}, - {1, 0x7003d4, 0x2}, - {1, 0x7003d5, 0x7f}, - {1, 0x7003d4, 0x3}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x4}, - {1, 0x7003d5, 0x85}, - {1, 0x7003d4, 0x5}, - {1, 0x7003d5, 0x16}, - {1, 0x7003d4, 0x6}, - {1, 0x7003d5, 0x24}, - {1, 0x7003d4, 0x7}, - {1, 0x7003d5, 0xf5}, - {1, 0x7003d4, 0x8}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x9}, - {1, 0x7003d5, 0x60}, - {1, 0x7003d4, 0xa}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0xb}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0xc}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0xd}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0xe}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0xf}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x10}, - {1, 0x7003d5, 0x3}, - {1, 0x7003d4, 0x11}, - {1, 0x7003d5, 0x9}, - {1, 0x7003d4, 0x12}, - {1, 0x7003d5, 0xff}, - {1, 0x7003d4, 0x13}, - {1, 0x7003d5, 0x80}, - {1, 0x7003d4, 0x14}, - {1, 0x7003d5, 0x40}, - {1, 0x7003d4, 0x15}, - {1, 0x7003d5, 0xff}, - {1, 0x7003d4, 0x16}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x17}, - {1, 0x7003d5, 0xe3}, - {1, 0x7003d4, 0x18}, - {1, 0x7003d5, 0xff}, - {1, 0x7003d4, 0x30}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x31}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x32}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x33}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x34}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x35}, - {1, 0x7003d5, 0x80}, - {1, 0x7003d4, 0x36}, - {1, 0x7003d5, 0x2}, - {1, 0x7003d4, 0x37}, - {1, 0x7003d5, 0x20}, - {1, 0x7003d4, 0x38}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x39}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x3a}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x3b}, - {1, 0x7003d5, 0x40}, - {1, 0x7003d4, 0x3c}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x3d}, - {1, 0x7003d5, 0xff}, - {1, 0x7003d4, 0x3e}, - {1, 0x7003d5, 0x46}, - {1, 0x7003d4, 0x3f}, - {1, 0x7003d5, 0x91}, - {1, 0x7003d4, 0x40}, - {1, 0x7003d5, 0xa3}, - {1, 0x7003d4, 0x41}, - {1, 0x7003d5, 0x7f}, - {1, 0x7003d4, 0x42}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x43}, - {1, 0x7003d5, 0x86}, - {1, 0x7003d4, 0x44}, - {1, 0x7003d5, 0x15}, - {1, 0x7003d4, 0x45}, - {1, 0x7003d5, 0x24}, - {1, 0x7003d4, 0x46}, - {1, 0x7003d5, 0xff}, - {1, 0x7003d4, 0x47}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x48}, - {1, 0x7003d5, 0x1}, - {1, 0x7003d4, 0x49}, - {1, 0x7003d5, 0x7}, - {1, 0x7003d4, 0x4a}, - {1, 0x7003d5, 0xe5}, - {1, 0x7003d4, 0x4b}, - {1, 0x7003d5, 0x20}, - {1, 0x7003d4, 0x4c}, - {1, 0x7003d5, 0x7f}, - {1, 0x7003d4, 0x4d}, - {1, 0x7003d5, 0x57}, - {1, 0x7003d4, 0x90}, - {1, 0x7003d5, 0x55}, - {1, 0x7003d4, 0x91}, - {1, 0x7003d5, 0xd5}, - {1, 0x7003d4, 0x92}, - {1, 0x7003d5, 0x5d}, - {1, 0x7003d4, 0x93}, - {1, 0x7003d5, 0xdd}, - {1, 0x7003d4, 0x94}, - {1, 0x7003d5, 0x86}, - {1, 0x7003d4, 0x95}, - {1, 0x7003d5, 0x17}, - {1, 0x7003d4, 0x96}, - {1, 0x7003d5, 0x8e}, - {1, 0x7003d4, 0x97}, - {1, 0x7003d5, 0xaa}, - {1, 0x7003d4, 0x98}, - {1, 0x7003d5, 0x8a}, - {1, 0x7003d4, 0x99}, - {1, 0x7003d5, 0xa3}, - {1, 0x7003d4, 0x9a}, - {1, 0x7003d5, 0xde}, - {1, 0x7003d4, 0x9b}, - {1, 0x7003d5, 0xab}, - {1, 0x7003d4, 0x9c}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x9d}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x9e}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0x9f}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0xa0}, - {1, 0x7003d5, 0x2}, - {1, 0x7003d4, 0xa1}, - {1, 0x7003d5, 0x2}, - {1, 0x7003d4, 0xa2}, - {1, 0x7003d5, 0x2}, - {1, 0x7003d4, 0xa3}, - {1, 0x7003d5, 0x15}, - {1, 0x7003d4, 0xa4}, - {1, 0x7003d5, 0x2}, - {1, 0x7003d4, 0xa5}, - {1, 0x7003d5, 0x6}, - {1, 0x7003d4, 0xa6}, - {1, 0x7003d5, 0x0}, - {1, 0x7003d4, 0xa7}, - {1, 0x7003d5, 0x0}, - {1, 0x7003c2, 0x67}, - {4, 0x40c00c, 0x0}, - {4, 0x40c040, 0x0}, - {4, 0x40c000, 0x20000}, - {4, 0x40c010, 0x1020100}, - {1, 0x7003c4, 0x16}, - {-1, 0x7003c5, 0x17} -}; +static grub_uint8_t sm712_sr_seq1[] = + { 0xc8, 0x40, 0x14, 0x60, 0x0, 0xa, 0x92, 0x0, + 0x51, 0x00, 0x01, 0x00, 0x0, 0x0, 0x00, 0x0, + 0xc4, 0x30, 0x02, 0x00, 0x1 }; + +static grub_uint8_t sm712_sr_seq2[] = + { 0x28, 0x03, 0x24, 0x09, 0xc0, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x00, 0x00, 0x03, 0xff, + 0x00, 0xfc, 0x00, 0x00, 0x20, 0x18, 0x00, 0xfc, + 0x20, 0x0c, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3a, + 0x06, 0x68, 0xa7, 0x7f, 0x83, 0x24, 0xff, 0x03, + 0x00, 0x60, 0x59, 0x3a, 0x3a, 0x00, 0x00, 0x3a, + 0x01, 0x80 }; diff --git a/include/grub/bsdlabel.h b/include/grub/bsdlabel.h index d88b25353..636bd41a1 100644 --- a/include/grub/bsdlabel.h +++ b/include/grub/bsdlabel.h @@ -63,6 +63,8 @@ #define GRUB_PC_PARTITION_OPENBSD_TYPE_NTFS 18 #define GRUB_PC_PARTITION_OPENBSD_TYPE_RAID 19 +#define GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION 2 + /* The BSD partition entry. */ struct grub_partition_bsd_entry { diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h index f6b88b17e..e9038c916 100644 --- a/include/grub/emu/misc.h +++ b/include/grub/emu/misc.h @@ -1,8 +1,27 @@ +/* + * 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_EMU_MISC_H #define GRUB_EMU_MISC_H 1 #include #include +#include #ifdef __CYGWIN__ # include @@ -27,12 +46,16 @@ void grub_emu_init (void); void grub_init_all (void); void grub_fini_all (void); -char *grub_make_system_path_relative_to_its_root (const char *path); +void grub_find_zpool_from_dir (const char *dir, + char **poolname, char **poolfs); -void * EXPORT_FUNC(xmalloc) (grub_size_t size); -void * EXPORT_FUNC(xrealloc) (void *ptr, grub_size_t size); -char * EXPORT_FUNC(xstrdup) (const char *str); -char * EXPORT_FUNC(xasprintf) (const char *fmt, ...); +char *grub_make_system_path_relative_to_its_root (const char *path) + __attribute__ ((warn_unused_result)); + +void * EXPORT_FUNC(xmalloc) (grub_size_t size) __attribute__ ((warn_unused_result)); +void * EXPORT_FUNC(xrealloc) (void *ptr, grub_size_t size) __attribute__ ((warn_unused_result)); +char * EXPORT_FUNC(xstrdup) (const char *str) __attribute__ ((warn_unused_result)); +char * EXPORT_FUNC(xasprintf) (const char *fmt, ...) __attribute__ ((warn_unused_result)); void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...); void EXPORT_FUNC(grub_util_info) (const char *fmt, ...); @@ -46,11 +69,12 @@ int EXPORT_FUNC(vasprintf) (char **buf, const char *fmt, va_list ap); int EXPORT_FUNC(asprintf) (char **buf, const char *fmt, ...); #endif -char * EXPORT_FUNC(xasprintf) (const char *fmt, ...); extern char * canonicalize_file_name (const char *path); #ifdef HAVE_DEVICE_MAPPER int grub_device_mapper_supported (void); #endif +libzfs_handle_t *grub_get_libzfs_handle (void); + #endif /* GRUB_EMU_MISC_H */ diff --git a/include/grub/misc.h b/include/grub/misc.h index 056bd1a65..8bf8c82b4 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -231,10 +231,10 @@ grub_strtol (const char *str, char **end, int base) } } -char *EXPORT_FUNC(grub_strdup) (const char *s); -char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n); +char *EXPORT_FUNC(grub_strdup) (const char *s) __attribute__ ((warn_unused_result)); +char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n) __attribute__ ((warn_unused_result)); void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n); -grub_size_t EXPORT_FUNC(grub_strlen) (const char *s); +grub_size_t EXPORT_FUNC(grub_strlen) (const char *s) __attribute__ ((warn_unused_result)); int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); int EXPORT_FUNC(grub_printf_) (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); @@ -261,8 +261,8 @@ int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) int EXPORT_FUNC(grub_vsnprintf) (char *str, grub_size_t n, const char *fmt, va_list args); char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...) - __attribute__ ((format (printf, 1, 2))); -char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args); + __attribute__ ((format (printf, 1, 2))) __attribute__ ((warn_unused_result)); +char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) __attribute__ ((warn_unused_result)); void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn)); grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, @@ -288,6 +288,15 @@ grub_abs (int x) return (unsigned int) x; } +static inline long +grub_min (long x, long y) +{ + if (x < y) + return x; + else + return y; +} + static inline long grub_max (long x, long y) { diff --git a/include/grub/normal.h b/include/grub/normal.h index a33e42e61..2a0298bc6 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -73,7 +73,7 @@ grub_err_t grub_normal_print_device_info (const char *name); /* Defined in `color.c'. */ char *grub_env_write_color_normal (struct grub_env_var *var, const char *val); char *grub_env_write_color_highlight (struct grub_env_var *var, const char *val); -void grub_parse_color_name_pair (grub_uint8_t *ret, const char *name); +int grub_parse_color_name_pair (grub_uint8_t *ret, const char *name); /* Defined in `menu_text.c'. */ void grub_wait_after_message (void); diff --git a/include/grub/partition.h b/include/grub/partition.h index a23e94e07..20705c527 100644 --- a/include/grub/partition.h +++ b/include/grub/partition.h @@ -48,7 +48,7 @@ struct grub_partition /* The partition number. */ int number; - /* The start sector. */ + /* The start sector (relative to parent). */ grub_disk_addr_t start; /* The length in sector units. */ @@ -60,7 +60,7 @@ struct grub_partition /* The index of this partition in the partition table. */ int index; - /* Parent partition map. */ + /* Parent partition (physically contains this partition). */ struct grub_partition *parent; /* The type partition map. */ diff --git a/include/grub/pci.h b/include/grub/pci.h index e6d6488f0..f34e3d907 100644 --- a/include/grub/pci.h +++ b/include/grub/pci.h @@ -80,6 +80,7 @@ #define GRUB_PCI_STATUS_DEVSEL_TIMING_SHIFT 9 #define GRUB_PCI_STATUS_DEVSEL_TIMING_MASK 0x0600 +#define GRUB_PCI_CLASS_SUBCLASS_VGA 0x0300 #ifndef ASM_FILE typedef grub_uint32_t grub_pci_id_t; diff --git a/include/grub/raid.h b/include/grub/raid.h index 8fa4c3814..711a7f79c 100644 --- a/include/grub/raid.h +++ b/include/grub/raid.h @@ -1,7 +1,7 @@ /* raid.h - On disk structures for RAID. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,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 @@ -51,6 +51,8 @@ struct grub_raid_array char *name; /* That will be "md". */ unsigned int nr_devs; /* The number of devices we've found so far. */ grub_disk_t device[GRUB_RAID_MAX_DEVICES]; /* Array of total_devs devices. */ + grub_disk_addr_t start_sector[GRUB_RAID_MAX_DEVICES]; + /* Start of each device, in 512 byte sectors. */ struct grub_raid_array *next; }; @@ -58,7 +60,8 @@ struct grub_raid { const char *name; - grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array); + grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array, + grub_disk_addr_t *start_sector); struct grub_raid *next; }; diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 7d6129243..77e807360 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -23,6 +23,7 @@ #include #include #include +#include struct grub_script_mem; @@ -63,6 +64,13 @@ struct grub_script_arg struct grub_script_arg *next; }; +/* An argument vector. */ +struct grub_script_argv +{ + unsigned argc; + char **args; +}; + /* A complete argument. It consists of a list of one or more `struct grub_script_arg's. */ struct grub_script_arglist @@ -82,15 +90,6 @@ struct grub_script_cmdline struct grub_script_arglist *arglist; }; -/* A block of commands, this can be used to group commands. */ -struct grub_script_cmdblock -{ - struct grub_script_cmd cmd; - - /* A chain of commands. */ - struct grub_script_cmd *cmdlist; -}; - /* An if statement. */ struct grub_script_cmdif { @@ -224,6 +223,14 @@ struct grub_parser_param struct grub_lexer_param *lexerstate; }; +void grub_script_init (void); +void grub_script_fini (void); + +void grub_script_argv_free (struct grub_script_argv *argv); +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); + struct grub_script_arglist * grub_script_create_arglist (struct grub_parser_param *state); @@ -234,8 +241,6 @@ grub_script_add_arglist (struct grub_parser_param *state, struct grub_script_cmd * grub_script_create_cmdline (struct grub_parser_param *state, struct grub_script_arglist *arglist); -struct grub_script_cmd * -grub_script_create_cmdblock (struct grub_parser_param *state); struct grub_script_cmd * grub_script_create_cmdif (struct grub_parser_param *state, @@ -262,9 +267,9 @@ grub_script_create_cmdmenu (struct grub_parser_param *state, int options); struct grub_script_cmd * -grub_script_add_cmd (struct grub_parser_param *state, - struct grub_script_cmdblock *cmdblock, - struct grub_script_cmd *cmd); +grub_script_append_cmd (struct grub_parser_param *state, + struct grub_script_cmd *list, + struct grub_script_cmd *last); struct grub_script_arg * grub_script_arg_add (struct grub_parser_param *state, struct grub_script_arg *arg, @@ -301,7 +306,7 @@ void grub_script_yyerror (struct grub_parser_param *, char const *); /* Commands to execute, don't use these directly. */ grub_err_t grub_script_execute_cmdline (struct grub_script_cmd *cmd); -grub_err_t grub_script_execute_cmdblock (struct grub_script_cmd *cmd); +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); @@ -310,6 +315,12 @@ 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); +/* Break command for loops. */ +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[]); + /* This variable points to the parsed command. This is used to communicate with the bison code. */ extern struct grub_script_cmd *grub_script_parsed; @@ -344,8 +355,9 @@ grub_script_function_t grub_script_function_create (struct grub_script_arg *func struct grub_script *cmd); void grub_script_function_remove (const char *name); grub_script_function_t grub_script_function_find (char *functionname); -int grub_script_function_call (grub_script_function_t func, - int argc, char **args); + +grub_err_t grub_script_function_call (grub_script_function_t func, + int argc, char **args); char ** grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *count); diff --git a/include/grub/usb.h b/include/grub/usb.h index 64dc78d61..3c17318fc 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -104,7 +104,7 @@ struct grub_usb_controller_dev grub_err_t (*portstatus) (grub_usb_controller_t dev, unsigned int port, unsigned int enable); - grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port); + grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port, int *changed); /* The next host controller. */ struct grub_usb_controller_dev *next; @@ -125,6 +125,13 @@ struct grub_usb_interface struct grub_usb_desc_if *descif; struct grub_usb_desc_endp *descendp; + + /* A driver is handling this interface. Do we need to support multiple drivers + for single interface? + */ + int attached; + + void (*detach_hook) (struct grub_usb_device *dev, int config, int interface); }; struct grub_usb_configuration @@ -207,4 +214,21 @@ grub_usb_get_config_interface (struct grub_usb_desc_config *config) return interf; } +typedef int (*grub_usb_attach_hook_class) (grub_usb_device_t usbdev, + int configno, int interfno); + +struct grub_usb_attach_desc +{ + struct grub_usb_attach_desc *next; + int class; + grub_usb_attach_hook_class hook; +}; + +void grub_usb_register_attach_hook_class (struct grub_usb_attach_desc *desc); +void grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc); + +void grub_usb_poll_devices (void); + +void grub_usb_device_attach (grub_usb_device_t dev); + #endif /* GRUB_USB_H */ diff --git a/include/grub/usbtrans.h b/include/grub/usbtrans.h index 8f49c246f..e68698c1d 100644 --- a/include/grub/usbtrans.h +++ b/include/grub/usbtrans.h @@ -93,10 +93,12 @@ typedef struct grub_usb_transfer *grub_usb_transfer_t; #define GRUB_USB_HUB_FEATURE_PORT_RESET 0x04 #define GRUB_USB_HUB_FEATURE_PORT_POWER 0x08 +#define GRUB_USB_HUB_FEATURE_C_CONNECTED 0x10 #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) struct grub_usb_packet_setup diff --git a/include/grub/util/libnvpair.h b/include/grub/util/libnvpair.h new file mode 100644 index 000000000..26f7e9d0f --- /dev/null +++ b/include/grub/util/libnvpair.h @@ -0,0 +1,39 @@ +/* + * 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_LIBNVPAIR_UTIL_HEADER +#define GRUB_LIBNVPAIR_UTIL_HEADER 1 + +#include + +#ifdef HAVE_LIBNVPAIR_H +#include +#else /* ! HAVE_LIBNVPAIR_H */ + +#include /* FILE */ + +typedef void nvlist_t; + +int nvlist_lookup_string (nvlist_t *, const char *, char **); +int nvlist_lookup_nvlist (nvlist_t *, const char *, nvlist_t **); +int nvlist_lookup_nvlist_array (nvlist_t *, const char *, nvlist_t ***, unsigned int *); +void nvlist_print (FILE *, nvlist_t *); + +#endif /* ! HAVE_LIBNVPAIR_H */ + +#endif diff --git a/include/grub/util/libzfs.h b/include/grub/util/libzfs.h new file mode 100644 index 000000000..0500f70d7 --- /dev/null +++ b/include/grub/util/libzfs.h @@ -0,0 +1,45 @@ +/* + * 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_LIBZFS_UTIL_HEADER +#define GRUB_LIBZFS_UTIL_HEADER 1 + +#include + +#ifdef HAVE_LIBZFS_H +#include +#else /* ! HAVE_LIBZFS_H */ + +#include + +typedef void libzfs_handle_t; +typedef void zpool_handle_t; + +extern libzfs_handle_t *libzfs_init (void); +extern void libzfs_fini (libzfs_handle_t *); + +extern zpool_handle_t *zpool_open (libzfs_handle_t *, const char *); +extern void zpool_close (zpool_handle_t *); + +extern int zpool_get_physpath (zpool_handle_t *, const char *); + +extern nvlist_t *zpool_get_config (zpool_handle_t *, nvlist_t **); + +#endif /* ! HAVE_LIBZFS_H */ + +#endif diff --git a/include/grub/vga.h b/include/grub/vga.h index d4a1523a7..7f112d83a 100644 --- a/include/grub/vga.h +++ b/include/grub/vga.h @@ -19,9 +19,13 @@ #ifndef GRUB_VGA_HEADER #define GRUB_VGA_HEADER 1 +#include + enum { GRUB_VGA_IO_ARX = 0x3c0, + GRUB_VGA_IO_ARX_READ = 0x3c1, + GRUB_VGA_IO_MISC_WRITE = 0x3c2, GRUB_VGA_IO_SR_INDEX = 0x3c4, GRUB_VGA_IO_SR_DATA = 0x3c5, GRUB_VGA_IO_PIXEL_MASK = 0x3c6, @@ -39,8 +43,15 @@ enum enum { - GRUB_VGA_CR_WIDTH = 0x01, + GRUB_VGA_CR_HTOTAL = 0x00, + GRUB_VGA_CR_HORIZ_END = 0x01, + GRUB_VGA_CR_HBLANK_START = 0x02, + GRUB_VGA_CR_HBLANK_END = 0x03, + GRUB_VGA_CR_HORIZ_SYNC_PULSE_START = 0x04, + GRUB_VGA_CR_HORIZ_SYNC_PULSE_END = 0x05, + GRUB_VGA_CR_VERT_TOTAL = 0x06, GRUB_VGA_CR_OVERFLOW = 0x07, + GRUB_VGA_CR_BYTE_PANNING = 0x08, GRUB_VGA_CR_CELL_HEIGHT = 0x09, GRUB_VGA_CR_CURSOR_START = 0x0a, GRUB_VGA_CR_CURSOR_END = 0x0b, @@ -48,14 +59,71 @@ enum GRUB_VGA_CR_START_ADDR_LOW_REGISTER = 0x0d, GRUB_VGA_CR_CURSOR_ADDR_HIGH = 0x0e, GRUB_VGA_CR_CURSOR_ADDR_LOW = 0x0f, + GRUB_VGA_CR_VSYNC_START = 0x10, GRUB_VGA_CR_VSYNC_END = 0x11, - GRUB_VGA_CR_HEIGHT = 0x12, + GRUB_VGA_CR_VDISPLAY_END = 0x12, GRUB_VGA_CR_PITCH = 0x13, + GRUB_VGA_CR_UNDERLINE_LOCATION = 0x14, + GRUB_VGA_CR_VERTICAL_BLANK_START = 0x15, + GRUB_VGA_CR_VERTICAL_BLANK_END = 0x16, GRUB_VGA_CR_MODE = 0x17, GRUB_VGA_CR_LINE_COMPARE = 0x18, }; +enum + { + GRUB_VGA_CR_BYTE_PANNING_NORMAL = 0 + }; + +enum + { + GRUB_VGA_CR_UNDERLINE_LOCATION_DWORD_MODE = 0x40 + }; + +enum + { + GRUB_VGA_IO_MISC_COLOR = 0x01, + GRUB_VGA_IO_MISC_ENABLE_VRAM_ACCESS = 0x02, + GRUB_VGA_IO_MISC_EXTERNAL_CLOCK_0 = 0x08, + GRUB_VGA_IO_MISC_28MHZ = 0x04, + GRUB_VGA_IO_MISC_UPPER_64K = 0x20, + GRUB_VGA_IO_MISC_NEGATIVE_HORIZ_POLARITY = 0x40, + GRUB_VGA_IO_MISC_NEGATIVE_VERT_POLARITY = 0x80, + }; + +enum + { + GRUB_VGA_ARX_MODE = 0x10, + GRUB_VGA_ARX_OVERSCAN = 0x11, + GRUB_VGA_ARX_COLOR_PLANE_ENABLE = 0x12, + GRUB_VGA_ARX_HORIZONTAL_PANNING = 0x13, + GRUB_VGA_ARX_COLOR_SELECT = 0x14 + }; + +enum + { + GRUB_VGA_ARX_MODE_TEXT = 0x00, + GRUB_VGA_ARX_MODE_GRAPHICS = 0x01, + GRUB_VGA_ARX_MODE_ENABLE_256COLOR = 0x40 + }; + #define GRUB_VGA_CR_WIDTH_DIVISOR 8 + +#define GRUB_VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT 7 +#define GRUB_VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK 0x02 +#define GRUB_VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT 3 +#define GRUB_VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK 0x40 + +#define GRUB_VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT 8 +#define GRUB_VGA_CR_OVERFLOW_VERT_TOTAL1_MASK 0x01 +#define GRUB_VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT 4 +#define GRUB_VGA_CR_OVERFLOW_VERT_TOTAL2_MASK 0x20 + +#define GRUB_VGA_CR_OVERFLOW_VSYNC_START1_SHIFT 6 +#define GRUB_VGA_CR_OVERFLOW_VSYNC_START1_MASK 0x04 +#define GRUB_VGA_CR_OVERFLOW_VSYNC_START2_SHIFT 2 +#define GRUB_VGA_CR_OVERFLOW_VSYNC_START2_MASK 0x80 + #define GRUB_VGA_CR_OVERFLOW_HEIGHT1_SHIFT 7 #define GRUB_VGA_CR_OVERFLOW_HEIGHT1_MASK 0x02 #define GRUB_VGA_CR_OVERFLOW_HEIGHT2_SHIFT 3 @@ -65,7 +133,9 @@ enum #define GRUB_VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK 0x40 #define GRUB_VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT 3 - +#define GRUB_VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK 0x20 +#define GRUB_VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT 4 +#define GRUB_VGA_CR_CELL_HEIGHT_DOUBLE_SCAN 0x80 enum { GRUB_VGA_CR_CURSOR_START_DISABLE = (1 << 5) @@ -77,17 +147,26 @@ enum { GRUB_VGA_CR_MODE_NO_CGA = 0x01, GRUB_VGA_CR_MODE_NO_HERCULES = 0x02, + GRUB_VGA_CR_MODE_ADDRESS_WRAP = 0x20, GRUB_VGA_CR_MODE_BYTE_MODE = 0x40, GRUB_VGA_CR_MODE_TIMING_ENABLE = 0x80 }; enum { + GRUB_VGA_SR_RESET = 0, GRUB_VGA_SR_CLOCKING_MODE = 1, GRUB_VGA_SR_MAP_MASK_REGISTER = 2, + GRUB_VGA_SR_CHAR_MAP_SELECT = 3, GRUB_VGA_SR_MEMORY_MODE = 4, }; +enum + { + GRUB_VGA_SR_RESET_ASYNC = 1, + GRUB_VGA_SR_RESET_SYNC = 2 + }; + enum { GRUB_VGA_SR_CLOCKING_MODE_8_DOT_CLOCK = 1 @@ -96,19 +175,33 @@ enum enum { GRUB_VGA_SR_MEMORY_MODE_NORMAL = 0, - GRUB_VGA_SR_MEMORY_MODE_CHAIN4 = 8 + GRUB_VGA_SR_MEMORY_MODE_EXTERNAL_VIDEO_MEMORY = 2, + GRUB_VGA_SR_MEMORY_MODE_SEQUENTIAL_ADDRESSING = 4, + GRUB_VGA_SR_MEMORY_MODE_CHAIN4 = 8, }; enum { + GRUB_VGA_GR_SET_RESET_PLANE = 0, + GRUB_VGA_GR_SET_RESET_PLANE_ENABLE = 1, + GRUB_VGA_GR_COLOR_COMPARE = 2, GRUB_VGA_GR_DATA_ROTATE = 3, GRUB_VGA_GR_READ_MAP_REGISTER = 4, GRUB_VGA_GR_MODE = 5, GRUB_VGA_GR_GR6 = 6, + GRUB_VGA_GR_COLOR_COMPARE_DISABLE = 7, GRUB_VGA_GR_BITMASK = 8, GRUB_VGA_GR_MAX }; +#define GRUB_VGA_ALL_PLANES 0xf +#define GRUB_VGA_NO_PLANES 0x0 + +enum + { + GRUB_VGA_GR_DATA_ROTATE_NOP = 0 + }; + enum { GRUB_VGA_TEXT_TEXT_PLANE = 0, @@ -119,6 +212,7 @@ enum enum { GRUB_VGA_GR_GR6_GRAPHICS_MODE = 1, + GRUB_VGA_GR_GR6_MMAP_A0 = (1 << 2), GRUB_VGA_GR_GR6_MMAP_CGA = (3 << 2) }; @@ -126,70 +220,152 @@ enum { GRUB_VGA_GR_MODE_READ_MODE1 = 0x08, GRUB_VGA_GR_MODE_ODD_EVEN = 0x10, + GRUB_VGA_GR_MODE_ODD_EVEN_SHIFT = 0x20, GRUB_VGA_GR_MODE_256_COLOR = 0x40 }; static inline void grub_vga_gr_write (grub_uint8_t val, grub_uint8_t addr) { - grub_outb (addr, GRUB_VGA_IO_GR_INDEX); - grub_outb (val, GRUB_VGA_IO_GR_DATA); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_GR_INDEX); + grub_outb (val, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_GR_DATA); } static inline grub_uint8_t grub_vga_gr_read (grub_uint8_t addr) { - grub_outb (addr, GRUB_VGA_IO_GR_INDEX); - return grub_inb (GRUB_VGA_IO_GR_DATA); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_GR_INDEX); + return grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_GR_DATA); } static inline void grub_vga_cr_write (grub_uint8_t val, grub_uint8_t addr) { - grub_outb (addr, GRUB_VGA_IO_CR_INDEX); - grub_outb (val, GRUB_VGA_IO_CR_DATA); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_CR_INDEX); + grub_outb (val, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_CR_DATA); } static inline grub_uint8_t grub_vga_cr_read (grub_uint8_t addr) { - grub_outb (addr, GRUB_VGA_IO_CR_INDEX); - return grub_inb (GRUB_VGA_IO_CR_DATA); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_CR_INDEX); + return grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_CR_DATA); } static inline void grub_vga_sr_write (grub_uint8_t val, grub_uint8_t addr) { - grub_outb (addr, GRUB_VGA_IO_SR_INDEX); - grub_outb (val, GRUB_VGA_IO_SR_DATA); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_SR_INDEX); + grub_outb (val, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_SR_DATA); } static inline grub_uint8_t grub_vga_sr_read (grub_uint8_t addr) { - grub_outb (addr, GRUB_VGA_IO_SR_INDEX); - return grub_inb (GRUB_VGA_IO_SR_DATA); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_SR_INDEX); + return grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_SR_DATA); } static inline void grub_vga_palette_read (grub_uint8_t addr, grub_uint8_t *r, grub_uint8_t *g, grub_uint8_t *b) { - grub_outb (addr, GRUB_VGA_IO_PALLETTE_READ_INDEX); - *r = grub_inb (GRUB_VGA_IO_PALLETTE_DATA); - *g = grub_inb (GRUB_VGA_IO_PALLETTE_DATA); - *b = grub_inb (GRUB_VGA_IO_PALLETTE_DATA); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_PALLETTE_READ_INDEX); + *r = grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_PALLETTE_DATA); + *g = grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_PALLETTE_DATA); + *b = grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_PALLETTE_DATA); } static inline void grub_vga_palette_write (grub_uint8_t addr, grub_uint8_t r, grub_uint8_t g, grub_uint8_t b) { - grub_outb (addr, GRUB_VGA_IO_PALLETTE_WRITE_INDEX); - grub_outb (r, GRUB_VGA_IO_PALLETTE_DATA); - grub_outb (g, GRUB_VGA_IO_PALLETTE_DATA); - grub_outb (b, GRUB_VGA_IO_PALLETTE_DATA); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_PALLETTE_WRITE_INDEX); + grub_outb (r, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_PALLETTE_DATA); + grub_outb (g, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_PALLETTE_DATA); + grub_outb (b, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_PALLETTE_DATA); } +static inline void +grub_vga_write_arx (grub_uint8_t val, grub_uint8_t addr) +{ + grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_INPUT_STATUS1_REGISTER); + grub_outb (addr, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX); + grub_inb (GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX_READ); + grub_outb (val, GRUB_MACHINE_PCI_IO_BASE + GRUB_VGA_IO_ARX); +} + +struct grub_video_hw_config +{ + unsigned vertical_total; + unsigned vertical_blank_start; + unsigned vertical_blank_end; + unsigned vertical_sync_start; + unsigned vertical_sync_end; + unsigned line_compare; + unsigned vdisplay_end; + unsigned pitch; + unsigned horizontal_total; + unsigned horizontal_blank_start; + unsigned horizontal_blank_end; + unsigned horizontal_sync_pulse_start; + unsigned horizontal_sync_pulse_end; + unsigned horizontal_end; +}; + +static inline void +grub_vga_set_geometry (struct grub_video_hw_config *config, + void (*cr_write) (grub_uint8_t val, grub_uint8_t addr)) +{ + unsigned vertical_total = config->vertical_total - 2; + unsigned vertical_blank_start = config->vertical_blank_start - 1; + unsigned vdisplay_end = config->vdisplay_end - 1; + grub_uint8_t overflow, cell_height_reg; + + /* Disable CR0-7 write protection. */ + cr_write (0, GRUB_VGA_CR_VSYNC_END); + + overflow = ((vertical_total >> GRUB_VGA_CR_OVERFLOW_VERT_TOTAL1_SHIFT) + & GRUB_VGA_CR_OVERFLOW_VERT_TOTAL1_MASK) + | ((vertical_total >> GRUB_VGA_CR_OVERFLOW_VERT_TOTAL2_SHIFT) + & GRUB_VGA_CR_OVERFLOW_VERT_TOTAL2_MASK) + | ((config->vertical_sync_start >> GRUB_VGA_CR_OVERFLOW_VSYNC_START2_SHIFT) + & GRUB_VGA_CR_OVERFLOW_VSYNC_START2_MASK) + | ((config->vertical_sync_start >> GRUB_VGA_CR_OVERFLOW_VSYNC_START1_SHIFT) + & GRUB_VGA_CR_OVERFLOW_VSYNC_START1_MASK) + | ((vdisplay_end >> GRUB_VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_SHIFT) + & GRUB_VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END1_MASK) + | ((vdisplay_end >> GRUB_VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_SHIFT) + & GRUB_VGA_CR_OVERFLOW_VERT_DISPLAY_ENABLE_END2_MASK) + | ((config->vertical_sync_start >> GRUB_VGA_CR_OVERFLOW_VSYNC_START1_SHIFT) + & GRUB_VGA_CR_OVERFLOW_VSYNC_START1_MASK) + | ((config->line_compare >> GRUB_VGA_CR_OVERFLOW_LINE_COMPARE_SHIFT) + & GRUB_VGA_CR_OVERFLOW_LINE_COMPARE_MASK); + + cell_height_reg = ((vertical_blank_start + >> GRUB_VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_SHIFT) + & GRUB_VGA_CR_CELL_HEIGHT_VERTICAL_BLANK_MASK) + | ((config->line_compare >> GRUB_VGA_CR_CELL_HEIGHT_LINE_COMPARE_SHIFT) + & GRUB_VGA_CR_CELL_HEIGHT_LINE_COMPARE_MASK); + + cr_write (config->horizontal_total - 1, GRUB_VGA_CR_HTOTAL); + cr_write (config->horizontal_end - 1, GRUB_VGA_CR_HORIZ_END); + cr_write (config->horizontal_blank_start - 1, GRUB_VGA_CR_HBLANK_START); + cr_write (config->horizontal_blank_end, GRUB_VGA_CR_HBLANK_END); + cr_write (config->horizontal_sync_pulse_start, + GRUB_VGA_CR_HORIZ_SYNC_PULSE_START); + cr_write (config->horizontal_sync_pulse_end, + GRUB_VGA_CR_HORIZ_SYNC_PULSE_END); + cr_write (vertical_total & 0xff, GRUB_VGA_CR_VERT_TOTAL); + cr_write (overflow, GRUB_VGA_CR_OVERFLOW); + cr_write (cell_height_reg, GRUB_VGA_CR_CELL_HEIGHT); + cr_write (config->vertical_sync_start & 0xff, GRUB_VGA_CR_VSYNC_START); + cr_write (config->vertical_sync_end & 0x0f, GRUB_VGA_CR_VSYNC_END); + cr_write (vdisplay_end & 0xff, GRUB_VGA_CR_VDISPLAY_END); + cr_write (config->pitch & 0xff, GRUB_VGA_CR_PITCH); + cr_write (vertical_blank_start & 0xff, GRUB_VGA_CR_VERTICAL_BLANK_START); + cr_write (config->vertical_blank_end & 0xff, GRUB_VGA_CR_VERTICAL_BLANK_END); + cr_write (config->line_compare & 0xff, GRUB_VGA_CR_LINE_COMPARE); +} #endif diff --git a/modules.def b/modules.def index c7574e928..50b5ac0d6 100644 --- a/modules.def +++ b/modules.def @@ -90,6 +90,7 @@ library = { source = grub-core/script/lexer.c; source = grub-core/script/main.c; source = grub-core/script/script.c; + source = grub-core/script/argv.c; nodist = grub_script.yy.h; nodist = grub_script.tab.h; @@ -443,6 +444,30 @@ script = { source = tests/grub_script_comments.in; }; +script = { + testcase; + name = grub_script_functions; + source = tests/grub_script_functions.in; +}; + +script = { + testcase; + name = grub_script_break; + source = tests/grub_script_break.in; +}; + +script = { + testcase; + name = grub_script_continue; + source = tests/grub_script_continue.in; +}; + +script = { + testcase; + name = grub_script_shift; + source = tests/grub_script_shift.in; +}; + program = { testcase; name = example_unit_test; diff --git a/tests/grub_script_break.in b/tests/grub_script_break.in new file mode 100644 index 000000000..bf265e8b3 --- /dev/null +++ b/tests/grub_script_break.in @@ -0,0 +1,86 @@ +#! @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 . + +# break without any arguments +for i in 1 2 3 4 5 6 7 8 9 10 +do + echo $i + if test "$i" = 5 + then + break + fi +done + +# break with one +for i in 1 2 3 4 5 6 7 8 9 10 +do + echo $i + if test "$i" = 5 + then + break 1 + fi +done + +# break with loop count +for i in 1 2 3 4 5 +do + for j in a b c d e f + do + echo "$i $j" + if test "$i" = 3 + then + if test "$j" = d + then + break 2 + fi + fi + done +done + +# break into middle loop +for i in 1 2 3 4 5 +do + for j in a b c d e f + do + echo "$i $j" + if test "$i" = 3 + then + if test "$j" = d + then + break 1 + fi + fi + done +done + +# while and until loops +a= +while test "$a" != "aaaaaaa" +do + a="a$a" + for i in 1 2 3 4 + do + b= + until test "$b" = "bbbbb" + do + b="b$b" + echo "$a $i $b" + if test "$i" = 3; then echo "break 2"; break 2; fi + done + done +done + diff --git a/tests/grub_script_continue.in b/tests/grub_script_continue.in new file mode 100644 index 000000000..4c28ce404 --- /dev/null +++ b/tests/grub_script_continue.in @@ -0,0 +1,86 @@ +#! @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 . + +# continue without any arguments +for i in 1 2 3 4 5 6 7 8 9 10 +do + if test "$i" = 5 + then + continue + fi + echo $i +done + +# continue with one +for i in 1 2 3 4 5 6 7 8 9 10 +do + if test "$i" = 5 + then + continue 1 + fi + echo $i +done + +# continue with loop count +for i in 1 2 3 4 5 +do + for j in a b c d e f + do + if test "$i" = 3 + then + if test "$j" = d + then + continue 2 + fi + echo "$i $j" + fi + done +done + +# continue into middle loop +for i in 1 2 3 4 5 +do + for j in a b c d e f + do + if test "$i" = 3 + then + if test "$j" = d + then + continue 1 + fi + echo "$i $j" + fi + done +done + +# while and until loops +a= +while test "$a" != "aaaaaaa" +do + a="a$a" + for i in 1 2 3 4 + do + b= + until test "$b" = "bbbbb" + do + b="b$b" + if test "$i" = 3; then echo "continue 2"; continue 2; fi + echo "$a $i $b" + done + done +done + diff --git a/tests/grub_script_echo1.in b/tests/grub_script_echo1.in index 048907a76..554dd68ed 100644 --- a/tests/grub_script_echo1.in +++ b/tests/grub_script_echo1.in @@ -16,6 +16,33 @@ # You should have received a copy of the GNU General Public License # along with GRUB. If not, see . +# simple arguments +echo one two three +echo "one two three" +echo 'one two three' + +# empty arguments +echo a "" b +echo a '' b + +echo a $foo b +echo a ${foo} b + +echo a "$foo" b +echo a "${foo}" b + +# multi-part arguments +echo one"two"three +echo one${two}three +echo one"two"$three + +echo one'two'three +echo one${two}three +echo one'two'$three + +echo one'two'three"four"five${six}seven$eight + + foo=bar echo $foo ${foo} echo "$foo" "${foo}" diff --git a/tests/grub_script_functions.in b/tests/grub_script_functions.in new file mode 100644 index 000000000..3e69014d6 --- /dev/null +++ b/tests/grub_script_functions.in @@ -0,0 +1,147 @@ +#! @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 . + +echo parameter count +function fcount { + echo fcount "$#" +} + +fcount +fcount a +fcount a b + +echo parameter count, with nesting +function ffcount { + echo ffcount "$#" + fcount + fcount a + fcount a b +} + +ffcount +ffcount 1 +ffcount 1 2 + +echo parameters +function fparam { + echo fparam 1 $1 + echo fparam 2 $2 + echo fparam 3 $3 +} + +fparam +fparam a +fparam a b + +echo parameters, with nesting +function ffparam { + echo ffparam 1 $1 + echo ffparam 2 $2 + echo ffparam 3 $3 + fparam + fparam a + fparam a b +} + +ffparam +ffparam 1 +ffparam 1 2 + +echo parameter expansion with specials +function fstar { + for f in $* + do + echo fstar $f + done + + for f in aaa$*bbb + do + echo fstar $f + done +} + +fstar +fstar a +fstar a "1 2" +fstar a "1 2" b + +function fdqstar { + for f in "$*" + do + echo fdqstar $f + done + + for f in aaa"$*"bbb + do + echo fdqstar $f + done + + for f in "aaa$*bbb" + do + echo fdqstar $f + done +} + +fdqstar +fdqstar a +fdqstar a "1 2" +fdqstar a "1 2" b + +function fat { + for f in $@ + do + echo fat $f + done + + for f in aaa$@bbb + do + echo fat $f + done +} + +fat +fat a +fat a "1 2" +fat a "1 2" b +fat a "1 2" b "c d" +fat a "1 2" b "c d" e + +function fdqat { + for f in "$@" + do + echo fdqat $f + done + + for f in aaa"$@"bbb + do + echo fdqat $f + done + + for f in "aaa$@bbb" + do + echo fdqat $f + done +} + +# fdqat # this case needs special handling, lets ignore till we really need it. +fdqat a +fdqat a "1 2" +fdqat a "1 2" b +fdqat a "1 2" b "c d" +fdqat a "1 2" b "c d" e + diff --git a/tests/grub_script_shift.in b/tests/grub_script_shift.in new file mode 100644 index 000000000..785b9c396 --- /dev/null +++ b/tests/grub_script_shift.in @@ -0,0 +1,85 @@ +#! @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 { + echo f1 '$@' $@ + echo f1 '$*' $* + echo f1 $# $1 $2 $3 + shift + echo f1 '$@' $@ + echo f1 '$*' $* + echo f1 $# $1 $2 $3 +} + +f1 +f1 a +f1 a b +f1 a b c +f1 a b c d +f1 a b c d e + +function f2 { + echo f1 '$@' $@ + echo f1 '$*' $* + echo f2 $# $1 $2 $3 + shift 1 + echo f1 '$@' $@ + echo f1 '$*' $* + echo f2 $# $1 $2 $3 +} + +f2 +f2 a +f2 a b +f2 a b c +f2 a b c d +f2 a b c d e + +function f3 { + echo f1 '$@' $@ + echo f1 '$*' $* + echo f3 $# $1 $2 $3 + shift 3 + echo f1 '$@' $@ + echo f1 '$*' $* + echo f3 $# $1 $2 $3 +} + +f3 +f3 a +f3 a b +f3 a b c +f3 a b c d +f3 a b c d e + +function f4 { + echo f1 '$@' $@ + echo f1 '$*' $* + echo f4 $# $1 $2 $3 + shift 100 + echo f1 '$@' $@ + echo f1 '$*' $* + echo f4 $# $1 $2 $3 +} + +f4 +f4 a +f4 a b +f4 a b c +f4 a b c d +f4 a b c d e diff --git a/tests/grub_script_vars1.in b/tests/grub_script_vars1.in index 9ff897627..77b3cf298 100644 --- a/tests/grub_script_vars1.in +++ b/tests/grub_script_vars1.in @@ -28,7 +28,7 @@ foo=foo echo "" $foo echo $bar $foo - + bar="" echo $bar $foo diff --git a/tests/util/grub-shell-tester.in b/tests/util/grub-shell-tester.in index f1e91f561..d2a9af3ab 100644 --- a/tests/util/grub-shell-tester.in +++ b/tests/util/grub-shell-tester.in @@ -1,4 +1,4 @@ -#! /bin/bash -e +#! /bin/sh -e # Compares GRUB script output with BASH output. # Copyright (C) 2009,2010 Free Software Foundation, Inc. @@ -84,7 +84,7 @@ done if [ "x${source}" = x ] ; then tmpfile=`mktemp` - while read; do + while read REPLY; do echo $REPLY >> ${tmpfile} done source=${tmpfile} diff --git a/util/deviceiter.c b/util/deviceiter.c index bbcc00a91..1cf511934 100644 --- a/util/deviceiter.c +++ b/util/deviceiter.c @@ -467,13 +467,30 @@ clear_seen_devices (void) } #ifdef __linux__ -/* Like strcmp, but doesn't require a cast for use as a qsort comparator. */ -static int -compare_file_names (const void *a, const void *b) +struct device { - const char *left = *(const char **) a; - const char *right = *(const char **) b; - return strcmp (left, right); + char *stable; + char *kernel; +}; + +/* Sort by the kernel name for preference since that most closely matches + older device.map files, but sort by stable by-id names as a fallback. + This is because /dev/disk/by-id/ usually has a few alternative + identifications of devices (e.g. ATA vs. SATA). + check_device_readable_unique will ensure that we only get one for any + given disk, but sort the list so that the choice of which one we get is + stable. */ +static int +compare_devices (const void *a, const void *b) +{ + const struct device *left = (const struct device *) a; + const struct device *right = (const struct device *) b; + int ret; + ret = strcmp (left->kernel, right->kernel); + if (ret) + return ret; + else + return strcmp (left->stable, right->stable); } #endif /* __linux__ */ @@ -507,10 +524,10 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), if (dir) { struct dirent *entry; - char **names; - size_t names_len = 0, names_max = 1024, i; + struct device *devs; + size_t devs_len = 0, devs_max = 1024, i; - names = xmalloc (names_max * sizeof (*names)); + devs = xmalloc (devs_max * sizeof (*devs)); /* Dump all the directory entries into names, resizing if necessary. */ @@ -526,35 +543,34 @@ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int), /* Skip RAID entries; they are handled by upper layers. */ if (strncmp (entry->d_name, "md-", sizeof ("md-") - 1) == 0) continue; - if (names_len >= names_max) + if (devs_len >= devs_max) { - names_max *= 2; - names = xrealloc (names, names_max * sizeof (*names)); + devs_max *= 2; + devs = xrealloc (devs, devs_max * sizeof (*devs)); } - names[names_len++] = xasprintf (entry->d_name); + devs[devs_len].stable = + xasprintf ("/dev/disk/by-id/%s", entry->d_name); + devs[devs_len].kernel = + canonicalize_file_name (devs[devs_len].stable); + devs_len++; } - /* /dev/disk/by-id/ usually has a few alternative identifications of - devices (e.g. ATA vs. SATA). check_device_readable_unique will - ensure that we only get one for any given disk, but sort the list - so that the choice of which one we get is stable. */ - qsort (names, names_len, sizeof (*names), &compare_file_names); + qsort (devs, devs_len, sizeof (*devs), &compare_devices); closedir (dir); /* Now add all the devices in sorted order. */ - for (i = 0; i < names_len; ++i) + for (i = 0; i < devs_len; ++i) { - char *path = xasprintf ("/dev/disk/by-id/%s", names[i]); - if (check_device_readable_unique (path)) + if (check_device_readable_unique (devs[i].stable)) { - if (hook (path, 0)) + if (hook (devs[i].stable, 0)) goto out; } - free (path); - free (names[i]); + free (devs[i].stable); + free (devs[i].kernel); } - free (names); + free (devs); } } diff --git a/util/grub-fstest.c b/util/grub-fstest.c index 9ac5cf550..48fcbc57f 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -136,7 +136,7 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) sz = grub_file_read (file, buf, (len > BUF_SIZE) ? BUF_SIZE : len); if (sz < 0) { - grub_util_error ("read error at offset %llu", ofs); + grub_util_error ("read error at offset %llu: %s", ofs, grub_errmsg); break; } @@ -190,7 +190,7 @@ cmd_cmp (char *src, char *dest) { if ((int) fread (buf_1, 1, len, ff) != len) { - grub_util_error ("read error at offset %llu", ofs); + grub_util_error ("read error at offset %llu: %s", ofs, grub_errmsg); return 1; } diff --git a/util/grub-macho2img.c b/util/grub-macho2img.c index 8683587be..23ffafb04 100644 --- a/util/grub-macho2img.c +++ b/util/grub-macho2img.c @@ -79,7 +79,7 @@ main (int argc, char **argv) fclose (in); fclose (out); free (buf); - printf ("Invalid Mach-O fle\n"); + printf ("Invalid Mach-O file\n"); return 4; } curcmd = (struct grub_macho_segment32 *) (buf + sizeof (*head)); diff --git a/util/grub-mkrescue.in b/util/grub-mkrescue.in index 43d128033..0f40e92cc 100644 --- a/util/grub-mkrescue.in +++ b/util/grub-mkrescue.in @@ -296,6 +296,7 @@ if test -e "${efi64_dir}" || test -e "${efi32_dir}"; then mformat -C -f 2880 -L 16 -i "${iso9660_dir}"/efi.img :: mcopy -s -i "${iso9660_dir}"/efi.img ${efi_dir}/efi ::/ + rm -rf ${efi_dir} grub_mkisofs_arguments="${grub_mkisofs_arguments} --efi-boot efi.img" fi diff --git a/util/grub-probe.c b/util/grub-probe.c index 3f72ae93d..ab3e2713e 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -49,6 +49,7 @@ enum { PRINT_FS, PRINT_FS_UUID, + PRINT_FS_LABEL, PRINT_DRIVE, PRINT_DEVICE, PRINT_PARTMAP, @@ -270,6 +271,16 @@ probe (const char *path, char *device_name) printf ("%s\n", uuid); } + else if (print == PRINT_FS_LABEL) + { + char *label; + if (! fs->label) + grub_util_error ("%s does not support labels", fs->name); + + fs->label (dev, &label); + + printf ("%s\n", label); + } end: if (dev) @@ -305,7 +316,7 @@ Probe device information for a given path (or device, if the -d option is given) \n\ -d, --device given argument is a system device, not a path\n\ -m, --device-map=FILE use FILE as the device map [default=%s]\n\ - -t, --target=(fs|fs_uuid|drive|device|partmap|abstraction)\n\ + -t, --target=(fs|fs_uuid|fs_label|drive|device|partmap|abstraction)\n\ print filesystem module, GRUB drive, system device, partition map module or abstraction module [default=fs]\n\ -h, --help display this message and exit\n\ -V, --version print version information and exit\n\ @@ -354,6 +365,8 @@ main (int argc, char *argv[]) print = PRINT_FS; else if (!strcmp (optarg, "fs_uuid")) print = PRINT_FS_UUID; + else if (!strcmp (optarg, "fs_label")) + print = PRINT_FS_LABEL; else if (!strcmp (optarg, "drive")) print = PRINT_DRIVE; else if (!strcmp (optarg, "device")) diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in index 75c8b0fa2..2f39650e9 100644 --- a/util/grub.d/00_header.in +++ b/util/grub.d/00_header.in @@ -137,11 +137,7 @@ case x${GRUB_TERMINAL_INPUT} in ;; x*) cat << EOF -if terminal_input ${GRUB_TERMINAL_INPUT} ; then true ; else - # For backward compatibility with versions of terminal.mod that don't - # understand terminal_input - terminal ${GRUB_TERMINAL_INPUT} -fi +terminal_input ${GRUB_TERMINAL_INPUT} EOF ;; esac @@ -152,11 +148,7 @@ case x${GRUB_TERMINAL_OUTPUT} in ;; x*) cat << EOF -if terminal_output ${GRUB_TERMINAL_OUTPUT} ; then true ; else - # For backward compatibility with versions of terminal.mod that don't - # understand terminal_output - terminal ${GRUB_TERMINAL_OUTPUT} -fi +terminal_output ${GRUB_TERMINAL_OUTPUT} EOF ;; esac diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in index 9915abdf1..3a42de529 100644 --- a/util/grub.d/10_kfreebsd.in +++ b/util/grub.d/10_kfreebsd.in @@ -51,6 +51,10 @@ kfreebsd_entry () if [ -z "${prepare_boot_cache}" ]; then prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")" fi + if [ -z "${prepare_module_dir_cache}" ]; then + prepare_module_dir_cache="$(prepare_grub_to_access_device $(grub-probe -t device "${module_dir}") | sed -e "s/^/\t/")" + fi + printf '%s\n' "${prepare_boot_cache}" cat << EOF echo '$(printf "$(gettext_quoted "Loading kernel of FreeBSD %s ...")" ${version})' @@ -63,14 +67,35 @@ EOF EOF fi - if test -n "${acpi_ko}" ; then + if test -e "${module_dir}/acpi.ko" ; then + printf '%s\n' "${prepare_module_dir_cache}" cat << EOF - kfreebsd_module_elf ${acpi_ko_rel_dirname}/${acpi_ko_basename} + kfreebsd_module_elf ${module_dir_rel}/acpi.ko EOF fi + case "${kfreebsd_fs}" in + zfs) + for i in "${module_dir}/opensolaris.ko" "${module_dir}/zfs.ko" \ + "${dirname}/zfs/zpool.cache" ; do + ls "$i" > /dev/null + done + + printf '%s\n' "${prepare_module_dir_cache}" + cat << EOF + kfreebsd_module_elf ${module_dir_rel}/opensolaris.ko + kfreebsd_module_elf ${module_dir_rel}/zfs.ko +EOF + + printf '%s\n' "${prepare_boot_cache}" cat << EOF - set kFreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${GRUB_DEVICE} + kfreebsd_module ${rel_dirname}/zfs/zpool.cache type=/boot/zfs/zpool.cache +EOF + ;; + esac + + cat << EOF + set kFreeBSD.vfs.root.mountfrom=${kfreebsd_fs}:${kfreebsd_device} set kFreeBSD.vfs.root.mountfrom.options=rw } EOF @@ -100,22 +125,25 @@ while [ "x$list" != "x" ] ; do *) kfreebsd_fs=${GRUB_FS} ;; esac + case ${GRUB_FS} in + zfs) kfreebsd_device=$(grub-probe -t fs_label --device ${GRUB_DEVICE}) ;; + *) kfreebsd_device=${GRUB_DEVICE} ;; + esac + version=`echo $basename | sed -e "s,^[^0-9]*-,,g;s/\.gz$//g"` alt_version=`echo $version | sed -e "s,\.old$,,g"` - acpi_ko= - for i in "/lib/modules/${version}/acpi.ko" "/lib/modules/${alt_version}/acpi.ko" \ - "/boot/kernel/acpi.ko"; do + module_dir= + for i in "/lib/modules/${version}" "/lib/modules/${alt_version}" \ + "/boot/kernel"; do if test -e "$i" ; then - acpi_ko="$i" + module_dir="$i" break fi done - if test -n "${acpi_ko}" ; then - echo "Found ACPI module: ${acpi_ko}" >&2 - acpi_ko_basename=`basename ${acpi_ko}` - acpi_ko_dirname=`dirname ${acpi_ko}` - acpi_ko_rel_dirname=`make_system_path_relative_to_its_root $acpi_ko_dirname` + if test -n "${module_dir}" ; then + echo "Found kernel module directory: ${module_dir}" >&2 + module_dir_rel=$(make_system_path_relative_to_its_root $module_dir) fi kfreebsd_entry "${OS}" "${version}" diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in index 8612c96b0..e631c0a4a 100644 --- a/util/grub.d/20_linux_xen.in +++ b/util/grub.d/20_linux_xen.in @@ -44,7 +44,8 @@ case ${GRUB_DEVICE} in esac if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ - || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then + || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ + || uses_abstraction "${GRUB_DEVICE}" lvm; then LINUX_ROOT_DEVICE=${GRUB_DEVICE} else LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} diff --git a/util/i386/efi/grub-install.in b/util/i386/efi/grub-install.in index 269317cd0..d8554a328 100644 --- a/util/i386/efi/grub-install.in +++ b/util/i386/efi/grub-install.in @@ -246,7 +246,7 @@ devabstraction_module=`$grub_probe --target=abstraction --device-map=${device_ma # The order in this list is critical. Be careful when modifying it. modules="$modules $fs_module $partmap_module $devabstraction_module" -$grub_mkimage -O ${target_cpu}-efi --output=${grubdir}/grub.efi $modules || exit 1 +$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." diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 36c837bf3..9788efe4a 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -791,14 +791,14 @@ main (int argc, char *argv[]) must_embed = 1; if (root_dev[0] == 'm' && root_dev[1] == 'd' - && root_dev[2] >= '0' && root_dev[2] <= '9') + && ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/')) { /* FIXME: we can avoid this on RAID1. */ must_embed = 1; } if (dest_dev[0] == 'm' && dest_dev[1] == 'd' - && dest_dev[2] >= '0' && dest_dev[2] <= '9') + && ((dest_dev[2] >= '0' && dest_dev[2] <= '9') || dest_dev[2] == '/')) { char **devicelist; int i; diff --git a/util/ieee1275/grub-install.in b/util/ieee1275/grub-install.in index 98fd5d65a..98de5f348 100644 --- a/util/ieee1275/grub-install.in +++ b/util/ieee1275/grub-install.in @@ -212,7 +212,7 @@ fi # 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 ${grub_device} 2> /dev/null`; do +for x in `$grub_probe --target=partmap --device-map=${device_map} ${grubdir} 2> /dev/null`; do partmap_module="$partmap_module part_$x"; done diff --git a/util/import_unicode.py b/util/import_unicode.py index 1ee162d3f..8d17e7ef6 100644 --- a/util/import_unicode.py +++ b/util/import_unicode.py @@ -18,8 +18,6 @@ import re import sys -import os -import datetime if len (sys.argv) < 3: print ("Usage: %s SOURCE DESTINATION" % sys.argv[0]) diff --git a/util/misc.c b/util/misc.c index 3413c051a..cfbae609b 100644 --- a/util/misc.c +++ b/util/misc.c @@ -193,7 +193,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd __attribute__ ((unused) } grub_err_t -grub_script_execute_cmdblock (struct grub_script_cmd *cmd __attribute__ ((unused))) +grub_script_execute_cmdlist (struct grub_script_cmd *cmd __attribute__ ((unused))) { return 0; }