diff --git a/.bzrignore b/.bzrignore index 3c7150afb..cfdd069fd 100644 --- a/.bzrignore +++ b/.bzrignore @@ -69,6 +69,7 @@ Makefile mod-*.c missing *.pf2 +*.pp po/*.mo po/grub.pot stamp-h @@ -91,7 +92,10 @@ texinfo.tex grub-core/lib/libgcrypt-grub **/.deps-util **/.deps-core +**/.dirstamp Makefile.util.am grub-core/Makefile.core.am grub-core/Makefile.gcry.am grub-core/Makefile.gcry.def +grub-core/*.module +grub-core/*.pp diff --git a/ChangeLog b/ChangeLog index 7043faf97..04c526d98 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,1161 @@ +2010-09-05 Vladimir Serbinenko + + * docs/grub.texi (Theme file format): Document new position format. + +2010-09-05 Vladimir Serbinenko + + * docs/grub.texi (Theme file format): Replace Box_slice_names.png with + a table. Use @code instead of @verbatim. + +2010-09-05 Colin D Bennett + + Gfxmenu documentation. + + * docs/grub.texi (Theme file format): New chapter. + +2010-09-05 Szymon Janc + + * grub-core/Makefile.core.def (xzio): New module. + * grub-core/io/xzio.c: New file. + * grub-core/lib/xzembed/xz.h: New file (from xembed). + * grub-core/lib/xzembed/xz_config.h: Likewise. + * grub-core/lib/xzembed/xz_dec_bcj.c: Likewise. + * grub-core/lib/xzembed/xz_dec_lzma2.c: Likewise. + * grub-core/lib/xzembed/xz_dec_stream.c: Likewise. + * grub-core/lib/xzembed/xz_lzma2.h: Likewise. + * grub-core/lib/xzembed/xz_private.h: Likewise. + * grub-core/lib/xzembed/xz_stream.h: Likewise. + * include/grub/file.h (grub_file_filter_id): New compression filter + GRUB_FILE_FILTER_XZIO. + +2010-09-05 Vladimir Serbinenko + + * include/grub/file.h (GRUB_FILE_SIZE_UNKNOWN): New definition. + * grub-core/disk/loopback.c (grub_loopback_open): Handle unknown file + size. + +2010-09-05 Vladimir Serbinenko + + * include/grub/err.h (grub_err_t): Replace GRUB_ERR_BAD_GZIP_DATA with + GRUB_ERR_BAD_COMPRESSED_DATA. All users updated. + +2010-09-05 Vladimir Serbinenko + + Uncompressed checksum support. + + * grub-core/commands/hashsum.c (options): Add option --uncompress. + (check_list): New parameter uncompress. + (grub_cmd_hashsum): Handle --uncompress. + +2010-09-05 Vladimir Serbinenko + + Reintroduce testload. + + * grub-core/commands/minicmd.c (grub_rescue_cmd_testload) [0]: Moved + from here ... + * grub-core/commands/testload.c (grub_cmd_testload): ... here. + (GRUB_MOD_INIT): New function. + (GRUB_MOD_FINI): Likewise. + * grub-core/Makefile.core.def (testload): New module. + +2010-09-05 Szymon Janc + + * grub-core/lib/posix_wrap/sys/types.h (bool): Transform into an enum. + (uint8_t): New type. + (uint16_t): Likewise. + (uint32_t): Likewise. + (uint64_t): Likewise. + +2010-09-05 Szymon Janc + + * include/grub/crypto.h (GRUB_MD_CRC32): New definition. + +2010-09-05 Vladimir Serbinenko + + * grub-core/io/gzio.c (grub_gzio_open): Removed "transparent" parameter. + Made static. + (grub_gzfile_open): Removed. All users updated. + (GRUB_MOD_INIT): New function. + (GRUB_MOD_FINI): Likewise. + * grub-core/kern/file.c (grub_file_filters_all): New variable. + (grub_file_filters_enabled): Likewise. + (grub_file_open): Handle filters. + * grub-core/loader/i386/bsd.c (GRUB_MOD_INIT): Load gzio. + * grub-core/normal/main.c (GRUB_MOD_INIT): Likewise. + * include/grub/file.h (grub_file_filter_id_t): New type. + (grub_file_filter_t): Likewise. + (grub_file_filters_all): New extern variable. + (grub_file_filters_enabled): Likewise. + (grub_file_filter_register): New inline function. + (grub_file_filter_unregister): Likewise. + (grub_file_filter_disable): Likewise. + (grub_file_filter_disable_compression): Likewise. + * include/grub/gzio.h: Removed. + +2010-09-04 BVK Chaitanya + + Filename expansion support for wildcards in GRUB script. + + * tests/grub_script_expansion.in: New test. + * Makefile.util.def: Rule for new test. + + * grub-core/commands/wildcard.c: New file, implements filename + expansion support for GRUB script. + * grub-core/Makefile.core.def: Rule update for regexp.mod. + * grub-core/script/argv.c: Cosmetic changes. + * grub-core/script/execute.c (grub_script_arglist_to_argv): + Refactored to perform wildcard expansion on arguments. + * include/grub/script_sh.h (grub_script_wildcard_translator): New + struct. + + * tests/util/grub-shell.in: Fix quoting for read input. + +2010-09-04 BVK Chaitanya + + Support for updating environment variables with matched substrings + of regexp. + + * tests/grub_cmd_regexp.in: New test. + * Makefile.util.def: Rule for new test. + + * grub-core/commands/regexp.c: New option -s to update environment + variables with regexp matches. + +2010-09-04 Szymon Janc + + * include/grub/file.h (grub_file): New member not_easly_seekable. + (grub_file_seekable): New inline function. + * grub-core/io/gzio.c (test_header): Don't test end magic if file isn't + easily seekable. + (grub_gzio_open): Set not_easly_seekable. + * grub-core/fs/i386/pc/pxe.c (grub_pxefs_open): Set not_easily_seekable. + * grub-core/io/bufio.c (grub_bufio_open): Propagate not_easily_seekable. + +2010-09-04 BVK Chaitanya + + Support for options to appear multiple times on cmdline. + + * include/grub/lib/arg.h (grub_arg_list_alloc): New prototype. + * grub-core/commands/extcmd.c: Support for repeatable option. + * grub-core/lib/arg.c (grub_arg_list_alloc): New function for + repeatable option support. + + Refactor menuentry into a regular command. + + * grub-core/commands/menuentry.c: New file, menuentry command + implementation. + * grub-core/Makefile.core.def: Rule update for normal.mod. + * grub-core/normal/main.c: Moved menuentry creation to + grub-core/commands/menuentry.c. + * grub-core/normal/menu.c (grub_menu_execute_entry): Removed. + (grub_menu_execute_entry_real): Removed. + * grub-core/script/execute.c (grub_script_execute_sourcecode): New + function. + (grub_script_execute_menuentry): Removed. + * grub-core/script/parser.y (menuentry): Removed. + * grub-core/script/script.c (grub_script_create_cmdmenu): Removed. + * grub-core/script/yylex.l (menuentry): Removed. + * include/grub/menu.h (grub_menu_init): New prototype. + (grub_menu_fini): New prototype. + * include/grub/normal.h (grub_normal_add_menu_entry): Removed. + * include/grub/script_sh.h (grub_script_cmd_menuentry): Removed. + (grub_script_execute_sourcecode): New prototype. + +2010-09-04 BVK Chaitanya + + "return" command for GRUB script functions. + + * tests/grub_script_return.in: New test. + * Makefile.util.def: Rules for new test. + + * grub-core/script/execute.c (grub_script_return): New function. + * grub-core/script/main.c: Register/unregister return commaond. + * include/grub/script_sh.h (grub_script_return): New prototype. + +2010-09-04 BVK Chaitanya + + "setparams" command to update positional parameters. + + * tests/grub_script_setparams.in: New test. + * Makefile.util.def: Rules for new test. + + * grub-core/script/argv.c (grub_script_argv_make): New function. + * grub-core/script/execute.c (replace_scope): New function. + (grub_script_setparams): New function. + * grub-core/script/lexer.c: Remove unused variables. + * grub-core/script/main.c: Register/unregister setparams command. + * include/grub/script_sh.h (grub_script_argv_make): New prototype. + (grub_script_setparams): New prototype. + +2010-09-04 BVK Chaitanya + + * grub-core/normal/completion.c (grub_normal_do_completion): Fix + grub_free order. + +2010-09-04 BVK Chaitanya + + Support for passing block of commands as an argument to extcmds. + + * Makefile.util.def: Rules for new test. + * tests/grub_script_blockarg.in: New test. + * grub-core/tests/test_blockarg.c: New file, block argument + command used in the test. + + * include/grub/extcmd.h (grub_extcmd_context): New struct. + (grub_register_extcmd_prio): New function prototype. + (grub_extcmd_dispatcher): New function prototype. + * include/grub/command.h (GRUB_COMMAND_FLAG_BLOCKS): New command + type. + * include/grub/script_sh.h (struct grub_script): New members + `children', `next_siblings' and `refcnt' for block arguments and + reference counting. + (GRUB_SCRIPT_ARG_TYPE_BLOCK): New argument type. + (grub_script_arg): New member `script' for block argument. + (grub_script_argv): New member `script' for block argument. + (grub_parser_param): New member `scripts' for block argument. + (grub_script_mem_free): New extern function prototype. + (grub_script_ref): New function prototype. + (grub_script_unref): New function prototype. + + * grub-core/normal/dyncmd.c (grub_dyncmd_dispatcher): Moved to + extcmd form to support block arguments. + * grub-core/script/argv.c: Block arguments support. + * grub-core/script/execute.c: Likewise. + * grub-core/script/lexer.c: Likewise. + * grub-core/script/main.c: Likewise. + * grub-core/script/script.c: Likewise. + * grub-core/script/parser.y: Likewise. New `block' and `block0' + non-terminals. + + * grub-core/commands/acpi.c: Update extcmd implementations with + grub_extcmd_context_t. + * grub-core/commands/cat.c: Likewise. + * grub-core/commands/echo.c: Likewise. + * grub-core/commands/extcmd.c: Likewise. + * grub-core/commands/hashsum.c: Likewise. + * grub-core/commands/hdparm.c: Likewise. + * grub-core/commands/help.c: Likewise. + * grub-core/commands/hexdump.c: Likewise. + * grub-core/commands/i386/cpuid.c: Likewise. + * grub-core/commands/i386/pc/drivemap.c: Likewise. + * grub-core/commands/i386/pc/halt.c: Likewise. + * grub-core/commands/i386/pc/sendkey.c: Likewise. + * grub-core/commands/iorw.c: Likewise. + * grub-core/commands/keystatus.c: Likewise. + * grub-core/commands/loadenv.c: Likewise. + * grub-core/commands/ls.c: Likewise. + * grub-core/commands/lspci.c: Likewise. + * grub-core/commands/memrw.c: Likewise. + * grub-core/commands/probe.c: Likewise. + * grub-core/commands/search_wrap.c: Likewise. + * grub-core/commands/setpci.c: Likewise. + * grub-core/commands/sleep.c: Likewise. + * grub-core/disk/loopback.c: Likewise. + * grub-core/hello/hello.c: Likewise. + * grub-core/loader/i386/bsd.c: Likewise. + * grub-core/loader/xnu.c: Likewise. + * grub-core/term/gfxterm.c: Likewise. + * grub-core/term/serial.c: Likewise. + * grub-core/tests/lib/functional_test.c: Likewise. + +2010-09-04 BVK Chaitanya + + Multi-line quoted strings support. + + * grub-core/script/lexer.c (append_newline): Removed. + (grub_script_lexer_yywrap): Refactored. + (grub_script_lexer_init): Refactored. + * grub-core/script/yylex.l (yywrap): New function. + (grub_lexer_resplit): New function. + (grub_lexer_unput): New function. + * include/grub/script_sh.h (grub_lexer_param): New members, unput + and resplit. + * tests/grub_script_echo1.in: Added few more testcases. + +2010-09-04 Vladimir Serbinenko + + * grub-core/kern/misc.c: Don't add abort alias in utils. + Reported by: echoline. + +2010-09-03 BVK Chaitanya + + Add missing files into "make dist" tarball for other platforms. + + * gentpl.py (script): Use dist_noinst_DATA instead of EXTRA_DIST. + * conf/Makefile.common (dist_noinst_DATA): New variable. + * conf/Makefile.extra-dist: Added missing make dist files. + * grub-core/Makefile.core.def: Likewise. + +2010-09-03 Vladimir Serbinenko + + Compress grub_prefix. + + * grub-core/boot/i386/pc/lnxboot.S: Use + GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE. + * grub-core/kern/i386/pc/startup.S: Move grub_prefix to compressed part. + * include/grub/offsets.h: Rename GRUB_MACHINE_DATA_END to + GRUB_MACHINE_PREFIX_END. All users updated. + (GRUB_KERNEL_I386_PC_PREFIX): Set to GRUB_KERNEL_I386_PC_RAW_SIZE. + (GRUB_KERNEL_I386_PC_PREFIX_END): Set to GRUB_KERNEL_I386_PC_PREFIX + + 0x40. + (GRUB_KERNEL_I386_PC_RAW_SIZE): Decrease. + * util/grub-mkimage.c (image_target_desc): Change data_end to + prefix_end. All users updated. + +2010-09-03 Vladimir Serbinenko + + * grub-core/loader/i386/bsd.c (grub_freebsd_boot): Set %ebp to sane + value. + (grub_openbsd_boot): Likewise. + (grub_netbsd_boot): Likewise. + * grub-core/loader/i386/xnu.c (grub_xnu_boot_resume): Likewise. + (grub_xnu_boot): Likewise. + +2010-09-02 Vladimir Serbinenko + + * configure.ac: Clean LIBS variable after tests. + +2010-09-02 Colin Watson + + * INSTALL: Document that libdevmapper needs to be 1.02.34 or later. + +2010-09-02 Vladimir Serbinenko + + * configure.ac: Check for dm_log_with_errno_init in libdevmapper and + echo if libdevmapper will be used. + +2010-09-02 Ian Turner + + * grub-core/fs/i386/pc/pxe.c (grub_pxefs_read): Keep the blocksize + constant for the same file. + +2010-09-02 Vladimir Serbinenko + + * grub-core/kern/i386/multiboot_mmap.c: Remove leftover include. + +2010-09-02 Colin Watson + + * .bzrignore: Add *.pp, **/.dirstamp, grub-core/*.module, and + grub-core/*.pp. + +2010-09-02 Colin Watson + + Zero %ebp and %edi when entering Linux's 32-bit entry point, as + required by the boot protocol. + + * include/grub/i386/relocator.h (struct grub_relocator32_state): Add + ebp and edi members. + * grub-core/lib/i386/relocator.c (grub_relocator_boot): Handle + state.ebp and state.edi. + * grub-core/lib/i386/relocator32.S (grub_relocator32_start): Set + %ebp and %edi according to grub_relocator32_ebp and + grub_relocator32_edi respectively. + * grub-core/loader/i386/linux.c (grub_linux_boot): Zero state.ebp + and state.edi. + +2010-09-02 Vladimir Serbinenko + + Add i386-pc-pxe image target. + + * util/grub-mkimage.c (image_target_desc): New enum value + IMAGE_I386_PC_PXE. + (image_targets): New target i386-pc-pxe. + (generate_image): Handle i386-pc-pxe image. + +2010-09-02 Vladimir Serbinenko + + Fix grub_pxe_scan. + + * grub-core/fs/i386/pc/pxe.c (grub_pxe_pxenv): Put correct type bangpxe. + (grub_pxe_scan): Fix types and pxe_rm_entry computation. + All users updated. + * include/grub/i386/pc/pxe.h (grub_pxe_bangpxe): New struct. + (grub_pxe_pxenv): Correct type. + +2010-09-01 Colin Watson + + * NEWS: Document most of the important changes since 1.98. + +2010-09-01 Colin Watson + + * util/grub-mkrescue.in (usage): Tidy up usage output (and hence + generated manual page) a little. + +2010-09-01 Colin Watson + + * docs/grub.texi: Add myself as an author. + +2010-09-01 Vladimir Serbinenko + + * Makefile.util.def (libgrub.a): Add missing sunpc. + Reported by: Seth Goldberg. + +2010-08-30 Vladimir Serbinenko + + Interrupt wrapping and code simplifications. + + * Makefile.util.def (grub-mkrescue): Use x86 tg instead of + x86_noieee1275 which are functionaly equivalent in this case. + (grub-install): Make source on each platform explicit. Enable on + all noemu. + * gentpl.py (x86_efi_pc): Removed group. + (x86_noefi): Likewise. + (i386_noefi): Likewise. + (x86_noieee1275): Likewise. + (i386_noieee1275): Likewise. + (i386_noefi_noieee1275): Likewise. + (i386_pc_qemu_coreboot): Likewise. + (i386_coreboot_multiboot): Likewise. + (i386_pc_coreboot_multiboot_qemu): Likewise. + (x86_noefi_mips): Likewise. + (noieee1275): Likewise. + (ieee1275_mips): Likewise. + (noemu_noieee1275): Likewise. + (cmos): New group. + (usb): Likewise. + (videoinkernel): Likewise. + (videomodules): Likewise. + * grub-core/Makefile.am (KERNEL_HEADER_FILES): Remove + include/grub/elf.h, include/grub/elfload.h, include/grub/net.h, + include/grub/reader.h, include/grub/symbol.h, include/grub/types.h, + include/grub/loader.h, include/grub/msdos_partition.h, + include/grub/machine/biosdisk.h, include/grub/machine/boot.h, + include/grub/machine/console.h, include/grub/machine/vga.h, + include/grub/machine/vbe.h, include/grub/machine/init.h, + include/grub/machine/kernel.h, include/grub/cpu/time.h, + include/grub/cpu/types.h, include/grub/gzio.h and include/grub/menu.h + (KERNEL_HEADER_FILES) [i386-pc]: Add include/grub/machine/int.h. + (KERNEL_HEADER_FILES) [i386-ieee1275]: Add include/grub/i386/pit.h + * grub-core/Makefile.core.def (kernel): Explicit the source for + startup. Explicit the platforms using kern/generic/rtc_get_time_ms.c. + Split ieee1275_mips. Remove kern/i386/halt.c. Remove kern/i386/misc.S. + Enable kern/i386/pit.c on all x86. Remove kern/i386/ieee1275/init.c. + Use videoinkernel tag. + (usb): Enable on all usb. + (usbserial_common): Likewise. + (usbserial_pl2303): Likewise. + (usbserial_ftdi): Likewise. + (uhci): Enable on all x86. + (ohci): Enable on all pci. + (cmostest): Enable on all CMOS. + (acpi): Include commands/acpi.c on all platforms. + (halt): Add relevant lib/*/halt.c. + (hdparm): Enable on all pci. + (lspci): Likewise. + (usbtest): Enable on all usb. + (ata): Enable on all pci. + (ata_pthru): Likewise. + (usbms): Enable on all usb. + (usb_keyboard): Likewise. + (font): Use tag videomodules. + (bufio): Likewise. + (datetime): Use tag cmos. Enable on all noemu. + (mmap): Use tags common and x86. + (gfxterm): Use tag videomodules. + (bitmap): Likewise. + (bitmap_scale): Likewise. + (video_fb): Likewise. + (video): Likewise. + * grub-core/bus/usb/ohci.c (grub_ohci_td): Make link_td a pointer and + adjust padding accordingly. All users updated. + (grub_ohci_transaction): Fix bad format specification. + (GRUB_MOD_INIT): Add asserts for struct size. + * grub-core/bus/usb/uhci.c (grub_uhci_pci_iter): Add explicit casts. + (grub_alloc_td): Likewise. + (grub_free_queue): Likewise. + (grub_uhci_transfer): Likewise. + (grub_uhci_transaction): Fix bad format specification. + * grub-core/bus/usb/usbtrans.c (grub_usb_control_msg): Likewise. + (grub_usb_bulk_readwrite): Likewise. + * grub-core/kern/i386/misc.S (grub_stop): Moved from here ... + * grub-core/commands/i386/pc/halt.c (stop): ...here. Transformed into C. + Made static. + * grub-core/lib/i386/halt.c (stop): ... and here. Transformed into C. + Made static. + * grub-core/kern/i386/pc/startup.S (grub_halt): Moved from here ... + * grub-core/commands/i386/pc/halt.c (grub_halt): ...here. + Transformed into C. + * grub-core/kern/i386/pc/startup.S (grub_biosdisk_rw_int13_extensions): + Moved from here ... + * grub-core/disk/i386/pc/biosdisk.c (grub_biosdisk_rw_int13_extensions): + ... here. Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S (grub_biosdisk_rw_standard): + Moved from here ... + * grub-core/disk/i386/pc/biosdisk.c (grub_biosdisk_rw_standard): + ... here. Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S + (grub_biosdisk_check_int13_extensions): Moved from here ... + * grub-core/disk/i386/pc/biosdisk.c + (grub_biosdisk_check_int13_extensions): ... here. Transformed into C. + Made static. + * grub-core/kern/i386/pc/startup.S + (grub_biosdisk_get_cdinfo_int13_extensions): Moved from here ... + * grub-core/disk/i386/pc/biosdisk.c + (grub_biosdisk_get_cdinfo_int13_extensions): ... here. + Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S + (grub_biosdisk_get_diskinfo_int13_extensions): Moved from here ... + * grub-core/disk/i386/pc/biosdisk.c + (grub_biosdisk_get_diskinfo_int13_extensions): ... here. + Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S + (grub_biosdisk_get_diskinfo_standard): Moved from here ... + * grub-core/disk/i386/pc/biosdisk.c + (grub_biosdisk_get_diskinfo_standard): ... here. + Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S + (grub_biosdisk_get_num_floppies): Moved from here ... + * grub-core/disk/i386/pc/biosdisk.c + (grub_biosdisk_get_num_floppies): ... here. + Transformed into C. Made static. + * grub-core/disk/i386/pc/biosdisk.c (grub_biosdisk_get_diskinfo_real): + New function. + * grub-core/kern/i386/pc/startup.S (grub_pxe_scan): Moved from here ... + * grub-core/fs/i386/pc/pxe.c (grub_pxe_scan): ... here. + Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S (grub_rm_entry): Moved from here ... + * grub-core/fs/i386/pc/pxe.c (grub_rm_entry): ... here. + Transformed into C. Made static. + * grub-core/kern/i386/ieee1275/init.c: Removed. + * grub-core/kern/i386/misc.S: Likewise. + * grub-core/kern/i386/pc/startup.S (grub_get_memsize): + Splitted from here ... + * grub-core/kern/i386/pc/init.c (grub_get_conv_memsize): ... here. + Transformed into C. Made static. All users updated. + * grub-core/kern/i386/pc/mmap.c (grub_get_ext_memsize): ... and here. + Transformed into C. Made static. All users updated. + * grub-core/kern/i386/pc/startup.S (grub_get_eisa_mmap): + Moved from here... + * grub-core/kern/i386/pc/mmap.c (grub_get_eisa_mmap): ... here. + Transformed into C. Made static. All users updated. + * grub-core/kern/i386/pc/startup.S (grub_get_mmap_entry): + Moved from here... + * grub-core/kern/i386/pc/mmap.c (grub_get_mmap_entry): ... here. + Transformed into C. Made static. All users updated. + * grub-core/kern/i386/pc/startup.S (grub_stop_floppy): + Removed (replaced by C version). + * grub-core/kern/i386/pc/startup.S (grub_vga_set_mode): + Moved from here... + * grub-core/video/i386/pc/vga.c (grub_vga_set_mode): ...here. + Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_get_controller_info): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_controller_info): + ... here. Transformed into C. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_get_mode_info): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_mode_info): + ... here. Transformed into C. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_set_mode): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_set_mode): + ... here. Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_get_mode): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_mode): + ... here. Transformed into C. + * grub-core/kern/i386/pc/startup.S + (grub_vbe_bios_getset_dac_palette_width):Moved from here... + * grub-core/video/i386/pc/vbe.c + (grub_vbe_bios_getset_dac_palette_width):... here. Transformed into C. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_set_memory_window): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_set_memory_window): + ... here. Transformed into C. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_get_memory_window): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_memory_window): + ... here. Transformed into C. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_set_scanline_length): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_set_scanline_length): + ... here. Transformed into C. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_get_scanline_length): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_scanline_length): + ... here. Transformed into C. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_set_display_start): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_set_display_start): + ... here. Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_get_display_start): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_get_display_start): + ... here. Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S (grub_vbe_bios_set_palette_data): + Moved from here... + * grub-core/video/i386/pc/vbe.c (grub_vbe_bios_set_palette_data): + ... here. Transformed into C. Made static. + * grub-core/kern/i386/pc/startup.S (grub_pxe_call): Receive + pxe_rm_entry as third argument. + (grub_bios_interrupt): New function. + * grub-core/kern/i386/qemu/mmap.c: Remove useless include. + * grub-core/kern/i386/qemu/startup.S (codestart): Do cli;hlt instead + of calling grub_stop. + * grub-core/kern/efi/efi.c (grub_halt): Moved from here ... + * grub-core/lib/efi/halt.c (grub_halt): ...here. + * grub-core/kern/emu/main.c (grub_halt): Moved from here ... + * grub-core/lib/emu/halt.c (grub_halt): ... here. + * grub-core/lib/i386/halt.c: Moved from here ... + * grub-core/lib/i386/halt.c: ... here. + * grub-core/kern/ieee1275/openfw.c (grub_halt): Moved from here ... + * grub-core/lib/ieee1275/halt.c (grub_halt): ... here. + * grub-core/loader/i386/pc/linux.c (grub_linux16_boot): Call + grub_stop_floppy. + * grub-core/loader/i386/xnu.c (guessfsb) [IEEE1275]: Enable. + * include/grub/i386/coreboot/init.h: Removed. + * include/grub/i386/multiboot/init.h: Likewise. + * include/grub/i386/pc/biosdisk.h: Removed all function prototypes. + * include/grub/i386/pc/init.h: Likewise except grub_gate_a20. + * include/grub/i386/pc/int.h: New file. + * include/grub/i386/pc/pxe.h (GRUB_PXE_SIGNATURE): New definition. + (grub_pxe_scan): Removed. + (grub_pxe_call): Update prototype. + * include/grub/i386/pc/vbe.h: Removed EXPORT_FUNC and useless + prototypes. + * include/grub/i386/pc/vga.h (grub_vga_set_mode): Removed. + * include/grub/i386/qemu/init.h: Removed. + * include/grub/mips/yeeloong/kernel.h (grub_reboot): Add missing + noreturn. + (grub_halt): Likewise. + * include/grub/misc.h (grub_halt): Removed EXPORT_FUNC. + (grub_reboot): Likewise. + * grub-core/kern/i386/coreboot/init.c (grub_stop_floppy): Moved from here... + * include/grub/i386/floppy.h (grub_stop_floppy): ...here. Inlined. + * grub-core/kern/i386/pc/startup.S (grub_hard_stop): Removed. + +2010-08-30 Robert Millan + + * NEWS: Document addition of ZFS support in `grub-install' and + `grub-mkconfig'. + +2010-08-30 BVK Chaitanya + + * conf/Makefile.common (CPPFLAGS_DEFAULT): Remove leading / from + dprintf output. + +2010-08-30 Vladimir Serbinenko + + Remove leftover embedding of font objects. + + * include/grub/kernel.h (OBJ_TYPE_FONT): Removed. + * util/grub-install.in (font): Removed. + * util/grub-mkimage.c (generate_image): Remove font support. All users + updated. + +2010-08-30 Vladimir Serbinenko + + * docs/grub.texi (Network): Fix reference to pxe_blksize. + Reported by: Ian Turner + +2010-08-30 Vladimir Serbinenko + + * grub-core/normal/menu.c (grub_wait_after_message): Add a 10 second + timeout to avoid indefinite boot stalling. + +2010-08-30 Vladimir Serbinenko + + * grub-core/normal/color.c (grub_env_write_color_normal): Fix a warning. + (grub_env_write_color_highlight): Likewise. + +2010-08-30 Vladimir Serbinenko + + * grub-core/normal/term.c (print_more): Return to normal and not + to standard state after printing "---MORE---". + +2010-08-30 Vladimir Serbinenko + + * grub-core/term/i386/vga_common.c (grub_console_setcolorstate): + Mask out the bit 0x80 since it has other meaning that specifiing color. + +2010-08-29 Vladimir Serbinenko + + New relocator. Allows for more kernel support and more straightforward + loader writing. + + * Makefile.am (BOOTTARGET): New variable. + (QEMU32): Likewise. + (linux.init.x86_64): New target. + (linux.init.i386): Likewise. + (multiboot.elf): Likewise. + (kfreebsd.elf): Likewise. + (kfreebsd.aout): Likewise. + (pc-chainloader.elf): Likewise. + (pc-chainloader.bin): Likewise. + (ntldr.elf): Likewise. + (ntldr.bin): Likewise. + (multiboot2.elf): Likewise. + (kfreebsd.init.x86_64): Likewise. + (kfreebsd.init.i386): Likewise. + (knetbsd.init.i386): Likewise. + (kopenbsd.init.i386): Likewise. + (knetbsd.init.x86_64): Likewise. + (kopenbsd.init.x86_64): Likewise. + (linux-initramfs.i386): Likewise. + (linux-initramfs.x86_64): Likewise. + (kfreebsd-mfsroot.i386.img): Likewise. + (knetbsd.image.i386): Likewise. + (kopenbsd.image.i386): Likewise. + (kopenbsd.image.x86_64): Likewise. + (knetbsd.miniroot-image.i386.img): Likewise. + (kfreebsd-mfsroot.x86_64.img): Likewise. + (knetbsd.image.x86_64): Likewise. + (knetbsd.miniroot-image.x86_64.img): Likewise. + (kfreebsd-mfsroot.i386.gz): Likewise. + (bootcheck-kfreebsd-i386): Likewise. + (kfreebsd-mfsroot.x86_64.gz): Likewise. + (bootcheck-kfreebsd-x86_64): Likewise. + (knetbsd.miniroot-image.i386.gz): Likewise. + (bootcheck-knetbsd-i386): Likewise. + (bootcheck-kopenbsd-i386): Likewise. + (bootcheck-kopenbsd-x86_64): Likewise. + (knetbsd.miniroot-image.x86_64.gz): Likewise. + (bootcheck-knetbsd-x86_64): Likewise. + (bootcheck-linux-i386): Likewise. + (bootcheck-linux-x86_64): Likewise. + (bootcheck-linux16-i386): Likewise. + (bootcheck-linux16-x86_64): Likewise. + (bootcheck-multiboot): Likewise. + (bootcheck-multiboot2): Likewise. + (bootcheck-kfreebsd-aout): Likewise. + (bootcheck-pc-chainloader): Likewise. + (bootcheck-ntldr): Likewise. + (CLEANFILES): Add new targets. + (BOOTCHECKS): New variable. + (.PHONY): Add bootchecks. + (SUCCESSFUL_BOOT_STRING): New variable. + (BOOTCHECK_TIMEOUT): Likewise. + (bootcheck): New target + * Makefile.util.def (grub-mkrescue): Enable on i386-multiboot. + * configure.ac: Correct efiemu excuse. + * docs/grub.texi (Supported kernels): New chapter. + * grub-core/Makefile.am (KERNEL_HEADER_FILES): Add + include/grub/mm_private.h. Simplify inclusion of + include/grub/boot.h, include/grub/loader.h + and include/grub/msdos_partition.h + (KERNEL_HEADER_FILES) [i386_coreboot]: + Remove include/grub/machine/loader.h. Add include/grub/i386/pit.h. + (KERNEL_HEADER_FILES) [i386_multiboot]: Likewise. + (KERNEL_HEADER_FILES) [i386_qemu]: Likewise. + (KERNEL_HEADER_FILES) [i386_ieee1275]: Remove + include/grub/machine/loader.h. + (KERNEL_HEADER_FILES) [x86_64-efi]: Likewise. + * grub-core/Makefile.core.def (kernel): Remove kern/i386/loader.S from + extra_dist. + (pci.mod): Enable on i386-multiboot. + (acpi.mod): Enable on i386-multiboot and i386-coreboot. + (efiemu.mod): Enable on i386-coreboot, i386-ieee1275, i386-multiboot and + i386-qemu. + (relocator.mod): Rewritten. + (aout.mod): Enable on all x86. + (bsd.mod): Likewise. + (ntldr.mod): New module. + (linux.mod): Use loader/i386/linux.c on all x86. + (xnu.mod): Enable on all x86. + (vga_text.mod): disable on EFI and QEMU. + * grub-core/efiemu/i386/coredetect.c: Remove useless include. + * grub-core/efiemu/i386/pc/cfgtables.c: Likewise. + * grub-core/efiemu/loadcore.c: Likewise. + * grub-core/efiemu/main.c: Likewise. + (grub_efiemu_exit_boot_services): Removed. + (grub_efiemu_finish_boot_services): Likewise. + * grub-core/efiemu/mm.c (grub_efiemu_finish_boot_services): New + function. + * grub-core/efiemu/i386/nocfgtables.c: New file. + * grub-core/kern/dl.c (grub_dl_unload_all): Removed. + * grub-core/kern/efi/efi.c (grub_efi_exit_boot_services): Removed. + (grub_efi_finish_boot_services): Moved from here ... + * grub-core/kern/efi/mm.c (grub_efi_finish_boot_services): ...here. + Fille finish memory map and related data. + (finish_mmap_buf): New variable. + (grub_efi_uintn_t finish_mmap_size): Likewise. + (grub_efi_uintn_t finish_key): Likewise. + (grub_efi_uintn_t finish_desc_size): Likewise. + (grub_efi_uint32_t finish_desc_version): Likewise. + (grub_efi_is_finished): Likewise. + (grub_efi_get_memory_map): Use saved memory map if EFI is already + finished. + * grub-core/kern/elf.c (grub_elf32_phdr_iterate): Make global. + (grub_elf64_phdr_iterate): Likewise. + * grub-core/kern/i386/coreboot/init.c (grub_os_area_addr): Removed. + (grub_os_area_size): Likewise. + (grub_machine_init): Don't reserve os area. + * grub-core/kern/i386/coreboot/startup.S: Don't include loader.S. + * grub-core/kern/i386/ieee1275/startup.S: Likewise. + * grub-core/kern/i386/loader.S: Removed. + * grub-core/kern/i386/pc/init.c (grub_os_area_addr): Removed. + (grub_os_area_size): Likewise. + (grub_machine_init): Don't reserve os area. + * grub-core/kern/i386/pc/startup.S (grub_chainloader_real_boot): + Don't call grub_dl_unload_all. + Don't include loader.S. + * grub-core/kern/i386/qemu/mmap.c (grub_machine_mmap_iterate): + Declare the memory after _end as available. + * grub-core/kern/mm.c (GRUB_MM_FREE_MAGIC): Moved from here... + * include/grub/mm_private.h (GRUB_MM_FREE_MAGIC): ... here. + (GRUB_MM_ALLOC_MAGIC): Moved from here... + * include/grub/mm_private.h (GRUB_MM_ALLOC_MAGIC): ... here. + * grub-core/kern/mm.c (grub_mm_header): Moved from here... + * include/grub/mm_private.h (grub_mm_header): ... here. + * grub-core/kern/mm.c (GRUB_MM_ALIGN): Moved from here... + * include/grub/mm_private.h (GRUB_MM_ALIGN): ... here. + * grub-core/kern/mm.c (grub_mm_region): Moved from here ... + (grub_mm_region): ..here. Removed addr. Added pre_size. + All users updated. + * grub-core/kern/mm.c (base): Renamed to ... + (grub_mm_base): ... this. Made global. + (grub_real_malloc): Alloc from end of region. + (grub_memalign): Don't attempt to malloc if grub_mm_base is NULL. + * grub-core/kern/powerpc/cache.S (grub_arch_sync_caches): Move to ... + * grub-core/kern/powerpc/cache_flush.S: ... here. + * grub-core/lib/efi/relocator.c: New file. + * grub-core/lib/i386/relocator.c: Rewritten. + * grub-core/lib/i386/relocator16.S: New file. + * grub-core/lib/i386/relocator32.S: Likewise. + * grub-core/lib/i386/relocator64.S: Likewise. + * grub-core/lib/i386/relocator_asm.S: Rewritten. + * grub-core/lib/i386/relocator_common.S: New file. + * grub-core/lib/ieee1275/relocator.c: Likewise. + * grub-core/lib/mips/relocator.c: Rewritten. + * grub-core/lib/mips/relocator_asm.S: Renamed variables and minor + stylistic adjustments. + * grub-core/lib/powerpc/relocator.c: New file. + * grub-core/lib/powerpc/relocator_asm.S: Likewise. + * grub-core/lib/relocator.c: Rewritten. + * grub-core/lib/x86_64/relocator_asm.S: New file. + * grub-core/loader/aout.c (grub_aout_load): Make load_addr a void *. + * grub-core/loader/i386/bsd.c (NETBSD_DEFAULT_VIDEO_MODE): New const. + (bsd_tag): New struct. + (tags): New variable. + (tags_last): Likewise. + (netbsd_module): New struct. + (netbsd_mods): New variable. + (netbsd_mods_last): Likewise. + (openbsd_opts): New parameter "serial". + (OPENBSD_SERIAL_ARG): New definition. + (netbsd_opts): New parameter "serial". + (NETBSD_SERIAL_ARG): New definition. + (grub_freebsd_add_meta): Reorganised into ... + (grub_bsd_add_meta): ...this. All users updated. + (grub_freebsd_add_mmap): Reorganised into ... + (generate_e820_mmap): ...this... + (grub_bsd_add_mmap): ...and this. All users updated. + (grub_freebsd_list_modules): Use tags. + (grub_netbsd_add_meta_module): New function. + (grub_netbsd_list_modules): Likewise. + (grub_freebsd_boot): Use relocator and finish EFI. + (grub_openbsd_boot): Likewise. + (grub_netbsd_setup_video): New function. + (grub_netbsd_add_modules): Likewise. + (grub_netbsd_boot): Use grub_netbsd_add_modules, relocator, netbsd_tags + and finish EFI. + (grub_bsd_unload): Unload tags. + (grub_bsd_load_aout): Use relocator. + (grub_bsd_elf32_size_hook): New function. + (grub_bsd_elf32_hook): Use relocator. + (grub_bsd_elf64_size_hook): New function. + (grub_bsd_elf64_hook): Use relocator. + (grub_bsd_load_elf): Use relocator and call grub_openbsd_find_ramdisk. + (grub_bsd_load): Zero-out openbsd_ramdisk. + (grub_bsd_load): Use relocator. + (grub_cmd_openbsd): Support serial. + (grub_cmd_netbsd): Support modules. + (grub_cmd_freebsd_module): Use relocator. + (grub_netbsd_module_load): New function. + (grub_cmd_netbsd_module): Likewise. + (grub_cmd_openbsd_ramdisk): Likewise. + (GRUB_MOD_INIT): Register knetbsd_module, knetbsd_module_elf and + kopenbsd_ramdisk. + (GRUB_MOD_FINI): Unregister new commands. + * grub-core/loader/i386/bsdXX.c (load): Remove useless checks. + (grub_freebsd_load_elfmodule_obj): Use relocator. + (grub_freebsd_load_elfmodule): Likewise. + (grub_freebsd_load_elf_meta): Likewise. + (grub_netbsd_load_elf_meta): New function. + (grub_openbsd_find_ramdisk): Likewise. + * grub-core/loader/i386/bsd_helper.S: Removed. + * grub-core/loader/i386/bsd_pagetable.c: Support relocator. + * grub-core/loader/i386/bsd_trampoline.S: Removed. + * grub-core/loader/i386/efi/linux.c: Likewise. + * grub-core/loader/i386/ieee1275/linux.c: Likewise. + * grub-core/loader/i386/linux.c (HAS_VGA_TEXT): New const. + (DEFAULT_VIDEO_MODE): Likewise. + (real_mode_target): New variable. + (prot_mode_target): Likewise. + (initrd_mem_target): Likewise. + (relocator): Likewise. + (efi_mmap_buf): Likewise. + (efi_mmap_size): Likewise. + (find_efi_mmap_size): Moved from grub-core/loader/i386/efi/linux.c. + (free_pages): Use relocator. + (allocate_pages): Account for efi_mmap and use relocator. Return error. + (grub_linux_setup_video): Return error. + (grub_linux_trampoline_start): Removed. + (grub_linux_trampoline_end): Likewise. + (grub_linux_boot): Use relocator and DEFAULT_VIDEO_MODE. Pass console + andd video parameters depending on firmware. + [GRUB_MACHINE_IEEE1275]: Pass OFW parameters. + [GRUB_MACHINE_EFI]: Pass EFI parameters. + (grub_cmd_linux) [GRUB_MACHINE_EFI]: Likewise. + (grub_cmd_initrd): Use relocator. + * grub-core/loader/i386/linux_trampoline.S: Removed. + * grub-core/loader/i386/multiboot_mbi.c (elf_sec_num): New variable. + (elf_sec_entsize): Likewise. + (elf_sec_shstrndx): Likewise. + (elf_sections): Likewise. + (grub_multiboot_load): Use relocator. + (grub_multiboot_get_mbi_size): Account for sections. + (grub_multiboot_make_mbi): Use relocator and support sections. + (grub_multiboot_add_elfsyms): New function. + (grub_multiboot_free_mbi): Free sections. + * grub-core/loader/i386/pc/linux.c (relocator): New variable. + (grub_linux_real_target): Likewise. + (grub_linux_real_chunk): Likewise. + (grub_linux16_prot_size): Likewise. + (grub_linux16_boot): Use relocator. + (grub_linux_unload): Unload relocator. + (grub_cmd_linux): Use relocator. + (grub_cmd_initrd): Likewise. + * grub-core/loader/i386/pc/ntldr.c: New file. + * grub-core/loader/i386/xnu.c (guessfsb) [GRUB_MACHINE_IEEE1275]: + Don't try to guess CPU frequency. + (grub_xnu_set_video): Stretch bitmap. + (grub_xnu_boot): Use relocator. + * grub-core/loader/mips/linux.c (grub_linux_boot): Use relocator. + (grub_linux_unload): Free relocator. + (grub_linux_load32): Use relocator. + (grub_linux_load64): Likewise. + (grub_cmd_initrd): Likewise. + * grub-core/loader/multiboot.c (grub_multiboot_boot): Use relocator. + (grub_multiboot_unload): Unload relocator. + (grub_cmd_multiboot): Use relocator. + (grub_cmd_module): Likewise. + * grub-core/loader/multiboot_elfxx.c (grub_multiboot_load_elfXX): + Use relocator and support sections. + * grub-core/loader/multiboot_mbi2.c(elf_sec_num): New variable. + (elf_sec_entsize): Likewise. + (elf_sec_shstrndx): Likewise. + (elf_sections): Likewise. + (grub_multiboot_load): Use relocator. + (grub_multiboot_get_mbi_size): Account for sections. + (grub_multiboot_make_mbi): Use relocator and support sections. + (grub_multiboot_add_elfsyms): New function. + * grub-core/loader/powerpc/ieee1275/linux.c: Remove useless include. + * grub-core/loader/sparc64/ieee1275/linux.c: Likewise. + * grub-core/loader/xnu.c (grub_xnu_heap_malloc): Use relocator. + Prototype changed. All users updated. + (grub_xnu_align_heap): Simplified. + (grub_xnu_writetree_toheap): Likewise. + (grub_xnu_unload): Unload relocator. + (grub_cmd_xnu_kernel): Use relocator. + (grub_cmd_xnu_kernel64): Likewise. + (grub_xnu_register_memory): Simplified. + * grub-core/loader/xnu_resume.c (grub_xnu_resume): Use relocator. + * grub-core/term/efi/console.c (grub_console_putchar): Abort if + EFI is finished. + (grub_console_checkkey): Likewise. + (grub_console_getkey): Likewise. + (grub_console_getwh): Likewise. + (grub_console_getxy): Likewise. + (grub_console_gotoxy): Likewise. + (grub_console_cls): Likewise. + (grub_console_setcolorstate): Likewise. + (grub_console_setcursor): Likewise. + * grub-core/term/ns8250.c (grub_ns8250_hw_get_port): New function. + * grub-core/tests/boot/kbsd.init-i386.S: New file. + * grub-core/tests/boot/kbsd.init-x86_64.S: Likewise. + * grub-core/tests/boot/kbsd.spec.txt: Likewise. + * grub-core/tests/boot/kernel-8086.S: Likewise. + * grub-core/tests/boot/kernel-i386.S: Likewise. + * grub-core/tests/boot/kfreebsd-aout.cfg: Likewise. + * grub-core/tests/boot/kfreebsd.cfg: Likewise. + * grub-core/tests/boot/kfreebsd.init-i386.S: Likewise. + * grub-core/tests/boot/kfreebsd.init-x86_64.S: Likewise. + * grub-core/tests/boot/knetbsd.cfg: Likewise. + * grub-core/tests/boot/kopenbsd.cfg: Likewise. + * grub-core/tests/boot/kopenbsdlabel.txt: Likewise. + * grub-core/tests/boot/linux.cfg: Likewise. + * grub-core/tests/boot/linux.init-i386.S: Likewise. + * grub-core/tests/boot/linux.init-x86_64.S: Likewise. + * grub-core/tests/boot/linux16.cfg: Likewise. + * grub-core/tests/boot/multiboot.cfg: Likewise. + * grub-core/tests/boot/multiboot2.cfg: Likewise. + * grub-core/tests/boot/ntldr.cfg: Likewise. + * grub-core/tests/boot/pc-chainloader.cfg: Likewise. + * include/grub/aout.h (grub_aout_load): Make load_addr a void *. + * include/grub/autoefi.h (grub_autoefi_finish_boot_services): + New definition. + * include/grub/dl.h (grub_dl_unload_all): Removed. + * include/grub/efi/efi.h (grub_efi_exit_boot_services): Likewise. + (grub_efi_finish_boot_services): Change prototype. + (grub_efi_is_finished): New variable. + * include/grub/efiemu/efiemu.h (grub_efiemu_finish_boot_services): + Changed prototype. + (grub_efiemu_finish_boot_services): Removed. + (grub_machine_efiemu_init_tables): New prototype. + * include/grub/elfload.h (grub_elf32_phdr_iterate): Likewise. + (grub_elf64_phdr_iterate): Likewise. + * include/grub/i386/bsd.h: Include relocator.h. + (freebsd_tag_header): New struct. + (grub_openbsd_bios_mmap): Removed. + (grub_unix_real_boot): Removed. + (grub_freebsd_load_elfmodule32): Changed prototype. + (grub_freebsd_load_elfmodule_obj64): Likewise. + (grub_freebsd_load_elf_meta32): Likewise. + (grub_freebsd_load_elf_meta64): Likewise. + (grub_freebsd_add_meta): Removed. + (grub_netbsd_load_elf_meta32): New prototype. + (grub_netbsd_load_elf_meta64): Likewise. + (grub_bsd_add_meta): Likewise. + (grub_openbsd_ramdisk_descriptor): New struct. + (grub_openbsd_find_ramdisk32): New prototype. + (grub_openbsd_find_ramdisk64): Likewise. + * include/grub/i386/coreboot/loader.h: Removed. + * include/grub/i386/efi/loader.h: Likewise. + * include/grub/i386/ieee1275/loader.h: Likewise. + * include/grub/i386/linux.h (linux_kernel_header): Change void * + to grub_uint32_t. + * include/grub/i386/loader.h: Removed. + * include/grub/i386/memory.h (GRUB_MEMORY_CPU_CR4_PAE_ON): Correct the + value. + (GRUB_MEMORY_CPU_CR4_PSE_ON): New definition. + (grub_phys_addr_t): New type. + (grub_vtop): New inline function. + (grub_map_memory): Likewise. + (grub_unmap_memory): Likewise. + * include/grub/i386/multiboot/loader.h: Removed. + * include/grub/i386/netbsd_bootinfo.h (NETBSD_BTINFO_BOOTDISK): Removed. + (NETBSD_BTINFO_CONSOLE): New definition. + (NETBSD_BTINFO_SYMTAB): Likewise. + (NETBSD_BTINFO_MODULES): Likewise. + (NETBSD_BTINFO_FRAMEBUF): Likewise. + (grub_netbsd_bootinfo): New struct. + (grub_netbsd_btinfo_common): Use explicit bitsize. + (grub_netbsd_btinfo_mmap_entry): Removed. + (GRUB_NETBSD_MAX_BOOTPATH_LEN): New definition. + (grub_netbsd_btinfo_bootdisk): New struct. + (grub_netbsd_btinfo_symtab): Likewise. + (grub_netbsd_btinfo_serial): Likewise. + (grub_netbsd_btinfo_modules): Likewise. + (grub_netbsd_btinfo_framebuf): Likewise. + (GRUB_NETBSD_MAX_ROOTDEVICE_LEN): New definition. + * include/grub/i386/openbsd_bootarg.h (OPENBSD_BOOTARG_CONSOLE): + Likewise. + (grub_openbsd_bootargs): Use explicit bitsize. + (grub_openbsd_bootarg_console): New struct. + (GRUB_OPENBSD_COM_MAJOR): New definition. + (GRUB_OPENBSD_VGA_MAJOR): Likewise. + * include/grub/i386/pc/efiemu.h: Removed. + * include/grub/i386/pc/loader.h: Don't include cpu/loader.h. + * include/grub/i386/qemu/loader.h: Removed. + * include/grub/i386/relocator.h: Rewritten. + * include/grub/i386/xnu.h (grub_xnu_heap_will_be_at): Removed. + * include/grub/mips/memory.h: New file. + * include/grub/mips/multiboot.h: Rewritten. + * include/grub/mips/relocator.h: Rewritten. + * include/grub/mips/yeeloong/memory.h (grub_phys_addr_t): New type. + (grub_vtop): New function. + (grub_map_memory): Likewise. + (grub_unmap_memory): Likewise. + * include/grub/misc.h (ALIGN_DOWN): New definition. + * include/grub/mm.h (grub_mm_check_real): New proto. + (GRUB_MM_CHECK): New definition. + * include/grub/mm_private.h: New file. + * include/grub/multiboot.h (grub_multiboot_relocator): New variable. + (grub_multiboot_get_mbi_size): Removed. + (grub_multiboot_make_mbi): Change prottype. + (grub_multiboot_set_accepts_video): New proto. + (grub_multiboot_add_elfsyms): Likewise. + (grub_multiboot_payload_eip): New variable. + * include/grub/ns8250.h (grub_ns8250_hw_get_port) [!ASM_FILE]: + New prototype. + * include/grub/offsets.h (GRUB_KERNEL_I386_MULTIBOOT_PREFIX): + New definition. + (GRUB_KERNEL_I386_MULTIBOOT_DATA_END): Likewise. + (GRUB_KERNEL_I386_MULTIBOOT_MOD_ALIGN): Likewise. + * include/grub/powerpc/ieee1275/loader.h: Removed. + * include/grub/powerpc/memory.h: New file. + * include/grub/powerpc/relocator.h: Likewise. + * include/grub/relocator.h: Likewise. + * include/grub/relocator_private.h: Likewise. + * include/grub/sparc64/ieee1275/loader.h: Removed. + * include/grub/x86_64/memory.h: New file. + * include/grub/xnu.h (grub_xnu_writetree_toheap): Changed prototype. + (grub_xnu_heap_malloc): Likewise. + (grub_xnu_heap_real_start): Removed. + (grub_xnu_heap_start): Likewise. + (grub_xnu_relocator): New variable. + (grub_xnu_heap_target_start): Likewise. + * tests/util/grub-shell.in: Support non-pc. + * util/grub-mkimage.c (image_targets): Fix multiboot target. + +2010-08-29 Vladimir Serbinenko + + * grub-core/normal/charset.c (grub_utf8_to_ucs4_alloc): Avoid deadloop + on malloc error. + (grub_bidi_logical_to_visual): Check that malloc succeded. + * grub-core/normal/term.c (grub_puts_terminal): Fix fallback to dumb + puts. + (grub_xputs_normal): Likewise. + +2010-08-29 Vladimir Serbinenko + + * grub-core/Makefile.core.def (kernel): Add kern/mips/cache_flush.S to + extra_dist. + +2010-08-29 Vladimir Serbinenko + + * grub-core/efiemu/runtime/efiemu.sh: Removed. + +2010-08-29 Vladimir Serbinenko + + * Makefile.util.def (grub-ofpathname): Add missing ldadd. + +2010-08-29 Vladimir Serbinenko + + * grub-core/kern/misc.c (grub_real_dprintf): Always refresh after + dprintf. + +2010-08-29 BVK Chaitanya + + * Makefile.util.def: Use ldadd instead of ldflags for libraries. + +2010-08-28 Vladimir Serbinenko + + * grub-core/normal/term.c (print_more): Fix a memory leak. + (grub_puts_terminal): Revert to dumb puts if memory allocation fails. + (grub_xputs_normal): Likewise. + +2010-08-28 Vladimir Serbinenko + + * grub-core/script/lexer.c (grub_script_lexer_init): Don't look before + the begining of the string + +2010-08-28 Vladimir Serbinenko + + * grub-core/script/script.c (grub_script_parse): Free parsed on + failure. + +2010-08-28 Vladimir Serbinenko + + * grub-core/normal/completion.c (grub_normal_do_completion): Free argv + on failure. + +2010-08-28 Vladimir Serbinenko + + * grub-core/normal/cmdline.c (grub_cmdline_get): Free cl_terms on + return. + +2010-08-28 Vladimir Serbinenko + + * grub-core/term/gfxterm.c (grub_gfxterm_term_fini): Free the text buffer. + (scroll_up): Fix a memory leak. + +2010-08-28 Vladimir Serbinenko + + * grub-core/fs/nilfs2.c (grub_nilfs2_load_sb): Handle grub_disk_read + errors. + 2010-08-27 Vladimir Serbinenko Handle USB pendrives exposed as floppies. diff --git a/INSTALL b/INSTALL index bbfa01f0a..e325fa2b2 100644 --- a/INSTALL +++ b/INSTALL @@ -21,7 +21,7 @@ configuring the GRUB. On GNU/Linux, you also need: -* libdevmapper (recommended) +* libdevmapper 1.02.34 or later (recommended) To build grub-emu, you need: diff --git a/Makefile.am b/Makefile.am index f49a92ead..1cf2297bd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -82,4 +82,223 @@ CLEANFILES += widthspec.h platform_HEADERS = config.h pkglib_DATA += grub-mkconfig_lib -pkglib_DATA += update-grub_lib \ No newline at end of file +pkglib_DATA += update-grub_lib + + +if COND_i386_coreboot +BOOTTARGET=coreboot +QEMU32=qemu-system-i386 +endif + +if COND_i386_multiboot +BOOTTARGET=cd +QEMU32=qemu-system-i386 +endif + +if COND_i386_ieee1275 +BOOTTARGET=cd +QEMU32=qemu-system-i386 +endif + +if COND_i386_qemu +BOOTTARGET=qemu +QEMU32=qemu-system-i386 +endif + +if COND_i386_pc +BOOTTARGET=cd +QEMU32=qemu-system-i386 +endif + +if COND_i386_efi +QEMU32=qemu-system-i386 +BOOTTARGET=cd +endif + +if COND_x86_64_efi +QEMU32=qemu-system-x86_64 +BOOTTARGET=cd +endif + +linux.init.x86_64: $(srcdir)/grub-core/tests/boot/linux.init-x86_64.S + $(TARGET_CC) -o $@ $< -m64 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +linux.init.i386: $(srcdir)/grub-core/tests/boot/linux.init-i386.S + $(TARGET_CC) -o $@ $< -m32 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +multiboot.elf: $(srcdir)/grub-core/tests/boot/kernel-i386.S + $(TARGET_CC) -o $@ $< -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -DTARGET_MULTIBOOT=1 -Wl,-N -Wl,-Ttext,0x100000 -m32 -I$(srcdir)/include + +kfreebsd.elf: $(srcdir)/grub-core/tests/boot/kernel-i386.S + $(TARGET_CC) -o $@ $< -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,-N -Wl,-Ttext,0x100000 -m32 -I$(srcdir)/include + +kfreebsd.aout: kfreebsd.elf + $(OBJCOPY) -O a.out-i386-linux $< $@ -R .note.gnu.build-id + +pc-chainloader.elf: $(srcdir)/grub-core/tests/boot/kernel-8086.S + $(TARGET_CC) -o $@ $< -DTARGET_CHAINLOADER=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,-N -Wl,-Ttext,0x7c00 -m32 + +pc-chainloader.bin: pc-chainloader.elf + $(OBJCOPY) -O binary --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .reginfo -R .rel.dyn $< $@; + +ntldr.elf: $(srcdir)/grub-core/tests/boot/kernel-8086.S + $(TARGET_CC) -o $@ $< -DTARGET_NTLDR=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,-N -Wl,-Ttext,0 -m32 + +ntldr.bin: ntldr.elf + $(OBJCOPY) -O binary --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .reginfo -R .rel.dyn $< $@; + +multiboot2.elf: $(srcdir)/grub-core/tests/boot/kernel-i386.S + $(TARGET_CC) -o $@ $< -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,-N -Wl,-Ttext,0x100000 -m32 -I$(srcdir)/include -DTARGET_MULTIBOOT2=1 + +kfreebsd.init.x86_64: $(srcdir)/grub-core/tests/boot/kfreebsd.init-x86_64.S + $(TARGET_CC) -o $@ $< -m64 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" && freebsd-brandelf -t FreeBSD $@ + +kfreebsd.init.i386: $(srcdir)/grub-core/tests/boot/kfreebsd.init-i386.S + $(TARGET_CC) -o $@ $< -m32 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" && freebsd-brandelf -t FreeBSD $@ + +knetbsd.init.i386: $(srcdir)/grub-core/tests/boot/kbsd.init-i386.S + $(TARGET_CC) -o $@ $< -m32 -nostdlib -nostdinc -DTARGET_NETBSD=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +kopenbsd.init.i386: $(srcdir)/grub-core/tests/boot/kbsd.init-i386.S + $(TARGET_CC) -o $@ $< -m32 -nostdlib -nostdinc -DTARGET_OPENBSD=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +knetbsd.init.x86_64: $(srcdir)/grub-core/tests/boot/kbsd.init-x86_64.S + $(TARGET_CC) -o $@ $< -m64 -DTARGET_NETBSD=1 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +kopenbsd.init.x86_64: $(srcdir)/grub-core/tests/boot/kbsd.init-x86_64.S + $(TARGET_CC) -o $@ $< -m64 -DTARGET_OPENBSD=1 -nostdlib -nostdinc -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" + +linux-initramfs.i386: linux.init.i386 Makefile + TDIR=`mktemp -d`; cp $< $$TDIR/init; (cd $$TDIR; echo ./init | cpio --quiet --dereference -o -H newc) | gzip > $@; rm -rf $$TDIR + +linux-initramfs.x86_64: linux.init.x86_64 Makefile + TDIR=`mktemp -d`; cp $< $$TDIR/init; (cd $$TDIR; echo ./init | cpio --quiet --dereference -o -H newc) | gzip > $@; rm -rf $$TDIR + +kfreebsd-mfsroot.i386.img: kfreebsd.init.i386 Makefile + TDIR=`mktemp -d`; mkdir $$TDIR/dev; mkdir $$TDIR/sbin; cp $< $$TDIR/sbin/init; makefs -t ffs -s 30m -f 1000 -o minfree=0,version=1 $@ $$TDIR; rm -rf $$TDIR + +knetbsd.image.i386: knetbsd.init.i386 $(srcdir)/grub-core/tests/boot/kbsd.spec.txt + TDIR=`mktemp -d` && mkdir $$TDIR/dev && mkdir $$TDIR/sbin && cp $< $$TDIR/sbin/init && makefs -F $(srcdir)/grub-core/tests/boot/kbsd.spec.txt -t ffs -s 64k -f 10 -o minfree=0,version=1 $@ $$TDIR && rm -rf $$TDIR + +kopenbsd.image.i386: kopenbsd.init.i386 $(srcdir)/grub-core/tests/boot/kopenbsdlabel.txt + TDIR=`mktemp -d` && mkdir $$TDIR/dev && mkdir $$TDIR/sbin && cp $< $$TDIR/sbin/init && makefs -F $(srcdir)/grub-core/tests/boot/kbsd.spec.txt -t ffs -s 128k -f 10 -o minfree=0,version=1 $@ $$TDIR && bsdlabel -f -R $@ $(srcdir)/grub-core/tests/boot/kopenbsdlabel.txt && rm -rf $$TDIR || rm -f $@ + +kopenbsd.image.x86_64: kopenbsd.init.x86_64 $(srcdir)/grub-core/tests/boot/kopenbsdlabel.txt + TDIR=`mktemp -d` && mkdir $$TDIR/dev && mkdir $$TDIR/sbin && cp $< $$TDIR/sbin/init && makefs -F $(srcdir)/grub-core/tests/boot/kbsd.spec.txt -t ffs -s 128k -f 10 -o minfree=0,version=1 $@ $$TDIR && bsdlabel -f -R $@ $(srcdir)/grub-core/tests/boot/kopenbsdlabel.txt && rm -rf $$TDIR || rm -f $@ + +knetbsd.miniroot-image.i386.img: knetbsd.image.i386 $(GRUB_PAYLOADS_DIR)/knetbsd.miniroot.i386 + $(OBJCOPY) --add-section=miniroot=$< $(GRUB_PAYLOADS_DIR)/knetbsd.miniroot.i386 $@ + +kfreebsd-mfsroot.x86_64.img: kfreebsd.init.x86_64 Makefile + TDIR=`mktemp -d`; mkdir $$TDIR/dev; mkdir $$TDIR/sbin; cp $< $$TDIR/sbin/init; makefs -t ffs -s 30m -f 1000 -o minfree=0,version=1 $@ $$TDIR; rm -rf $$TDIR + +knetbsd.image.x86_64: knetbsd.init.x86_64 $(srcdir)/grub-core/tests/boot/kbsd.spec.txt + TDIR=`mktemp -d` && mkdir $$TDIR/dev && mkdir $$TDIR/sbin && cp $< $$TDIR/sbin/init && makefs -F $(srcdir)/grub-core/tests/boot/kbsd.spec.txt -t ffs -s 64k -f 10 -o minfree=0,version=1 $@ $$TDIR && rm -rf $$TDIR + +knetbsd.miniroot-image.x86_64.img: knetbsd.image.x86_64 $(GRUB_PAYLOADS_DIR)/knetbsd.miniroot.x86_64 + $(OBJCOPY) --add-section=miniroot=$< $(GRUB_PAYLOADS_DIR)/knetbsd.miniroot.x86_64 $@ + +CLEANFILES += linux.init.i386 kfreebsd.init.i386 linux.init.x86_64 linux-initramfs.i386 linux-initramfs.x86_64 + +kfreebsd-mfsroot.i386.gz: kfreebsd-mfsroot.i386.img + gzip < $< > $@ + +bootcheck-kfreebsd-i386: kfreebsd-mfsroot.i386.gz $(GRUB_PAYLOADS_DIR)/kfreebsd.i386 $(GRUB_PAYLOADS_DIR)/kfreebsd_env.i386 $(srcdir)/grub-core/tests/boot/kfreebsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/mfsroot.gz=kfreebsd-mfsroot.i386.gz --files=/kfreebsd=$(GRUB_PAYLOADS_DIR)/kfreebsd.i386 --files=/kfreebsd_env=$(GRUB_PAYLOADS_DIR)/kfreebsd_env.i386 $(srcdir)/grub-core/tests/boot/kfreebsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +kfreebsd-mfsroot.x86_64.gz: kfreebsd-mfsroot.x86_64.img + gzip < $< > $@ + +bootcheck-kfreebsd-x86_64: kfreebsd-mfsroot.x86_64.gz $(GRUB_PAYLOADS_DIR)/kfreebsd.x86_64 $(GRUB_PAYLOADS_DIR)/kfreebsd_env.x86_64 $(srcdir)/grub-core/tests/boot/kfreebsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/mfsroot.gz=kfreebsd-mfsroot.x86_64.gz --files=/kfreebsd=$(GRUB_PAYLOADS_DIR)/kfreebsd.x86_64 --files=/kfreebsd_env=$(GRUB_PAYLOADS_DIR)/kfreebsd_env.x86_64 $(srcdir)/grub-core/tests/boot/kfreebsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +knetbsd.miniroot-image.i386.gz: knetbsd.miniroot-image.i386.img + gzip < $< > $@ + +bootcheck-knetbsd-i386: knetbsd.miniroot-image.i386.gz $(GRUB_PAYLOADS_DIR)/knetbsd.i386 $(srcdir)/grub-core/tests/boot/knetbsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/miniroot.gz=knetbsd.miniroot-image.i386.gz --files=/knetbsd=$(GRUB_PAYLOADS_DIR)/knetbsd.i386 $(srcdir)/grub-core/tests/boot/knetbsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-kopenbsd-i386: kopenbsd.image.i386 $(GRUB_PAYLOADS_DIR)/kopenbsd.i386 $(srcdir)/grub-core/tests/boot/kopenbsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/ramdisk=kopenbsd.image.i386 --files=/kopenbsd=$(GRUB_PAYLOADS_DIR)/kopenbsd.i386 $(srcdir)/grub-core/tests/boot/kopenbsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-kopenbsd-x86_64: kopenbsd.image.x86_64 $(GRUB_PAYLOADS_DIR)/kopenbsd.x86_64 $(srcdir)/grub-core/tests/boot/kopenbsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/ramdisk=kopenbsd.image.x86_64 --files=/kopenbsd=$(GRUB_PAYLOADS_DIR)/kopenbsd.x86_64 $(srcdir)/grub-core/tests/boot/kopenbsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +knetbsd.miniroot-image.x86_64.gz: knetbsd.miniroot-image.x86_64.img + gzip < $< > $@ + +bootcheck-knetbsd-x86_64: knetbsd.miniroot-image.x86_64.gz $(GRUB_PAYLOADS_DIR)/knetbsd.x86_64 $(srcdir)/grub-core/tests/boot/knetbsd.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/miniroot.gz=knetbsd.miniroot-image.x86_64.gz --files=/knetbsd=$(GRUB_PAYLOADS_DIR)/knetbsd.x86_64 $(srcdir)/grub-core/tests/boot/knetbsd.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-linux-i386: linux-initramfs.i386 $(GRUB_PAYLOADS_DIR)/linux.i386 $(srcdir)/grub-core/tests/boot/linux.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/initrd=linux-initramfs.i386 --files=/linux=$(GRUB_PAYLOADS_DIR)/linux.i386 $(srcdir)/grub-core/tests/boot/linux.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-linux-x86_64: linux-initramfs.x86_64 $(GRUB_PAYLOADS_DIR)/linux.x86_64 $(srcdir)/grub-core/tests/boot/linux.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/initrd=linux-initramfs.x86_64 --files=/linux=$(GRUB_PAYLOADS_DIR)/linux.x86_64 $(srcdir)/grub-core/tests/boot/linux.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-linux16-i386: linux-initramfs.i386 $(GRUB_PAYLOADS_DIR)/linux.i386 $(srcdir)/grub-core/tests/boot/linux.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/initrd=linux-initramfs.i386 --files=/linux=$(GRUB_PAYLOADS_DIR)/linux.i386 $(srcdir)/grub-core/tests/boot/linux16.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-linux16-x86_64: linux-initramfs.x86_64 $(GRUB_PAYLOADS_DIR)/linux.x86_64 $(srcdir)/grub-core/tests/boot/linux.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=qemu-system-x86_64 --files=/initrd=linux-initramfs.x86_64 --files=/linux=$(GRUB_PAYLOADS_DIR)/linux.x86_64 $(srcdir)/grub-core/tests/boot/linux16.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-multiboot: multiboot.elf $(srcdir)/grub-core/tests/boot/multiboot.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/multiboot.elf=multiboot.elf $(srcdir)/grub-core/tests/boot/multiboot.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-multiboot2: multiboot2.elf $(srcdir)/grub-core/tests/boot/multiboot2.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/multiboot2.elf=multiboot2.elf $(srcdir)/grub-core/tests/boot/multiboot2.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-kfreebsd-aout: kfreebsd.aout $(srcdir)/grub-core/tests/boot/kfreebsd-aout.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/kfreebsd.aout=kfreebsd.aout $(srcdir)/grub-core/tests/boot/kfreebsd-aout.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-pc-chainloader: pc-chainloader.bin $(srcdir)/grub-core/tests/boot/pc-chainloader.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/pc-chainloader.bin=pc-chainloader.bin $(srcdir)/grub-core/tests/boot/pc-chainloader.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +bootcheck-ntldr: ntldr.bin $(srcdir)/grub-core/tests/boot/ntldr.cfg grub-shell + timeout -s KILL $(BOOTCHECK_TIMEOUT) ./grub-shell --qemu-opts="$(GRUB_QEMU_OPTS)" --boot=$(BOOTTARGET) --qemu=$(QEMU32) --files=/ntldr.bin=ntldr.bin $(srcdir)/grub-core/tests/boot/ntldr.cfg | grep $(SUCCESSFUL_BOOT_STRING) > /dev/null + +BOOTCHECKS= + +if COND_i386_pc +#pc chainloader by definition is only for i386-pc +BOOTCHECKS += bootcheck-pc-chainloader +#ntldr and bootmgr require BIOS. +BOOTCHECKS += bootcheck-ntldr +#legacy protocol makes early BIOS calls. +BOOTCHECKS += bootcheck-linux16-i386 bootcheck-linux16-x86_64 +# Crashes early on non-BIOS +BOOTCHECKS += bootcheck-knetbsd-i386 +endif + +if !COND_i386_coreboot +# Crashes because memory at 0-0x1000 is occupied +BOOTCHECKS += bootcheck-knetbsd-x86_64 + +# Likewise and require ACPI. +if !COND_i386_multiboot +if !COND_i386_qemu +BOOTCHECKS += bootcheck-kfreebsd-x86_64 +BOOTCHECKS += bootcheck-kfreebsd-i386 +endif +endif +endif + +BOOTCHECKS += bootcheck-kfreebsd-aout + +BOOTCHECKS += bootcheck-kopenbsd-i386 bootcheck-kopenbsd-x86_64 + +BOOTCHECKS += bootcheck-multiboot bootcheck-multiboot2 + +BOOTCHECKS += bootcheck-linux-i386 bootcheck-linux-x86_64 + + +.PHONY: bootcheck-linux-i386 bootcheck-linux-x86_64 \ + bootcheck-kfreebsd-i386 bootcheck-kfreebsd-x86_64 \ + bootcheck-knetbsd-i386 bootcheck-knetbsd-x86_64 + +# Randomly generated +SUCCESSFUL_BOOT_STRING=3e49994fd5d82b7c9298d672d774080d +# tianocore cd access is very slow +BOOTCHECK_TIMEOUT=180 + +bootcheck: $(BOOTCHECKS) diff --git a/Makefile.util.def b/Makefile.util.def index b4f9fc60e..d3a4ac290 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -88,6 +88,7 @@ library = { common = grub-core/partmap/gpt.c; common = grub-core/partmap/msdos.c; common = grub-core/partmap/sun.c; + common = grub-core/partmap/sunpc.c; common = grub-core/script/function.c; common = grub-core/script/lexer.c; common = grub-core/script/main.c; @@ -99,7 +100,7 @@ program = { name = grub-bin2h; common = util/bin2h.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; mansection = 1; }; @@ -112,7 +113,7 @@ program = { extra_dist = util/grub-mkimagexx.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; cppflags = '-DGRUB_PKGLIBROOTDIR=\"$(pkglibrootdir)\"'; }; @@ -123,7 +124,7 @@ program = { common = util/grub-mkrelpath.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; }; program = { @@ -133,7 +134,7 @@ program = { common = util/grub-script-check.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; }; program = { @@ -143,7 +144,7 @@ program = { common = util/grub-editenv.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; }; program = { @@ -153,7 +154,7 @@ program = { common = util/grub-mkpasswd-pbkdf2.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; cflags = '$(CFLAGS_GCRY)'; cppflags = '$(CPPFLAGS_GCRY)'; }; @@ -171,7 +172,7 @@ program = { common = util/grub-pe2elf.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL)'; + ldadd = '$(LIBINTL)'; condition = COND_GRUB_PE2ELF; }; @@ -181,7 +182,7 @@ program = { common = util/grub-fstest.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; condition = COND_GRUB_FSTEST; }; @@ -194,8 +195,8 @@ program = { cflags = '$(freetype_cflags)'; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER)'; - ldflags = '$(freetype_libs)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER)'; + ldadd = '$(freetype_libs)'; condition = COND_GRUB_MKFONT; }; @@ -212,7 +213,7 @@ program = { sparc64_ieee1275 = util/ieee1275/devicemap.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)'; }; program = { @@ -222,7 +223,7 @@ program = { common = util/grub-probe.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)'; }; program = { @@ -239,7 +240,7 @@ program = { sparc64_ieee1275 = util/lvm.c; ldadd = libgrub.a; - ldflags = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)'; enable = i386_pc; enable = sparc64_ieee1275; @@ -252,6 +253,7 @@ program = { ieee1275 = util/ieee1275/ofpath.c; ldadd = libgrub.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL)'; enable = sparc64_ieee1275; }; @@ -329,11 +331,12 @@ script = { script = { mansection = 1; name = grub-mkrescue; - x86_noieee1275 = util/grub-mkrescue.in; + x86 = util/grub-mkrescue.in; powerpc_ieee1275 = util/powerpc/ieee1275/grub-mkrescue.in; enable = i386_pc; enable = x86_efi; enable = i386_qemu; + enable = i386_multiboot; enable = i386_coreboot; enable = powerpc_ieee1275; }; @@ -344,15 +347,17 @@ script = { name = grub-install; mips = util/grub-install.in; - i386_noefi_noieee1275 = util/grub-install.in; + i386_pc = util/grub-install.in; + i386_qemu = util/grub-install.in; + i386_coreboot = util/grub-install.in; + i386_multiboot = util/grub-install.in; + sparc64_ieee1275 = util/grub-install.in; x86_efi = util/i386/efi/grub-install.in; i386_ieee1275 = util/ieee1275/grub-install.in; powerpc_ieee1275 = util/ieee1275/grub-install.in; - enable = x86; - enable = mips; - enable = powerpc_ieee1275; + enable = noemu; }; script = { @@ -496,6 +501,36 @@ script = { common = tests/grub_script_shift.in; }; +script = { + testcase; + name = grub_script_blockarg; + common = tests/grub_script_blockarg.in; +}; + +script = { + testcase; + name = grub_script_setparams; + common = tests/grub_script_setparams.in; +}; + +script = { + testcase; + name = grub_script_return; + common = tests/grub_script_return.in; +}; + +script = { + testcase; + name = grub_cmd_regexp; + common = tests/grub_cmd_regexp.in; +}; + +script = { + testcase; + name = grub_script_expansion; + common = tests/grub_script_expansion.in; +}; + program = { testcase; name = example_unit_test; @@ -506,7 +541,7 @@ program = { common = grub-core/tests/lib/test.c; cflags = -Wno-format; ldadd = libgrub.a; - ldflags = '$(LIBDEVMAPPER)'; + ldadd = '$(LIBDEVMAPPER)'; }; program = { diff --git a/NEWS b/NEWS index 1e3334f18..bb6b8df3f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,98 @@ +New in 1.99: + +* New relocator. Allows for more kernel support and more + straightforward loader writing. + +* Handle USB pendrives exposed as floppies. + +* New Automake-based build system. + +* Add `sendkey' command (i386-pc only). + +* ZFS support in `grub-install' and `grub-mkconfig'. Note: complete + functionality requires external ZFS implementation (available from + grub-extras). + +* Support 1.x versions of mdadm metadata. + +* Fix corruption when reading Reiserfs directory entries. + +* Bidirectional text and diacritics support. + +* Skip LVM snapshots. + +* MIPS Yeeloong firmware port. + +* Change grub-mkdevicemap to emit /dev/disk/by-id/ names where possible + on GNU/Linux. + +* Add `grub-mkconfig' support for Xen with Linux. + +* Add `grub-mkconfig' support for initrd images on Fedora 13. + +* Support >3GiB and <16MiB RAM in i386-qemu. + +* Add support for Cirrus 5446 and Bochs video cards. + +* Load more appropriate video drivers automatically in `grub-mkconfig'. + +* USB improvements, including hotplugging/hotunplugging, hub support, + and USB serial support. + +* AMD Geode CS5536 support. + +* Extensive updates to the Texinfo documentation. + +* Add `grub-probe' support for the btrfs filesystem, permitting / to + reside on btrfs as long as /boot is on a filesystem natively supported + by GRUB. + +* Handle symbolic links under /dev/mapper on GNU/Linux. + +* Handle installation across multiple partition table types. + +* Add `cmostest' command (i386/x86_64 only). + +* Add support for DM-RAID disk devices on GNU/Linux. + +* Remove `grub-mkisofs'. `grub-mkrescue' now uses GNU xorriso to build + CD images. + +* `grub-mkrescue' support for EFI, coreboot, and QEMU platforms. + +* Unify `grub-mkimage' source code across platforms. + +* Fix VGA (as opposed to VBE) video driver, formerly a terminal driver. + +* Add menu hotkey support. + +* Add support for the nilfs2 filesystem. + +* `grub-probe' and `grub-mkconfig' support for NetBSD. + +* Support setting a background image in `grub-mkconfig'. + +* Support multiple terminals in `grub-mkconfig'. + +* Regexp support. + +* MIPS multiboot2 support. + +* Multiboot2 tag support. + +* sunpc partition table support. + +* Add a number of new language features to GRUB script: `for', `while', + `until', `elif', function parameters, `break', `continue', and + `shift'. + +* Support nested partition tables. GRUB now prefers to name partitions + in the form `(hd0,msdos1,bsd1)' rather than `(hd0,1,a)'. + +* Speed up consecutive hostdisk operations on the same device. + +* Compile parts of `grub-emu' as modules. + New in 1.98 - 2010-03-06: * Multiboot on EFI support. diff --git a/conf/Makefile.common b/conf/Makefile.common index eb70f7f77..fca0f67ae 100644 --- a/conf/Makefile.common +++ b/conf/Makefile.common @@ -31,7 +31,7 @@ endif # Other options -CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir),,$<)\" +CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir)/,,$<)\" CPPFLAGS_DEFAULT += -I$(builddir) CPPFLAGS_DEFAULT += -I$(srcdir) CPPFLAGS_DEFAULT += -I$(top_builddir) @@ -115,6 +115,7 @@ pkglib_SCRIPTS = noinst_PROGRAMS = grubconf_SCRIPTS = noinst_LIBRARIES = +dist_noinst_DATA = TESTS = EXTRA_DIST = diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist index 3acef7af7..afedc7d28 100644 --- a/conf/Makefile.extra-dist +++ b/conf/Makefile.extra-dist @@ -5,6 +5,11 @@ EXTRA_DIST += gentpl.py EXTRA_DIST += Makefile.tpl EXTRA_DIST += Makefile.util.def +EXTRA_DIST += unicode + +EXTRA_DIST += util/import_gcry.py +EXTRA_DIST += util/import_unicode.py + EXTRA_DIST += docs/man EXTRA_DIST += docs/grub.cfg @@ -26,8 +31,8 @@ EXTRA_DIST += grub-core/genterminallist.sh EXTRA_DIST += grub-core/genparttoollist.sh EXTRA_DIST += grub-core/genemuinitheader.sh +EXTRA_DIST += grub-core/lib/libgcrypt/cipher EXTRA_DIST += $(shell find $(top_srcdir)/include -name '*.h') EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/gnulib -name '*.h') EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/efiemu -name '*.h') -EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib/posix_wrap -name '*.h') -EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib/libgcrypt_wrap -name '*.h') +EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib -name '*.h') diff --git a/configure.ac b/configure.ac index dd2e82e3b..d362f68a5 100644 --- a/configure.ac +++ b/configure.ac @@ -586,6 +586,12 @@ AC_ARG_ENABLE([efiemu], if test x"$enable_efiemu" = xno ; then efiemu_excuse="explicitly disabled" fi +if test x"$target_cpu" != xi386 ; then + efiemu_excuse="only available on i386" +fi +if test x"$platform" = xefi ; then + efiemu_excuse="not available on efi" +fi if test x"$efiemu_excuse" = x ; then AC_CACHE_CHECK([whether options required for efiemu work], grub_cv_cc_efiemu, [ CFLAGS="$CFLAGS -m64 -mcmodel=large -mno-red-zone -nostdlib" @@ -816,12 +822,23 @@ fi if test x"$device_mapper_excuse" = x ; then # Check for device-mapper library. - AC_CHECK_LIB([devmapper], [dm_task_create], - [LIBDEVMAPPER="-ldevmapper" - AC_DEFINE([HAVE_DEVICE_MAPPER], [1], - [Define to 1 if you have the devmapper library.])], + AC_CHECK_LIB([devmapper], [dm_task_create], [], [device_mapper_excuse="need devmapper library"]) fi + +if test x"$device_mapper_excuse" = x ; then + # Check for device-mapper library. + AC_CHECK_LIB([devmapper], [dm_log_with_errno_init], + [], + [device_mapper_excuse="need devmapper library"]) +fi + +if test x"$device_mapper_excuse" = x ; then + LIBDEVMAPPER="-ldevmapper"; + AC_DEFINE([HAVE_DEVICE_MAPPER], [1], + [Define to 1 if you have the devmapper library.]) +fi + AC_SUBST([LIBDEVMAPPER]) AC_CHECK_LIB([zfs], [libzfs_init], @@ -836,6 +853,8 @@ AC_CHECK_LIB([nvpair], [nvlist_print], [Define to 1 if you have the NVPAIR library.])],) AC_SUBST([LIBNVPAIR]) +LIBS="" + pkglibrootdir='$(libdir)'/`echo $PACKAGE | sed "$program_transform_name"` AC_SUBST(pkglibrootdir) @@ -936,6 +955,11 @@ else echo PCI support for grub-emu: No "($grub_emu_pci_excuse)" fi fi +if test x"$device_mapper_excuse" = x ; then +echo With devmapper support: Yes +else +echo With devmapper support: No "($device_mapper_excuse)" +fi if [ x"$enable_mm_debug" = xyes ]; then echo With memory debugging: Yes else diff --git a/docs/grub.texi b/docs/grub.texi index f533a029c..80c6e50db 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -46,6 +46,8 @@ Invariant Sections. @subtitle The GRand Unified Bootloader, version @value{VERSION}, @value{UPDATED}. @author Gordon Matzigkeit @author Yoshinori K. Okuji +@author Colin Watson +@author Colin D. Bennett @c The following two commands start the copyright page. @page @vskip 0pt plus 1filll @@ -77,6 +79,7 @@ This edition documents version @value{VERSION}. * Installation:: Installing GRUB on your drive * Booting:: How to boot different operating systems * Configuration:: Writing your own configuration file +* Theme file format:: Format of GRUB theme files * Network:: Downloading OS images from a network * Serial terminal:: Using GRUB via a serial line * Vendor power-on keys:: Changing GRUB behaviour on vendor power-on keys @@ -85,6 +88,7 @@ This edition documents version @value{VERSION}. * Interface:: The menu and the command-line * Commands:: The list of available builtin commands * Security:: Authentication and authorisation +* Supported kernels:: The list of supported kernels * Troubleshooting:: Error messages produced by GRUB * Invoking grub-install:: How to use the GRUB installer * Invoking grub-mkconfig:: Generate a GRUB configuration file @@ -963,7 +967,6 @@ need to write the whole thing by hand. * Simple configuration:: Recommended for most users * Shell-like scripting:: For power users and developers * Embedded configuration:: Embedding a configuration file into GRUB -* Themes:: Graphical menu themes @end menu @@ -1125,7 +1128,6 @@ The image will be scaled if necessary to fit the screen. @item GRUB_THEME Set a theme for use with the @samp{gfxterm} graphical terminal. -@xref{Themes}. @item GRUB_GFXPAYLOAD_LINUX Set to @samp{text} to force the Linux kernel to boot in normal text mode, @@ -1371,9 +1373,372 @@ fi The embedded configuration file may not contain menu entries directly, but may only read them from elsewhere using @command{configfile}. +@node Theme file format +@chapter Theme file format +@section Introduction +The GRUB graphical menu supports themes that can customize the layout and +appearance of the GRUB boot menu. The theme is configured through a plain +text file that specifies the layout of the various GUI components (including +the boot menu, timeout progress bar, and text messages) as well as the +appearance using colors, fonts, and images. Example is available in docs/example_theme.txt + +@section Theme Elements +@subsection Colors + +Colors can be specified in several ways: + +@itemize +@item HTML-style ``#RRGGBB'' or ``#RGB'' format, where *R*, *G*, and *B* are hexadecimal digits (e.g., ``#8899FF'') +@item as comma-separated decimal RGB values (e.g., ``128, 128, 255'') +@item with ``SVG 1.0 color names'' (e.g., ``cornflowerblue'') which must be specified in lowercase. +@end itemize +@subsection Fonts +The fonts GRUB uses ``PFF2 font format'' bitmap fonts. Fonts are specified +with full font names. Currently there is no +provision for a preference list of fonts, or deriving one font from another. +Fonts are loaded with the ``loadfont'' command in GRUB. To see the list of +loaded fonts, execute the ``lsfonts'' command. If there are too many fonts to +fit on screen, do ``set pager=1'' before executing ``lsfonts''. + + +@subsection Progress Bar + +@float Figure, Pixmap-styled progress bar +@c @image{Theme_progress_bar,,,,.png} +@end float + +@float Figure, Plain progress bar, drawn with solid color. +@c @image{Theme_progress_bar_filled,,,,.png} +@end float + +Progress bars are used to display the remaining time before GRUB boots the +default menu entry. To create a progress bar that will display the remaining +time before automatic boot, simply create a ``progress_bar'' component with +the id ``__timeout__''. This indicates to GRUB that the progress bar should +be updated as time passes, and it should be made invisible if the countdown to +automatic boot is interrupted by the user. + +Progress bars may optionally have text displayed on them. This is controlled +through the ``show_text'' property, which can be set to either ``true'' or +``false'' to control whether text is displayed. When GRUB is counting down to +automatic boot, the text informs the user of the number of seconds remaining. + + +@subsection Circular Progress Indicator + +@c @image{Theme_circular_progress,,,,.png} + +The circular progress indicator functions similarly to the progress bar. When +given an id of ``__timeout__'', GRUB updates the circular progress indicator's +value to indicate the time remaining. For the circular progress indicator, +there are two images used to render it: the *center* image, and the *tick* +image. The center image is rendered in the center of the component, while the +tick image is used to render each mark along the circumference of the +indicator. + + +@subsection Labels + +Text labels can be placed on the boot screen. The font, color, and horizontal +alignment can be specified for labels. If a label is given the id +``__timeout__'', then the ``text'' property for that label is also updated +with a message informing the user of the number of seconds remaining until +automatic boot. This is useful in case you want the text displayed somewhere +else instead of directly on the progress bar. + + +@subsection Boot Menu + +@c @image{Theme_boot_menu,,,,.png} + +The boot menu where GRUB displays the menu entries from the ``grub.cfg'' file. +It is a list of items, where each item has a title and an optional icon. The +icon is selected based on the *classes* specified for the menu entry. If +there is a PNG file named ``myclass.png'' in the ``grub/themes/icons'' +directory, it will be displayed for items which have the class *myclass*. The +boot menu can be customized in several ways, such as the font and color used +for the menu entry title, and by specifying styled boxes for the menu itself +and for the selected item highlight. + + +@subsection Styled Boxes + +One of the most important features for customizing the layout is the use of + *styled boxes*. A styled box is composed of 9 rectangular (and potentially +empty) regions, which are used to seamlessly draw the styled box on screen: + +@multitable @columnfractions 0.3 0.3 0.3 +@item Northwest (nw) @tab North (n) @tab Northeast (ne) +@item West (w) @tab Center (c) @tab East (e) +@item Southwest (sw) @tab South (s) @tab Southeast (se) +@end multitable + +To support any size of box on screen, the center slice and the slices for the +top, bottom, and sides are all scaled to the correct size for the component on +screen, using the following rules: + +@enumerate +@item The edge slices (north, south, east, and west) are scaled in the direction of the edge they are adjacent to. For instance, the west slice is scaled vertically. +@item The corner slices (northwest, northeast, southeast, and southwest) are not scaled. +@item The center slice is scaled to fill the remaining space in the middle. +@end enumerate + +As an example of how an image might be sliced up, consider the styled box +used for a terminal view. + +@float Figure, An example of the slices (in red) used for a terminal window. This drawing was created and sliced in Inkscape_, as the next section explains. +@c @image{Box_slice_example_terminal,,,,.png} +@end float + +@subsection Creating Styled Box Images + +The Inkscape_ scalable vector graphics editor is a very useful tool for +creating styled box images. One process that works well for slicing a drawing +into the necessary image slices is: + +@enumerate +@item Create or open the drawing you'd like use. +@item Create a new layer on the top of the layer stack. Make it visible. Select this layer as the current layer. +@item Draw 9 rectangles on your drawing where you'd like the slices to be. Clear the fill option, and set the stroke to 1 pixel wide solid stroke. The corners of the slices must meet precisely; if it is off by a single pixel, it will probably be evident when the styled box is rendered in the GRUB menu. You should probably go to File | Document Properties | Grids and enable a grid or create a guide (click on one of the rulers next to the drawing and drag over the drawing; release the mouse button to place the guide) to help place the rectangles precisely. +@item Right click on the center slice rectangle and choose Object Properties. Change the "Id" to ``slice_c`` and click Set. Repeat this for the remaining 8 rectangles, giving them Id values of ``slice_n``, ``slice_ne``, ``slice_e``, and so on according to the location. +@item Save the drawing. +@item Select all the slice rectangles. With the slice layer selected, you can simply press Ctrl+A to select all rectangles. The status bar should indicate that 9 rectangles are selected. +@item Click the layer hide icon for the slice layer in the layer palette. The rectangles will remain selected, even though they are hidden. +@item Choose File | Export Bitmap and check the *Batch export 9 selected objects* box. Make sure that *Hide all except selected* is unchecked. click *Export*. This will create PNG files in the same directory as the drawing, named after the slices. These can now be used for a styled box in a GRUB theme. +@end enumerate + +@section Theme File Manual + +The theme file is a plain text file. Lines that begin with ``#`` are ignored +and considered comments. (Note: This may not be the case if the previous line +ended where a value was expected.) + +The theme file contains two types of statements: +@enumerate +@item Global properties. +@item Component construction. +@end enumerate + +@subsection Global Properties + +@subsection Format + +Global properties are specified with the simple format: +@itemize +@item name1: value1 +@item name2: "value which may contain spaces" +@item name3: #88F +@end itemize + +In this example, name3 is assigned a color value. + + +@subsection Global Property List + +@multitable @columnfractions 0.3 0.6 +@item title-text @tab Specifies the text to display at the top center of the screen as a title. +@item title-font @tab Defines the font used for the title message at the top of the screen. +@item title-color @tab Defines the color of the title message. +@item message-font @tab Defines the font used for messages, such as when GRUB is unable to automatically boot an entry. +@item message-color @tab Defines the color of the message text. +@item message-bg-color @tab Defines the background color of the message text area. +@item desktop-image @tab Specifies the image to use as the background. It will be scaled to fit the screen size. +@item desktop-color @tab Specifies the color for the background if *desktop-image* is not specified. +@item terminal-box @tab Specifies the file name pattern for the styled box slices used for the command line terminal window. For example, ``terminal-box: terminal_*.png'' will use the images ``terminal_c.png`` as the center area, ``terminal_n.png`` as the north (top) edge, ``terminal_nw.png`` as the northwest (upper left) corner, and so on. If the image for any slice is not found, it will simply be left empty. +@end multitable + + +@subsection Component Construction + +Greater customizability comes is provided by components. A tree of components +forms the user interface. *Containers* are components that can contain other +components, and there is always a single root component which is an instance +of a *canvas* container. + +Components are created in the theme file by prefixing the type of component +with a '+' sign: + +@code{ + label @{ text="GRUB" font="aqui 11" color="#8FF" @} } + +properties of a component are specified as "name = value" (whitespace +surrounding tokens is optional and is ignored) where *value* may be: +@itemize +@item a single word (e.g., ``align = center``, ``color = #FF8080``), +@item a quoted string (e.g., ``text = "Hello, World!"``), or +@item a tuple (e.g., ``preferred_size = (120, 80)``). +@end itemize + +@subsection Component List + +The following is a list of the components and the properties they support. + +@itemize +@item label + A label displays a line of text. + + Properties: + @multitable @columnfractions 0.2 0.7 + @item text @tab The text to display. + @item font @tab The font to use for text display. + @item color @tab The color of the text. + @item align @tab The horizontal alignment of the text within the component. Options are ``left``, ``center``, and ``right``. + @end multitable + +@item image + A component that displays an image. The image is scaled to fit the + component, although the preferred size defaults to the image's original + size unless the ``preferred_size`` property is explicitly set. + + Properties: + + @multitable @columnfractions 0.2 0.7 + @item file @tab The full path to the image file to load. + @end multitable + +@item progress_bar + Displays a horizontally oriented progress bar. It can be rendered using + simple solid filled rectangles, or using a pair of pixmap styled boxes. + + Properties: + + @multitable @columnfractions 0.2 0.7 + @item fg_color @tab The foreground color for plain solid color rendering. + @item bg_color @tab The background color for plain solid color rendering. + @item border_color @tab The border color for plain solid color rendering. + @item text_color @tab The text color. + @item show_text @tab Boolean value indicating whether or not text should be displayed on the progress bar. If set to *false*, then no text will be displayed on the bar. If set to any other value, text will be displayed on the bar. + @item bar_style @tab The styled box specification for the frame of the progress bar. Example: ``progress_frame_*.png`` + @item highlight_style @tab The styled box specification for the highlighted region of the progress bar. This box will be used to paint just the highlighted region of the bar, and will be increased in size as the bar nears completion. Example: ``progress_hl_*.png``. + @item text @tab The text to display on the progress bar. If the progress bar's ID is set to ``__timeout__``, then GRUB will updated this property with an informative message as the timeout approaches. + @item value @tab The progress bar current value. Normally not set manually. + @item start @tab The progress bar start value. Normally not set manually. + @item end @tab The progress bar end value. Normally not set manually. + @end multitable + +@item circular_progress + Displays a circular progress indicator. The appearance of this component + is determined by two images: the *center* image and the *tick* image. The + center image is generally larger and will be drawn in the center of the + component. Around the circumference of a circle within the component, the + tick image will be drawn a certain number of times, depending on the + properties of the component. + + Properties: + + @multitable @columnfractions 0.3 0.6 + @item center_bitmap + @tab The file name of the image to draw in the center of the component. + @item tick_bitmap + @tab The file name of the image to draw for the tick marks. + @item num_ticks + @tab The number of ticks that make up a full circle. + @item ticks_disappear + @tab Boolean value indicating whether tick marks should progressively appear, + or progressively disappear as *value* approaches *end*. Specify + ``true`` or ``false``. + @item value + @tab The progress indicator current value. Normally not set manually. + @item start + @tab The progress indicator start value. Normally not set manually. + @item end + @tab The progress indicator end value. Normally not set manually. + @end multitable +@item boot_menu + Displays the GRUB boot menu. It allows selecting items and executing them. + + Properties: + + @multitable @columnfractions 0.4 0.5 + @item item_font + @tab The font to use for the menu item titles. + @item selected_item_font + @tab The font to use for the selected menu item, or ``inherit`` (the default) + to use ``item_font`` for the selected menu item as well. + @item item_color + @tab The color to use for the menu item titles. + @item selected_item_color + @tab The color to use for the selected menu item, or ``inherit`` (the default) + to use ``item_color`` for the selected menu item as well. + @item icon_width + @tab The width of menu item icons. Icons are scaled to the specified size. + @item icon_height + @tab The height of menu item icons. + @item item_height + @tab The height of each menu item in pixels. + @item item_padding + @tab The amount of space in pixels to leave on each side of the menu item + contents. + @item item_icon_space + @tab The space between an item's icon and the title text, in pixels. + @item item_spacing + @tab The amount of space to leave between menu items, in pixels. + @item menu_pixmap_style + @tab The image file pattern for the menu frame styled box. + Example: ``menu_*.png`` (this will use images such as ``menu_c.png``, + ``menu_w.png``, `menu_nw.png``, etc.) + @item selected_item_pixmap_style + @tab The image file pattern for the selected item highlight styled box. + @item scrollbar + @tab Boolean value indicating whether the scroll bar should be drawn if the + frame and thumb styled boxes are configured. + @item scrollbar_frame + @tab The image file pattern for the entire scroll bar. + Example: ``scrollbar_*.png`` + @item scrollbar_thumb + @tab The image file pattern for the scroll bar thumb (the part of the scroll + bar that moves as scrolling occurs). + Example: ``scrollbar_thumb_*.png`` + @item max_items_shown + @tab The maximum number of items to show on the menu. If there are more than + *max_items_shown* items in the menu, the list will scroll to make all + items accessible. + @end multitable + +@item canvas + Canvas is a container that allows manual placement of components within it. + It does not alter the positions of its child components. It assigns all + child components their preferred sizes. + +@item hbox + The *hbox* container lays out its children from left to right, giving each + one its preferred width. The height of each child is set to the maximum of + the preferred heights of all children. + +@item vbox + The *vbox* container lays out its children from top to bottom, giving each + one its preferred height. The width of each child is set to the maximum of + the preferred widths of all children. +@end itemize + + +@subsection Common properties + +The following properties are supported by all components: +@table @samp +@item left + The distance from the left border of container to left border of the object in either of three formats: + @multitable @columnfractions 0.2 0.7 + @item x @tab Value in pixels + @item p% @tab Percentage + @item p%+x @tab mixture of both + @end multitable +@item top + The distance from the left border of container to left border of the object in same format. +@item width + The width of object in same format. +@item height + The height of object in same format. +@item id + The identifier for the component. This can be any arbitrary string. + The ID can be used by scripts to refer to various components in the GUI + component tree. Currently, there is one special ID value that GRUB + recognizes: + + @multitable @columnfractions 0.2 0.7 + @item ``__timeout__`` @tab Any component with this ID will have its *text*, *start*, *end*, *value*, and *visible* properties set by GRUB when it is counting down to an automatic boot of the default menu entry. + @end multitable +@end table -@node Themes -@section Graphical menu themes @node Network @@ -1435,7 +1800,7 @@ The boot file name provided by DHCP. Read-only. The name of the DHCP server responsible for these boot parameters. Read-only. -@item net_pxe_blksize +@item pxe_blksize The PXE transfer block size. Read-write, defaults to 512. @item pxe_default_server @@ -2862,6 +3227,145 @@ adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2} commands. +@node Supported kernels +@chapter Supported boot targets + +X86 support is summarised in following table. ``Yes'' means that kernel works on the given platform, ``crashes'' means an early kernel crash which we hove will be fixed by concerned kernel developpers. ``no'' means GRUB doesn't load given kernel on a given platform. ``headless'' means that the kernel works but lacks console drivers (you can still use serial or network console). In case of ``no'' and ``crashes'' the reason is given in footnote. +@multitable @columnfractions .50 .22 .22 +@item @tab BIOS @tab Coreboot +@item BIOS chainloading @tab yes @tab no (1) +@item NTLDR @tab yes @tab no (1) +@item FreeBSD bootloader @tab yes @tab crashes (1) +@item 32-bit kFreeBSD @tab yes @tab crashes (2,6) +@item 64-bit kFreeBSD @tab yes @tab crashes (2,6) +@item 32-bit kNetBSD @tab yes @tab crashes (1) +@item 64-bit kNetBSD @tab yes @tab crashes (2) +@item 32-bit kOpenBSD @tab yes @tab yes +@item 64-bit kOpenBSD @tab yes @tab yes +@item Multiboot @tab yes @tab yes +@item Multiboot2 @tab yes @tab yes +@item 32-bit Linux (legacy protocol) @tab yes @tab no (1) +@item 64-bit Linux (legacy protocol) @tab yes @tab no (1) +@item 32-bit Linux (modern protocol) @tab yes @tab yes +@item 64-bit Linux (modern protocol) @tab yes @tab yes +@item 32-bit XNU @tab yes @tab ? +@item 64-bit XNU @tab yes @tab ? +@item 32-bit EFI chainloader @tab no (3) @tab no (3) +@item 64-bit EFI chainloader @tab no (3) @tab no (3) +@item Appleloader @tab no (3) @tab no (3) +@end multitable + +@multitable @columnfractions .50 .22 .22 +@item @tab Multiboot @tab Qemu +@item BIOS chainloading @tab no (1) @tab no (1) +@item NTLDR @tab no (1) @tab no (1) +@item FreeBSD bootloader @tab crashes (1) @tab crashes (1) +@item 32-bit kFreeBSD @tab crashes (6) @tab crashes (6) +@item 64-bit kFreeBSD @tab crashes (6) @tab crashes (6) +@item 32-bit kNetBSD @tab crashes (1) @tab crashes (1) +@item 64-bit kNetBSD @tab yes @tab yes +@item 32-bit kOpenBSD @tab yes @tab yes +@item 64-bit kOpenBSD @tab yes @tab yes +@item Multiboot @tab yes @tab yes +@item Multiboot2 @tab yes @tab yes +@item 32-bit Linux (legacy protocol) @tab no (1) @tab no (1) +@item 64-bit Linux (legacy protocol) @tab no (1) @tab no (1) +@item 32-bit Linux (modern protocol) @tab yes @tab yes +@item 64-bit Linux (modern protocol) @tab yes @tab yes +@item 32-bit XNU @tab ? @tab ? +@item 64-bit XNU @tab ? @tab ? +@item 32-bit EFI chainloader @tab no (3) @tab no (3) +@item 64-bit EFI chainloader @tab no (3) @tab no (3) +@item Appleloader @tab no (3) @tab no (3) +@end multitable + +@multitable @columnfractions .50 .22 .22 +@item @tab 32-bit EFI @tab 64-bit EFI +@item BIOS chainloading @tab no (1) @tab no (1) +@item NTLDR @tab no (1) @tab no (1) +@item FreeBSD bootloader @tab crashes (1) @tab crashes (1) +@item 32-bit kFreeBSD @tab headless @tab headless +@item 64-bit kFreeBSD @tab headless @tab headless +@item 32-bit kNetBSD @tab crashes (1) @tab crashes (1) +@item 64-bit kNetBSD @tab yes @tab yes +@item 32-bit kOpenBSD @tab headless @tab headless +@item 64-bit kOpenBSD @tab headless @tab headless +@item Multiboot @tab yes @tab yes +@item Multiboot2 @tab yes @tab yes +@item 32-bit Linux (legacy protocol) @tab no (1) @tab no (1) +@item 64-bit Linux (legacy protocol) @tab no (1) @tab no (1) +@item 32-bit Linux (modern protocol) @tab yes @tab yes +@item 64-bit Linux (modern protocol) @tab yes @tab yes +@item 32-bit XNU @tab yes @tab yes +@item 64-bit XNU @tab yes (5) @tab yes +@item 32-bit EFI chainloader @tab yes @tab no (4) +@item 64-bit EFI chainloader @tab no (4) @tab yes +@item Appleloader @tab yes @tab yes +@end multitable + +@multitable @columnfractions .50 .22 .22 +@item @tab IEEE1275 +@item BIOS chainloading @tab no (1) +@item NTLDR @tab no (1) +@item FreeBSD bootloader @tab crashes (1) +@item 32-bit kFreeBSD @tab crashes (6) +@item 64-bit kFreeBSD @tab crashes (6) +@item 32-bit kNetBSD @tab crashes (1) +@item 64-bit kNetBSD @tab ? +@item 32-bit kOpenBSD @tab ? +@item 64-bit kOpenBSD @tab ? +@item Multiboot @tab ? +@item Multiboot2 @tab ? +@item 32-bit Linux (legacy protocol) @tab no (1) +@item 64-bit Linux (legacy protocol) @tab no (1) +@item 32-bit Linux (modern protocol) @tab ? +@item 64-bit Linux (modern protocol) @tab ? +@item 32-bit XNU @tab ? +@item 64-bit XNU @tab ? +@item 32-bit EFI chainloader @tab no (3) +@item 64-bit EFI chainloader @tab no (3) +@item Appleloader @tab no (3) +@end multitable + +@enumerate +@item Requires BIOS +@item Crashes because the memory at 0x0-0x1000 isn't available +@item EFI only +@item 32-bit and 64-bit EFI have different structures and work in different CPU modes so it's not possible to chainload 32-bit bootloader on 64-bit platform and vice-versa +@item Some modules may need to be disabled +@item Requires ACPI +@end enumerate + +PowerPC and Sparc ports support only Linux. MIPS port supports Linux and multiboot2. + +@chapter Boot tests + +As you have seen in previous chapter the support matrix is pretty big and some of the configurations are only rarely used. To ensure the quality bootchecks are available for all x86 targets except EFI chainloader, Appleloader and XNU. All x86 platforms have bootcheck facility except ieee1275. Multiboot, multiboot2, BIOS chainloader, ntldr and freebsd-bootloader boot targets are tested only with a fake kernel images. Only Linux is tested among the payloads using Linux protocols. + +Following variables must be defined: + +@multitable @columnfractions .30 .65 +@item GRUB_PAYLOADS_DIR @tab directory containing the required kernels +@item GRUB_CBFSTOOL @tab cbfstoll from Coreboot package (for coreboot platform only) +@item GRUB_COREBOOT_ROM @tab empty Coreboot ROM +@item GRUB_QEMU_OPTS @tab additional options to be supplied to QEMU +@end multitable + +Required files are: + +@multitable @columnfractions .40 .55 +@item kfreebsd_env.i386 @tab 32-bit kFreeBSD device hints +@item kfreebsd.i386 @tab 32-bit FreeBSD kernel image +@item kfreebsd.x86_64, kfreebsd_env.x86_64 @tab same from 64-bit kFreeBSD +@item knetbsd.i386 @tab 32-bit NetBSD kernel image +@item knetbsd.miniroot.i386 @tab 32-bit kNetBSD miniroot.kmod. +@item knetbsd.x86_64, knetbsd.miniroot.x86_64 @tab same from 64-bit kNetBSD +@item kopenbsd.i386 @tab 32-bit OpenBSD kernel bsd.rd image +@item kopenbsd.x86_64 @tab same from 64-bit kOpenBSD +@item linux.i386 @tab 32-bit Linux +@item linux.x86_64 @tab 64-bit Linux +@end multitable + @node Troubleshooting @chapter Error messages produced by GRUB diff --git a/gentpl.py b/gentpl.py index 17bda02c6..cd34fccff 100644 --- a/gentpl.py +++ b/gentpl.py @@ -10,46 +10,38 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", "powerpc_ieee1275" ] GROUPS = {} + +GROUPS["common"] = GRUB_PLATFORMS[:] + +# Groups based on CPU GROUPS["i386"] = [ "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", "i386_multiboot", "i386_ieee1275" ] GROUPS["x86_64"] = [ "x86_64_efi" ] GROUPS["x86"] = GROUPS["i386"] + GROUPS["x86_64"] -GROUPS["x86_efi"] = [ "i386_efi", "x86_64_efi" ] - -GROUPS["nopc"] = GRUB_PLATFORMS[:]; GROUPS["nopc"].remove("i386_pc") -GROUPS["x86_efi_pc"] = GROUPS["x86_efi"] + ["i386_pc"] - -GROUPS["x86_noefi"] = GROUPS["x86"][:]; GROUPS["x86_noefi"].remove("i386_efi"); GROUPS["x86_noefi"].remove("x86_64_efi") -GROUPS["i386_noefi"] = GROUPS["i386"][:]; GROUPS["i386_noefi"].remove("i386_efi") - -GROUPS["x86_noieee1275"] = GROUPS["x86"][:]; GROUPS["x86_noieee1275"].remove("i386_ieee1275") -GROUPS["i386_noieee1275"] = GROUPS["i386"][:]; GROUPS["i386_noieee1275"].remove("i386_ieee1275") - -GROUPS["i386_noefi_noieee1275"] = GROUPS["i386_noefi"][:]; GROUPS["i386_noefi_noieee1275"].remove("i386_ieee1275") - -GROUPS["i386_pc_qemu_coreboot"] = ["i386_pc", "i386_qemu", "i386_coreboot"] -GROUPS["i386_coreboot_multiboot"] = ["i386_coreboot", "i386_multiboot"] -GROUPS["i386_coreboot_multiboot_qemu"] = ["i386_coreboot", "i386_multiboot", "i386_qemu"] -GROUPS["i386_pc_coreboot_multiboot_qemu"] = ["i386_pc", "i386_coreboot", "i386_multiboot", "i386_qemu"] - GROUPS["mips"] = [ "mips_yeeloong" ] GROUPS["sparc64"] = [ "sparc64_ieee1275" ] GROUPS["powerpc"] = [ "powerpc_ieee1275" ] -GROUPS["nosparc64"] = GRUB_PLATFORMS[:]; GROUPS["nosparc64"].remove("sparc64_ieee1275") -GROUPS["x86_noefi_mips"] = GROUPS["x86_noefi"] + GROUPS["mips"] - +# Groups based on firmware +GROUPS["x86_efi"] = [ "i386_efi", "x86_64_efi" ] GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] -GROUPS["noieee1275"] = GRUB_PLATFORMS[:] -for i in GROUPS["ieee1275"]: GROUPS["noieee1275"].remove(i) -GROUPS["ieee1275_mips"] = GROUPS["ieee1275"] + GROUPS["mips"] - -GROUPS["pci"] = GROUPS["x86"] + GROUPS["mips"] +# emu is a special case so many core functionality isn't needed on this platform GROUPS["noemu"] = GRUB_PLATFORMS[:]; GROUPS["noemu"].remove("emu") -GROUPS["noemu_noieee1275"] = GRUB_PLATFORMS[:] -for i in ["emu"] + GROUPS["ieee1275"]: GROUPS["noemu_noieee1275"].remove(i) -GROUPS["common"] = GRUB_PLATFORMS[:] +# Groups based on hardware features +GROUPS["cmos"] = GROUPS["x86"][:] + ["mips_yeeloong"]; GROUPS["cmos"].remove("i386_efi"); GROUPS["cmos"].remove("x86_64_efi") +GROUPS["pci"] = GROUPS["x86"] + GROUPS["mips"] +GROUPS["usb"] = GROUPS["pci"] + +# If gfxterm is main output console integrate it into kernel +GROUPS["videoinkernel"] = ["mips_yeeloong"] +GROUPS["videomodules"] = GRUB_PLATFORMS[:]; +for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i) + +# Miscelaneous groups schedulded to disappear in future +GROUPS["nosparc64"] = GRUB_PLATFORMS[:]; GROUPS["nosparc64"].remove("sparc64_ieee1275") +GROUPS["i386_coreboot_multiboot_qemu"] = ["i386_coreboot", "i386_multiboot", "i386_qemu"] +GROUPS["nopc"] = GRUB_PLATFORMS[:]; GROUPS["nopc"].remove("i386_pc") # # Create platform => groups reverse map, where groups covering that @@ -486,7 +478,7 @@ chmod a+x [+ name +] """) r += gvar_add("CLEANFILES", "[+ name +]") - r += gvar_add("EXTRA_DIST", platform_sources(platform)) + r += gvar_add("dist_noinst_DATA", platform_sources(platform)) return r def module_rules(): diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 773803544..5d13d0313 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -58,8 +58,6 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/disk.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/dl.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/elf.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/elfload.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h @@ -70,35 +68,23 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/kernel.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/list.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/misc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/reader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/symbol.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/types.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h if COND_i386_pc -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/biosdisk.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/boot.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/console.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/vga.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/vbe.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/pxe.h +KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/int.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_efi -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/time.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h @@ -106,63 +92,36 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_coreboot -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/boot.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/console.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/init.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_multiboot -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/boot.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/console.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/init.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_qemu -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/boot.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/console.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/init.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/pci.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_i386_ieee1275 -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_x86_64_efi -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/time.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loader.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/pit.h endif if COND_mips_yeeloong -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/cache.h @@ -180,28 +139,17 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/serial.h endif if COND_powerpc_ieee1275 -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h endif if COND_sparc64_ieee1275 -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/boot.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/loader.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/msdos_partition.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/libgcc.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sparc64/ieee1275/ieee1275.h endif if COND_emu -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/time.h -KERNEL_HEADER_FILES += $(top_builddir)/include/grub/cpu/types.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gzio.h -KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/menu.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h if COND_GRUB_EMU_SDL @@ -312,7 +260,6 @@ moddep.lst: kernel_syms.lst genmoddep.awk $(DEF_FILES) $(UND_FILES) | $(AWK) -f $(srcdir)/genmoddep.awk $(UND_FILES) > $@ \ || (rm -f $@; exit 1) -if COND_i386_pc if COND_ENABLE_EFIEMU efiemu32.o: efiemu/runtime/efiemu.c $(TARGET_OBJ2ELF) -rm -f $@; \ @@ -355,5 +302,3 @@ efiemu64.o: efiemu64_c.o efiemu64_s.o $(TARGET_OBJ2ELEF) platform_DATA += efiemu32.o efiemu64.o CLEANFILES += efiemu32.o efiemu64.o efiemu64_c.o efiemu64_s.o endif -endif - diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 0ca28eb19..a72f61b66 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -36,7 +36,8 @@ kernel = { x86_64_efi_startup = kern/x86_64/efi/startup.S; i386_qemu_startup = kern/i386/qemu/startup.S; i386_ieee1275_startup = kern/i386/ieee1275/startup.S; - i386_coreboot_multiboot_startup = kern/i386/coreboot/startup.S; + i386_coreboot_startup = kern/i386/coreboot/startup.S; + i386_multiboot_startup = kern/i386/coreboot/startup.S; mips_yeeloong_startup = kern/mips/startup.S; sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S; powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S; @@ -65,7 +66,12 @@ kernel = { noemu_nodist = symlist.c; - noemu_noieee1275 = kern/generic/rtc_get_time_ms.c; + i386_pc = kern/generic/rtc_get_time_ms.c; + x86_efi = kern/generic/rtc_get_time_ms.c; + i386_qemu = kern/generic/rtc_get_time_ms.c; + i386_coreboot = kern/generic/rtc_get_time_ms.c; + i386_multiboot = kern/generic/rtc_get_time_ms.c; + mips_yeeloong = kern/generic/rtc_get_time_ms.c; ieee1275 = disk/ieee1275/ofdisk.c; ieee1275 = kern/ieee1275/cmain.c; @@ -74,20 +80,20 @@ kernel = { ieee1275 = kern/ieee1275/openfw.c; ieee1275 = term/ieee1275/ofconsole.c; - ieee1275_mips = term/terminfo.c; - ieee1275_mips = term/tparm.c; + ieee1275 = term/terminfo.c; + ieee1275 = term/tparm.c; + mips = term/terminfo.c; + mips = term/tparm.c; i386 = kern/i386/dl.c; i386_coreboot_multiboot_qemu = kern/i386/coreboot/init.c; - i386_coreboot_multiboot_qemu = kern/i386/halt.c; i386_coreboot_multiboot_qemu = term/i386/pc/vga_text.c; - i386_pc_coreboot_multiboot_qemu = term/i386/vga_common.c; + i386_coreboot_multiboot_qemu = term/i386/vga_common.c; + i386_pc = term/i386/vga_common.c; - i386_noefi = kern/i386/misc.S; - - x86_noieee1275 = kern/i386/pit.c; + x86 = kern/i386/pit.c; x86_efi = disk/efi/efidisk.c; x86_efi = kern/efi/efi.c; @@ -118,33 +124,20 @@ kernel = { i386_multiboot = kern/i386/multiboot_mmap.c; i386_multiboot = kern/i386/tsc.c; - i386_ieee1275 = kern/i386/ieee1275/init.c; i386_ieee1275 = kern/ieee1275/init.c; mips_yeeloong = term/ns8250.c; mips_yeeloong = bus/bonito.c; mips_yeeloong = bus/cs5536.c; mips_yeeloong = bus/pci.c; - mips_yeeloong = commands/extcmd.c; - mips_yeeloong = font/font.c; - mips_yeeloong = font/font_cmd.c; - mips_yeeloong = io/bufio.c; mips_yeeloong = kern/mips/cache.S; mips_yeeloong = kern/mips/dl.c; mips_yeeloong = kern/mips/init.c; mips_yeeloong = kern/mips/yeeloong/init.c; - mips_yeeloong = lib/arg.c; mips_yeeloong = term/at_keyboard.c; - mips_yeeloong = term/gfxterm.c; mips_yeeloong = term/serial.c; - mips_yeeloong = video/bitmap.c; - mips_yeeloong = video/bitmap_scale.c; - mips_yeeloong = video/fb/fbblit.c; - mips_yeeloong = video/fb/fbfill.c; - mips_yeeloong = video/fb/fbutil.c; - mips_yeeloong = video/fb/video_fb.c; mips_yeeloong = video/sm712.c; - mips_yeeloong = video/video.c; + extra_dist = video/sm712_init.c; powerpc_ieee1275 = kern/ieee1275/init.c; powerpc_ieee1275 = kern/powerpc/cache.S; @@ -166,9 +159,23 @@ kernel = { emu = kern/emu/mm.c; emu = kern/emu/time.c; - extra_dist = kern/i386/loader.S; + videoinkernel = lib/arg.c; + videoinkernel = term/gfxterm.c; + videoinkernel = commands/extcmd.c; + videoinkernel = font/font.c; + videoinkernel = font/font_cmd.c; + videoinkernel = io/bufio.c; + videoinkernel = video/bitmap.c; + videoinkernel = video/bitmap_scale.c; + videoinkernel = video/fb/fbblit.c; + videoinkernel = video/fb/fbfill.c; + videoinkernel = video/fb/fbutil.c; + videoinkernel = video/fb/video_fb.c; + videoinkernel = video/video.c; + extra_dist = kern/i386/realmode.S; extra_dist = kern/i386/pc/lzma_decode.S; + extra_dist = kern/mips/cache_flush.S; }; program = { @@ -305,8 +312,7 @@ module = { noemu = bus/usb/usbtrans.c; noemu = bus/usb/usbhub.c; enable = emu; - enable = i386; - enable = mips_yeeloong; + enable = usb; emu_condition = COND_GRUB_EMU_USB; }; @@ -314,8 +320,7 @@ module = { name = usbserial_common; common = bus/usb/serial/common.c; enable = emu; - enable = i386_pc; - enable = mips_yeeloong; + enable = usb; emu_condition = COND_GRUB_EMU_USB; }; @@ -323,8 +328,7 @@ module = { name = usbserial_pl2303; common = bus/usb/serial/pl2303.c; enable = emu; - enable = i386_pc; - enable = mips_yeeloong; + enable = usb; emu_condition = COND_GRUB_EMU_USB; }; @@ -332,22 +336,20 @@ module = { name = usbserial_ftdi; common = bus/usb/serial/ftdi.c; enable = emu; - enable = i386_pc; - enable = mips_yeeloong; + enable = usb; emu_condition = COND_GRUB_EMU_USB; }; module = { name = uhci; common = bus/usb/uhci.c; - enable = i386_pc; + enable = x86; }; module = { name = ohci; common = bus/usb/ohci.c; - enable = i386_pc; - enable = mips_yeeloong; + enable = pci; }; module = { @@ -361,6 +363,7 @@ module = { enable = x86_efi; enable = i386_ieee1275; enable = i386_coreboot; + enable = i386_multiboot; emu_condition = COND_GRUB_EMU_PCI; }; @@ -379,9 +382,8 @@ library = { module = { name = cmostest; - i386 = commands/i386/cmostest.c; - enable = i386_pc; - enable = i386_coreboot; + common = commands/i386/cmostest.c; + enable = cmos; }; module = { @@ -393,6 +395,7 @@ module = { module = { name = regexp; common = commands/regexp.c; + common = commands/wildcard.c; ldadd = libgnulib.a; cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; @@ -401,12 +404,16 @@ module = { module = { name = acpi; - i386 = commands/acpi.c; + x86 = commands/acpi.c; x86_efi = commands/efi/acpi.c; i386_pc = commands/i386/pc/acpi.c; + i386_coreboot = commands/i386/pc/acpi.c; + i386_multiboot = commands/i386/pc/acpi.c; enable = x86_efi; enable = i386_pc; + enable = i386_coreboot; + enable = i386_multiboot; }; module = { @@ -486,6 +493,12 @@ module = { name = halt; nopc = commands/halt.c; i386_pc = commands/i386/pc/halt.c; + i386_multiboot = lib/i386/halt.c; + i386_coreboot = lib/i386/halt.c; + i386_qemu = lib/i386/halt.c; + x86_efi = lib/efi/halt.c; + ieee1275 = lib/ieee1275/halt.c; + emu = lib/emu/halt.c; }; module = { @@ -497,7 +510,7 @@ module = { name = hdparm; common = commands/hdparm.c; common = lib/hexdump.c; - enable = i386_pc; + enable = pci; }; module = { @@ -542,8 +555,7 @@ module = { name = lspci; common = commands/lspci.c; - enable = x86; - enable = mips; + enable = pci; }; module = { @@ -655,8 +667,7 @@ module = { module = { name = usbtest; common = commands/usbtest.c; - enable = i386_pc; - enable = mips_yeeloong; + enable = usb; enable = emu; emu_condition = COND_GRUB_EMU_USB; }; @@ -731,15 +742,13 @@ module = { module = { name = ata; common = disk/ata.c; - enable = x86; - enable = mips; + enable = pci; }; module = { name = ata_pthru; common = disk/ata_pthru.c; - enable = x86; - enable = mips_yeeloong; + enable = pci; }; module = { @@ -751,8 +760,7 @@ module = { module = { name = usbms; common = disk/usbms.c; - enable = i386_pc; - enable = mips_yeeloong; + enable = usb; enable = emu; emu_condition = COND_GRUB_EMU_USB; }; @@ -765,19 +773,23 @@ module = { module = { name = efiemu; - i386_pc = efiemu/main.c; - i386_pc = efiemu/i386/loadcore32.c; - i386_pc = efiemu/i386/loadcore64.c; + common = efiemu/main.c; + common = efiemu/i386/loadcore32.c; + common = efiemu/i386/loadcore64.c; i386_pc = efiemu/i386/pc/cfgtables.c; - i386_pc = efiemu/mm.c; - i386_pc = efiemu/loadcore_common.c; - i386_pc = efiemu/symbols.c; - i386_pc = efiemu/loadcore32.c; - i386_pc = efiemu/loadcore64.c; - i386_pc = efiemu/prepare32.c; - i386_pc = efiemu/prepare64.c; - i386_pc = efiemu/pnvram.c; - i386_pc = efiemu/i386/coredetect.c; + i386_coreboot = efiemu/i386/pc/cfgtables.c; + i386_multiboot = efiemu/i386/pc/cfgtables.c; + i386_ieee1275 = efiemu/i386/nocfgtables.c; + i386_qemu = efiemu/i386/nocfgtables.c; + common = efiemu/mm.c; + common = efiemu/loadcore_common.c; + common = efiemu/symbols.c; + common = efiemu/loadcore32.c; + common = efiemu/loadcore64.c; + common = efiemu/prepare32.c; + common = efiemu/prepare64.c; + common = efiemu/pnvram.c; + common = efiemu/i386/coredetect.c; extra_dist = efiemu/prepare.c; extra_dist = efiemu/loadcore.c; @@ -785,16 +797,17 @@ module = { extra_dist = efiemu/runtime/efiemu.c; enable = i386_pc; + enable = i386_coreboot; + enable = i386_ieee1275; + enable = i386_multiboot; + enable = i386_qemu; }; module = { name = font; common = font/font.c; common = font/font_cmd.c; - enable = emu; - enable = x86; - enable = sparc64; - enable = powerpc; + enable = videomodules; }; module = { @@ -962,10 +975,7 @@ module = { module = { name = bufio; common = io/bufio.c; - enable = emu; - enable = x86; - enable = sparc64; - enable = powerpc; + enable = videomodules; }; module = { @@ -987,26 +997,35 @@ module = { module = { name = relocator; - mips = lib/mips/relocator.c; - mips = lib/mips/relocator_asm.S; + common = lib/relocator.c; + x86 = lib/i386/relocator16.S; + x86 = lib/i386/relocator32.S; + x86 = lib/i386/relocator64.S; + i386 = lib/i386/relocator_asm.S; + x86_64 = lib/x86_64/relocator_asm.S; x86 = lib/i386/relocator.c; - x86 = lib/i386/relocator_asm.S; - x86 = lib/i386/relocator_backward.S; - extra_dist = lib/relocator.c; + ieee1275 = lib/ieee1275/relocator.c; + x86_efi = lib/efi/relocator.c; + mips = lib/mips/relocator_asm.S; + mips = lib/mips/relocator.c; + powerpc = lib/powerpc/relocator_asm.S; + powerpc = lib/powerpc/relocator.c; + + extra_dist = lib/i386/relocator_common.S; + extra_dist = kern/powerpc/cache_flush.S; + enable = mips; + enable = powerpc; enable = x86; }; module = { name = datetime; - x86_noefi_mips = lib/cmos_datetime.c; + cmos = lib/cmos_datetime.c; x86_efi = lib/efi/datetime.c; sparc64_ieee1275 = lib/ieee1275/datetime.c; powerpc_ieee1275 = lib/ieee1275/datetime.c; - enable = x86; - enable = mips; - enable = sparc64_ieee1275; - enable = powerpc_ieee1275; + enable = noemu; }; module = { @@ -1022,28 +1041,19 @@ module = { module = { name = aout; common = loader/aout.c; - enable = i386_pc; - enable = i386_qemu; - enable = i386_coreboot; - enable = i386_multiboot; - enable = i386_ieee1275; + enable = x86; }; module = { name = bsd; - i386 = loader/i386/bsd.c; - i386 = loader/i386/bsd32.c; - i386 = loader/i386/bsd64.c; - i386 = loader/i386/bsd_helper.S; - i386 = loader/i386/bsd_trampoline.S; + x86 = loader/i386/bsd.c; + x86 = loader/i386/bsd32.c; + x86 = loader/i386/bsd64.c; extra_dist = loader/i386/bsdXX.c; extra_dist = loader/i386/bsd_pagetable.c; - enable = i386_pc; - enable = i386_qemu; - enable = i386_coreboot; - enable = i386_multiboot; + enable = x86; }; module = { @@ -1052,6 +1062,12 @@ module = { enable = i386_pc; }; +module = { + name = ntldr; + i386_pc = loader/i386/pc/ntldr.c; + enable = i386_pc; +}; + module = { name = multiboot2; cppflags = "-DGRUB_USE_MULTIBOOT2"; @@ -1072,11 +1088,7 @@ module = { module = { name = linux; - i386_noefi_noieee1275 = loader/i386/linux.c; - - x86_efi = loader/i386/efi/linux.c; - x86_64_efi = loader/i386/linux_trampoline.S; - i386_ieee1275 = loader/i386/ieee1275/linux.c; + x86 = loader/i386/linux.c; mips = loader/mips/linux.c; powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; @@ -1085,16 +1097,15 @@ module = { module = { name = xnu; - x86_efi_pc = loader/xnu_resume.c; - x86_efi_pc = loader/i386/xnu.c; - x86_efi_pc = loader/macho32.c; - x86_efi_pc = loader/macho64.c; - x86_efi_pc = loader/macho.c; - x86_efi_pc = loader/xnu.c; + x86 = loader/xnu_resume.c; + x86 = loader/i386/xnu.c; + x86 = loader/macho32.c; + x86 = loader/macho64.c; + x86 = loader/macho.c; + x86 = loader/xnu.c; extra_dist = loader/machoXX.c; - enable = i386_pc; - enable = x86_efi; + enable = x86; }; module = { @@ -1113,34 +1124,15 @@ module = { module = { name = mmap; - i386_pc = mmap/mmap.c; - i386_pc = mmap/i386/uppermem.c; - i386_pc = mmap/i386/mmap.c; + common = mmap/mmap.c; + x86 = mmap/i386/uppermem.c; + x86 = mmap/i386/mmap.c; + i386_pc = mmap/i386/pc/mmap.c; i386_pc = mmap/i386/pc/mmap_helper.S; - x86_efi = mmap/mmap.c; - x86_efi = mmap/i386/uppermem.c; - x86_efi = mmap/i386/mmap.c; x86_efi = mmap/efi/mmap.c; - i386_coreboot = mmap/mmap.c; - i386_coreboot = mmap/i386/uppermem.c; - i386_coreboot = mmap/i386/mmap.c; - - i386_multiboot = mmap/mmap.c; - i386_multiboot = mmap/i386/uppermem.c; - i386_multiboot = mmap/i386/mmap.c; - - i386_qemu = mmap/mmap.c; - i386_qemu = mmap/i386/uppermem.c; - i386_qemu = mmap/i386/mmap.c; - - i386_ieee1275 = mmap/mmap.c; - i386_ieee1275 = mmap/i386/uppermem.c; - i386_ieee1275 = mmap/i386/mmap.c; - - mips_yeeloong = mmap/mmap.c; mips_yeeloong = mmap/mips/yeeloong/uppermem.c; enable = x86; @@ -1173,6 +1165,8 @@ module = { common = script/lexer.c; common = script/argv.c; + common = commands/menuentry.c; + common = unidata.c; common_nodist = grub_script.tab.c; common_nodist = grub_script.yy.c; @@ -1240,10 +1234,7 @@ module = { module = { name = gfxterm; common = term/gfxterm.c; - enable = emu; - enable = x86; - enable = sparc64; - enable = powerpc; + enable = videomodules; }; module = { @@ -1272,8 +1263,7 @@ module = { module = { name = usb_keyboard; common = term/usb_keyboard.c; - enable = i386_pc; - enable = mips_yeeloong; + enable = usb; }; module = { @@ -1284,9 +1274,11 @@ module = { module = { name = vga_text; - x86 = term/i386/pc/vga_text.c; - x86 = term/i386/vga_common.c; - enable = x86; + common = term/i386/pc/vga_text.c; + common = term/i386/vga_common.c; + enable = i386_pc; + enable = i386_coreboot; + enable = i386_multiboot; }; module = { @@ -1316,19 +1308,13 @@ module = { module = { name = bitmap; common = video/bitmap.c; - enable = emu; - enable = x86; - enable = sparc64; - enable = powerpc; + enable = videomodules; }; module = { name = bitmap_scale; common = video/bitmap_scale.c; - enable = emu; - enable = x86; - enable = sparc64; - enable = powerpc; + enable = videomodules; }; module = { @@ -1370,19 +1356,13 @@ module = { common = video/fb/fbblit.c; common = video/fb/fbfill.c; common = video/fb/fbutil.c; - enable = emu; - enable = x86; - enable = sparc64; - enable = powerpc; + enable = videomodules; }; module = { name = video; common = video/video.c; - enable = emu; - enable = x86; - enable = sparc64; - enable = powerpc; + enable = videomodules; }; module = { @@ -1409,4 +1389,24 @@ module = { common = commands/legacycfg.c; common = lib/legacy_parse.c; enable = i386_pc; +} + +module = { + name = test_blockarg; + common = tests/test_blockarg.c; +}; + +module = { + name = xzio; + common = io/xzio.c; + common = lib/xzembed/xz_dec_bcj.c; + common = lib/xzembed/xz_dec_lzma2.c; + common = lib/xzembed/xz_dec_stream.c; + cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/xzembed'; +}; + +module = { + name = testload; + common = commands/testload.c; +>>>>>>> MERGE-SOURCE }; diff --git a/grub-core/boot/i386/pc/lnxboot.S b/grub-core/boot/i386/pc/lnxboot.S index b4f0030b8..9348553c3 100644 --- a/grub-core/boot/i386/pc/lnxboot.S +++ b/grub-core/boot/i386/pc/lnxboot.S @@ -185,7 +185,7 @@ real_code_2: call LOCAL(move_memory) /* Check for multiboot signature. */ - cmpl $MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_DATA_END) + cmpl $MULTIBOOT_HEADER_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE) jz 1f movl (ramdisk_image - start), %esi diff --git a/grub-core/bus/usb/ohci.c b/grub-core/bus/usb/ohci.c index 7f757485c..587a36420 100644 --- a/grub-core/bus/usb/ohci.c +++ b/grub-core/bus/usb/ohci.c @@ -55,12 +55,12 @@ struct grub_ohci_td grub_uint32_t next_td; /* LittleEndian physical address */ grub_uint32_t buffer_end; /* LittleEndian physical address */ /* next values are not for OHCI HW */ + volatile struct grub_ohci_td *link_td; /* pointer to next free/chained TD + * pointer as uint32 */ 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 */ + grub_uint8_t pad[8 - sizeof (volatile struct grub_ohci_td *)]; /* padding to 32 bytes */ } __attribute__((packed)); /* OHCI Endpoint Descriptor. */ @@ -334,7 +334,7 @@ grub_ohci_pci_iter (grub_pci_device_t dev, /* 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]; + o->td[j].link_td = &o->td[j+1]; grub_dprintf ("ohci", "TDs: chunk=%p, virt=%p, phys=0x%02x\n", o->td_chunk, o->td, o->td_addr); @@ -561,7 +561,7 @@ 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 */ + td->link_td = o->td_free; /* Cahin new free TD & rest */ o->td_free = td; /* Change address of first free TD */ } @@ -604,8 +604,8 @@ grub_ohci_transaction (grub_ohci_td_t td, grub_uint32_t buffer; grub_uint32_t buffer_end; - grub_dprintf ("ohci", "OHCI transaction td=%p type=%d, toggle=%d, size=%d\n", - td, type, toggle, size); + grub_dprintf ("ohci", "OHCI transaction td=%p type=%d, toggle=%d, size=%lu\n", + td, type, toggle, (unsigned long) size); switch (type) { @@ -781,7 +781,7 @@ grub_ohci_transfer (grub_usb_controller_t dev, } /* Chain TDs */ - td_current_virt->link_td = (grub_uint32_t) td_next_virt; + td_current_virt->link_td = td_next_virt; td_current_virt->next_td = grub_cpu_to_le32 ( grub_ohci_td_virt2phys (o, td_next_virt) ); @@ -1406,6 +1406,8 @@ static struct grub_usb_controller_dev usb_controller = GRUB_MOD_INIT(ohci) { + COMPILE_TIME_ASSERT (sizeof (struct grub_ohci_td) == 32); + COMPILE_TIME_ASSERT (sizeof (struct grub_ohci_ed) == 16); grub_ohci_inithw (); grub_usb_controller_dev_register (&usb_controller); grub_loader_register_preboot_hook (grub_ohci_fini_hw, grub_ohci_restore_hw, diff --git a/grub-core/bus/usb/uhci.c b/grub-core/bus/usb/uhci.c index 0bba24b54..1fe86f5d4 100644 --- a/grub-core/bus/usb/uhci.c +++ b/grub-core/bus/usb/uhci.c @@ -228,7 +228,7 @@ grub_uhci_pci_iter (grub_pci_device_t dev, /* Link all Transfer Descriptors in a list of available Transfer Descriptors. */ for (i = 0; i < 256; i++) - u->td[i].linkptr = (grub_uint32_t) &u->td[i + 1]; + u->td[i].linkptr = (grub_uint32_t) (grub_addr_t) &u->td[i + 1]; u->td[255 - 1].linkptr = 0; u->tdfree = u->td; @@ -238,20 +238,20 @@ grub_uhci_pci_iter (grub_pci_device_t dev, /* Setup the frame list pointers. Since no isochronous transfers are and will be supported, they all point to the (same!) queue head. */ - fp = (grub_uint32_t) u->qh & (~15); + fp = (grub_uint32_t) (grub_addr_t) u->qh & (~15); /* Mark this as a queue head. */ fp |= 2; for (i = 0; i < 1024; i++) u->framelist[i] = fp; /* Program the framelist address into the UHCI controller. */ grub_uhci_writereg32 (u, GRUB_UHCI_REG_FLBASEADD, - (grub_uint32_t) u->framelist); + (grub_uint32_t) (grub_addr_t) u->framelist); /* Make the Queue Heads point to each other. */ for (i = 0; i < 256; i++) { /* Point to the next QH. */ - u->qh[i].linkptr = (grub_uint32_t) (&u->qh[i + 1]) & (~15); + u->qh[i].linkptr = (grub_uint32_t) (grub_addr_t) (&u->qh[i + 1]) & (~15); /* This is a QH. */ u->qh[i].linkptr |= GRUB_UHCI_LINK_QUEUE_HEAD; @@ -319,7 +319,7 @@ grub_alloc_td (struct grub_uhci *u) return NULL; ret = u->tdfree; - u->tdfree = (grub_uhci_td_t) u->tdfree->linkptr; + u->tdfree = (grub_uhci_td_t) (grub_addr_t) u->tdfree->linkptr; return ret; } @@ -327,7 +327,7 @@ grub_alloc_td (struct grub_uhci *u) static void grub_free_td (struct grub_uhci *u, grub_uhci_td_t td) { - td->linkptr = (grub_uint32_t) u->tdfree; + td->linkptr = (grub_uint32_t) (grub_addr_t) u->tdfree; u->tdfree = td; } @@ -352,7 +352,7 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td, /* Unlink the queue. */ tdprev = td; - td = (grub_uhci_td_t) td->linkptr2; + td = (grub_uhci_td_t) (grub_addr_t) td->linkptr2; /* Free the TD. */ grub_free_td (u, tdprev); @@ -413,8 +413,8 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp, } grub_dprintf ("uhci", - "transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%d data=0x%x td=%p\n", - endp, type, addr, toggle, size, data, td); + "transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%lu data=0x%x td=%p\n", + endp, type, addr, toggle, (unsigned long) size, data, td); /* Don't point to any TD, just terminate. */ td->linkptr = 1; @@ -484,8 +484,8 @@ grub_uhci_transfer (grub_usb_controller_t dev, td_first = td; else { - td_prev->linkptr2 = (grub_uint32_t) td; - td_prev->linkptr = (grub_uint32_t) td; + td_prev->linkptr2 = (grub_uint32_t) (grub_addr_t) td; + td_prev->linkptr = (grub_uint32_t) (grub_addr_t) td; td_prev->linkptr |= 4; } td_prev = td; @@ -497,7 +497,7 @@ grub_uhci_transfer (grub_usb_controller_t dev, /* Link it into the queue and terminate. Now the transaction can take place. */ - qh->elinkptr = (grub_uint32_t) td_first; + qh->elinkptr = (grub_uint32_t) (grub_addr_t) td_first; grub_dprintf ("uhci", "initiate transaction\n"); @@ -508,7 +508,7 @@ grub_uhci_transfer (grub_usb_controller_t dev, { grub_uhci_td_t errtd; - errtd = (grub_uhci_td_t) (qh->elinkptr & ~0x0f); + errtd = (grub_uhci_td_t) (grub_addr_t) (qh->elinkptr & ~0x0f); grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n", errtd->ctrl_status, errtd->buffer & (~15), errtd); diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c index db2ec097a..13f5c28ed 100644 --- a/grub-core/bus/usb/usbtrans.c +++ b/grub-core/bus/usb/usbtrans.c @@ -54,8 +54,8 @@ grub_usb_control_msg (grub_usb_device_t dev, grub_memcpy ((char *) data, data_in, size); grub_dprintf ("usb", - "control: reqtype=0x%02x req=0x%02x val=0x%02x idx=0x%02x size=%d\n", - reqtype, request, value, index, size); + "control: reqtype=0x%02x req=0x%02x val=0x%02x idx=0x%02x size=%lu\n", + reqtype, request, value, index, (unsigned long)size); /* Create a transfer. */ transfer = grub_malloc (sizeof (*transfer)); @@ -179,7 +179,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); + grub_dprintf ("usb", "bulk: size=0x%02lx type=%d\n", (unsigned long) size, + type); /* FIXME: avoid allocation any kind of buffer in a first place. */ data_chunk = grub_memalign_dma32 (128, size); diff --git a/grub-core/commands/acpi.c b/grub-core/commands/acpi.c index 884ddf000..b2edcc9cd 100644 --- a/grub-core/commands/acpi.c +++ b/grub-core/commands/acpi.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -458,10 +457,9 @@ free_tables (void) } static grub_err_t -grub_cmd_acpi (struct grub_extcmd *cmd, - int argc, char **args) +grub_cmd_acpi (struct grub_extcmd_context *ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; struct grub_acpi_rsdp_v10 *rsdp; struct efiemu_acpi_table *cur, *t; grub_err_t err; @@ -629,7 +627,7 @@ grub_cmd_acpi (struct grub_extcmd *cmd, grub_size_t size; char *buf; - file = grub_gzfile_open (args[i], 1); + file = grub_file_open (args[i]); if (! file) { free_tables (); diff --git a/grub-core/commands/blocklist.c b/grub-core/commands/blocklist.c index cace31113..4651fb32a 100644 --- a/grub-core/commands/blocklist.c +++ b/grub-core/commands/blocklist.c @@ -82,6 +82,7 @@ grub_cmd_blocklist (grub_command_t cmd __attribute__ ((unused)), if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); + grub_file_filter_disable_compression (); file = grub_file_open (args[0]); if (! file) return grub_errno; diff --git a/grub-core/commands/cat.c b/grub-core/commands/cat.c index 77a4cc793..68ca83c5d 100644 --- a/grub-core/commands/cat.c +++ b/grub-core/commands/cat.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -33,9 +32,9 @@ static const struct grub_arg_option options[] = }; static grub_err_t -grub_cmd_cat (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_cat (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; int dos = 0; grub_file_t file; char buf[GRUB_DISK_SECTOR_SIZE]; @@ -48,7 +47,7 @@ grub_cmd_cat (grub_extcmd_t cmd, int argc, char **args) if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); - file = grub_gzfile_open (args[0], 1); + file = grub_file_open (args[0]); if (! file) return grub_errno; diff --git a/grub-core/commands/cmp.c b/grub-core/commands/cmp.c index 626e1d022..d9e76a4d7 100644 --- a/grub-core/commands/cmp.c +++ b/grub-core/commands/cmp.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -44,8 +43,8 @@ grub_cmd_cmp (grub_command_t cmd __attribute__ ((unused)), grub_printf ("Compare file `%s' with `%s':\n", args[0], args[1]); - file1 = grub_gzfile_open (args[0], 1); - file2 = grub_gzfile_open (args[1], 1); + file1 = grub_file_open (args[0]); + file2 = grub_file_open (args[1]); if (! file1 || ! file2) goto cleanup; diff --git a/grub-core/commands/crc.c b/grub-core/commands/crc.c index 1c1a690aa..f165e1aaf 100644 --- a/grub-core/commands/crc.c +++ b/grub-core/commands/crc.c @@ -38,6 +38,7 @@ grub_cmd_crc (grub_command_t cmd __attribute__ ((unused)), if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + grub_file_filter_disable_compression (); file = grub_file_open (args[0]); if (! file) return 0; diff --git a/grub-core/commands/echo.c b/grub-core/commands/echo.c index 4fea091cb..6bc00eae8 100644 --- a/grub-core/commands/echo.c +++ b/grub-core/commands/echo.c @@ -30,9 +30,9 @@ static const struct grub_arg_option options[] = }; static grub_err_t -grub_cmd_echo (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_echo (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; int newline = 1; int i; diff --git a/grub-core/commands/extcmd.c b/grub-core/commands/extcmd.c index 16796febf..44a4b6cfd 100644 --- a/grub-core/commands/extcmd.c +++ b/grub-core/commands/extcmd.c @@ -21,46 +21,55 @@ #include #include #include +#include -static grub_err_t -grub_extcmd_dispatcher (struct grub_command *cmd, - int argc, char **args) +grub_err_t +grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, + struct grub_script *script) { int new_argc; char **new_args; - struct grub_arg_option *parser; struct grub_arg_list *state; - int maxargs = 0; + struct grub_extcmd_context context; grub_err_t ret; - grub_extcmd_t ext; + grub_extcmd_t ext = cmd->data; - ext = cmd->data; - parser = (struct grub_arg_option *) ext->options; - while (parser && (parser++)->doc) - maxargs++; + context.state = 0; + context.extcmd = ext; + context.script = script; - /* Set up the option state. */ - state = grub_zalloc (sizeof (struct grub_arg_list) * maxargs); + if (! ext->options) + { + ret = (ext->func) (&context, argc, args); + return ret; + } + state = grub_arg_list_alloc (ext, argc, args); if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc)) { - ext->state = state; - ret = (ext->func) (ext, new_argc, new_args); + context.state = state; + ret = (ext->func) (&context, new_argc, new_args); grub_free (new_args); + grub_free (state); + return ret; } - else - ret = grub_errno; grub_free (state); + return grub_errno; +} - return ret; +static grub_err_t +grub_extcmd_dispatch (struct grub_command *cmd, int argc, char **args) +{ + return grub_extcmd_dispatcher (cmd, argc, args, 0); } grub_extcmd_t -grub_register_extcmd (const char *name, grub_extcmd_func_t func, - unsigned flags, const char *summary, - const char *description, - const struct grub_arg_option *parser) +grub_register_extcmd_prio (const char *name, grub_extcmd_func_t func, + unsigned flags, const char *summary, + const char *description, + const struct grub_arg_option *parser, + int prio) { grub_extcmd_t ext; grub_command_t cmd; @@ -69,8 +78,8 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, if (! ext) return 0; - cmd = grub_register_command_prio (name, grub_extcmd_dispatcher, - summary, description, 1); + cmd = grub_register_command_prio (name, grub_extcmd_dispatch, + summary, description, prio); if (! cmd) { grub_free (ext); @@ -88,6 +97,16 @@ grub_register_extcmd (const char *name, grub_extcmd_func_t func, return ext; } +grub_extcmd_t +grub_register_extcmd (const char *name, grub_extcmd_func_t func, + unsigned flags, const char *summary, + const char *description, + const struct grub_arg_option *parser) +{ + return grub_register_extcmd_prio (name, func, flags, + summary, description, parser, 1); +} + void grub_unregister_extcmd (grub_extcmd_t ext) { diff --git a/grub-core/commands/hashsum.c b/grub-core/commands/hashsum.c index d5f551dbb..6f65b4ab3 100644 --- a/grub-core/commands/hashsum.c +++ b/grub-core/commands/hashsum.c @@ -32,6 +32,7 @@ static const struct grub_arg_option options[] = { {"prefix", 'p', 0, N_("Base directory for hash list."), N_("DIRECTORY"), ARG_TYPE_STRING}, {"keep-going", 'k', 0, N_("Don't stop after first error."), 0, 0}, + {"uncompress", 'u', 0, N_("Uncompress file before checksumming."), 0, 0}, {0, 0, 0, 0, 0, 0} }; @@ -80,7 +81,7 @@ hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result) static grub_err_t check_list (const gcry_md_spec_t *hash, const char *hashfilename, - const char *prefix, int keep) + const char *prefix, int keep, int uncompress) { grub_file_t hashlist, file; char *buf = NULL; @@ -115,11 +116,17 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, filename = grub_xasprintf ("%s/%s", prefix, p); if (!filename) return grub_errno; + if (!uncompress) + grub_file_filter_disable_compression (); file = grub_file_open (filename); grub_free (filename); } else - file = grub_file_open (p); + { + if (!uncompress) + grub_file_filter_disable_compression (); + file = grub_file_open (p); + } if (!file) { grub_file_close (hashlist); @@ -165,19 +172,20 @@ check_list (const gcry_md_spec_t *hash, const char *hashfilename, } static grub_err_t -grub_cmd_hashsum (struct grub_extcmd *cmd, +grub_cmd_hashsum (struct grub_extcmd_context *ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; const char *hashname = NULL; const char *prefix = NULL; const gcry_md_spec_t *hash; unsigned i; int keep = state[3].set; + int uncompress = state[4].set; unsigned unread = 0; for (i = 0; i < ARRAY_SIZE (aliases); i++) - if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0) + if (grub_strcmp (ctxt->extcmd->cmd->name, aliases[i].name) == 0) hashname = aliases[i].hashname; if (state[0].set) hashname = state[0].arg; @@ -197,7 +205,7 @@ grub_cmd_hashsum (struct grub_extcmd *cmd, if (argc != 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "--check is incompatible with file list"); - return check_list (hash, state[1].arg, prefix, keep); + return check_list (hash, state[1].arg, prefix, keep, uncompress); } for (i = 0; i < (unsigned) argc; i++) @@ -206,6 +214,8 @@ grub_cmd_hashsum (struct grub_extcmd *cmd, grub_file_t file; grub_err_t err; unsigned j; + if (!uncompress) + grub_file_filter_disable_compression (); file = grub_file_open (args[i]); if (!file) { diff --git a/grub-core/commands/hdparm.c b/grub-core/commands/hdparm.c index a3f8bbff0..54724077d 100644 --- a/grub-core/commands/hdparm.c +++ b/grub-core/commands/hdparm.c @@ -270,9 +270,9 @@ static int get_int_arg (const struct grub_arg_list *state) } static grub_err_t -grub_cmd_hdparm (grub_extcmd_t cmd, int argc, char **args) // state???? +grub_cmd_hdparm (grub_extcmd_context_t ctxt, int argc, char **args) // state???? { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; /* Check command line. */ if (argc != 1) diff --git a/grub-core/commands/help.c b/grub-core/commands/help.c index e7d108c33..1ca46aa7e 100644 --- a/grub-core/commands/help.c +++ b/grub-core/commands/help.c @@ -27,7 +27,7 @@ #include static grub_err_t -grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, +grub_cmd_help (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc, char **args) { int cnt = 0; @@ -112,7 +112,8 @@ grub_cmd_help (grub_extcmd_t ext __attribute__ ((unused)), int argc, if (cnt++ > 0) grub_printf ("\n\n"); - if (cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) + if ((cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) && + ! (cmd->flags & GRUB_COMMAND_FLAG_DYNCMD)) grub_arg_show_help ((grub_extcmd_t) cmd->data); else grub_printf ("%s %s %s\n%s\n", _("Usage:"), cmd->name, _(cmd->summary), diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c index c1d4ecba9..08a94eb64 100644 --- a/grub-core/commands/hexdump.c +++ b/grub-core/commands/hexdump.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -34,9 +33,9 @@ static const struct grub_arg_option options[] = { }; static grub_err_t -grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; char buf[GRUB_DISK_SECTOR_SIZE * 4]; grub_ssize_t size, length; grub_disk_addr_t skip; @@ -89,7 +88,7 @@ grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args) { grub_file_t file; - file = grub_gzfile_open (args[0], 1); + file = grub_file_open (args[0]); if (! file) return 0; diff --git a/grub-core/commands/i386/cpuid.c b/grub-core/commands/i386/cpuid.c index 6eebf91a1..412b284d0 100644 --- a/grub-core/commands/i386/cpuid.c +++ b/grub-core/commands/i386/cpuid.c @@ -43,7 +43,7 @@ static const struct grub_arg_option options[] = unsigned char grub_cpuid_has_longmode = 0; static grub_err_t -grub_cmd_cpuid (grub_extcmd_t cmd __attribute__ ((unused)), +grub_cmd_cpuid (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { diff --git a/grub-core/commands/i386/pc/drivemap.c b/grub-core/commands/i386/pc/drivemap.c index 4afc43358..7ecfe7454 100644 --- a/grub-core/commands/i386/pc/drivemap.c +++ b/grub-core/commands/i386/pc/drivemap.c @@ -196,13 +196,13 @@ list_mappings (void) } static grub_err_t -grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args) +grub_cmd_drivemap (struct grub_extcmd_context *ctxt, int argc, char **args) { - if (cmd->state[OPTIDX_LIST].set) + if (ctxt->state[OPTIDX_LIST].set) { return list_mappings (); } - else if (cmd->state[OPTIDX_RESET].set) + else if (ctxt->state[OPTIDX_RESET].set) { /* Reset: just delete all mappings, freeing their memory. */ drivemap_node_t *curnode = map_head; @@ -216,7 +216,7 @@ grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args) map_head = 0; return GRUB_ERR_NONE; } - else if (!cmd->state[OPTIDX_SWAP].set && argc == 0) + else if (!ctxt->state[OPTIDX_SWAP].set && argc == 0) { /* No arguments */ return list_mappings (); @@ -248,11 +248,11 @@ grub_cmd_drivemap (struct grub_extcmd *cmd, int argc, char **args) } /* Set the mapping for the disk (overwrites any existing mapping). */ grub_dprintf ("drivemap", "%s %s (%02x) = %s (%02x)\n", - cmd->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping", + ctxt->state[OPTIDX_SWAP].set ? "Swapping" : "Mapping", args[1], mapto, args[0], mapfrom); err = drivemap_set (mapto, mapfrom); /* If -s, perform the reverse mapping too (only if the first was OK). */ - if (cmd->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE) + if (ctxt->state[OPTIDX_SWAP].set && err == GRUB_ERR_NONE) err = drivemap_set (mapfrom, mapto); return err; } diff --git a/grub-core/commands/i386/pc/halt.c b/grub-core/commands/i386/pc/halt.c index 4c39612ae..1e0aefa50 100644 --- a/grub-core/commands/i386/pc/halt.c +++ b/grub-core/commands/i386/pc/halt.c @@ -21,6 +21,7 @@ #include #include #include +#include static const struct grub_arg_option options[] = { @@ -28,13 +29,76 @@ static const struct grub_arg_option options[] = {0, 0, 0, 0, 0, 0} }; +static inline void __attribute__ ((noreturn)) +stop (void) +{ + while (1) + { + asm volatile ("hlt"); + } +} +/* + * Halt the system, using APM if possible. If NO_APM is true, don't use + * APM even if it is available. + */ +void +grub_halt (int no_apm) +{ + struct grub_bios_int_registers regs; + + if (no_apm) + stop (); + + /* detect APM */ + regs.eax = 0x5300; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + stop (); + + /* disconnect APM first */ + regs.eax = 0x5304; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + + /* connect APM */ + regs.eax = 0x5301; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + stop (); + + /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */ + regs.eax = 0x530E; + regs.ebx = 0; + regs.ecx = 0x0101; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + stop (); + + /* set the power state to off */ + regs.eax = 0x5307; + regs.ebx = 1; + regs.ecx = 3; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + + /* shouldn't reach here */ + stop (); +} + static grub_err_t -grub_cmd_halt (grub_extcmd_t cmd, +grub_cmd_halt (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; int no_apm = 0; if (state[0].set) no_apm = 1; diff --git a/grub-core/commands/i386/pc/sendkey.c b/grub-core/commands/i386/pc/sendkey.c index 6c5602dec..1f506b3cd 100644 --- a/grub-core/commands/i386/pc/sendkey.c +++ b/grub-core/commands/i386/pc/sendkey.c @@ -284,9 +284,9 @@ grub_sendkey_preboot (int noret __attribute__ ((unused))) } static grub_err_t -grub_cmd_sendkey (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_sendkey (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; auto int find_key_code (char *key); auto int find_ascii_code (char *key); diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c index 474c8712e..bd0183794 100644 --- a/grub-core/commands/iorw.c +++ b/grub-core/commands/iorw.c @@ -36,7 +36,7 @@ static const struct grub_arg_option options[] = static grub_err_t -grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) +grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **argv) { grub_target_addr_t addr; grub_uint32_t value = 0; @@ -46,7 +46,7 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments"); addr = grub_strtoul (argv[0], 0, 0); - switch (cmd->cmd->name[sizeof ("in") - 1]) + switch (ctxt->extcmd->cmd->name[sizeof ("in") - 1]) { case 'l': value = grub_inl (addr); @@ -61,10 +61,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) break; } - if (cmd->state[0].set) + if (ctxt->state[0].set) { grub_snprintf (buf, sizeof (buf), "%x", value); - grub_env_set (cmd->state[0].arg, buf); + grub_env_set (ctxt->state[0].arg, buf); } else grub_printf ("0x%x\n", value); diff --git a/grub-core/commands/keystatus.c b/grub-core/commands/keystatus.c index 838792889..c83c00560 100644 --- a/grub-core/commands/keystatus.c +++ b/grub-core/commands/keystatus.c @@ -34,11 +34,11 @@ static const struct grub_arg_option options[] = #define grub_cur_term_input grub_term_get_current_input () static grub_err_t -grub_cmd_keystatus (grub_extcmd_t cmd, +grub_cmd_keystatus (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; int expect_mods = 0; int mods; diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c index d763b2d5e..9a1873ba9 100644 --- a/grub-core/commands/loadenv.c +++ b/grub-core/commands/loadenv.c @@ -56,6 +56,7 @@ open_envblk_file (char *filename) grub_strcpy (filename, prefix); filename[len] = '/'; grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG); + grub_file_filter_disable_compression (); file = grub_file_open (filename); grub_free (filename); return file; @@ -67,6 +68,7 @@ open_envblk_file (char *filename) } } + grub_file_filter_disable_compression (); return grub_file_open (filename); } @@ -111,11 +113,11 @@ read_envblk_file (grub_file_t file) } static grub_err_t -grub_cmd_load_env (grub_extcmd_t cmd, +grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_file_t file; grub_envblk_t envblk; @@ -143,11 +145,11 @@ grub_cmd_load_env (grub_extcmd_t cmd, } static grub_err_t -grub_cmd_list_env (grub_extcmd_t cmd, +grub_cmd_list_env (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_file_t file; grub_envblk_t envblk; @@ -280,9 +282,9 @@ write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists, } static grub_err_t -grub_cmd_save_env (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_file_t file; grub_envblk_t envblk; struct blocklist *head = 0; diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c index 9ee0a7a31..02915bac4 100644 --- a/grub-core/commands/ls.c +++ b/grub-core/commands/ls.c @@ -105,6 +105,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) /* XXX: For ext2fs symlinks are detected as files while they should be reported as directories. */ + grub_file_filter_disable_compression (); file = grub_file_open (pathname); if (! file) { @@ -211,6 +212,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) struct grub_dirhook_info info; grub_errno = 0; + grub_file_filter_disable_compression (); file = grub_file_open (dirname); if (! file) goto fail; @@ -248,9 +250,9 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) } static grub_err_t -grub_cmd_ls (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_ls (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; if (argc == 0) grub_ls_list_devices (state[0].set); diff --git a/grub-core/commands/lspci.c b/grub-core/commands/lspci.c index a69bb35ad..bc52e060a 100644 --- a/grub-core/commands/lspci.c +++ b/grub-core/commands/lspci.c @@ -211,11 +211,11 @@ grub_lspci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) } static grub_err_t -grub_cmd_lspci (grub_extcmd_t cmd, +grub_cmd_lspci (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - iospace = cmd->state[0].set; + iospace = ctxt->state[0].set; grub_pci_iterate (grub_lspci_iter); return GRUB_ERR_NONE; } diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c index 6a4d43be2..d28f45ec1 100644 --- a/grub-core/commands/memrw.c +++ b/grub-core/commands/memrw.c @@ -35,7 +35,7 @@ static const struct grub_arg_option options[] = static grub_err_t -grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) +grub_cmd_read (grub_extcmd_context_t ctxt, int argc, char **argv) { grub_target_addr_t addr; grub_uint32_t value = 0; @@ -45,7 +45,7 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid number of arguments"); addr = grub_strtoul (argv[0], 0, 0); - switch (cmd->cmd->name[sizeof ("read_") - 1]) + switch (ctxt->extcmd->cmd->name[sizeof ("read_") - 1]) { case 'd': value = *((volatile grub_uint32_t *) addr); @@ -60,10 +60,10 @@ grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) break; } - if (cmd->state[0].set) + if (ctxt->state[0].set) { grub_snprintf (buf, sizeof (buf), "%x", value); - grub_env_set (cmd->state[0].arg, buf); + grub_env_set (ctxt->state[0].arg, buf); } else grub_printf ("0x%x\n", value); diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c new file mode 100644 index 000000000..fc1ae71c7 --- /dev/null +++ b/grub-core/commands/menuentry.c @@ -0,0 +1,285 @@ +/* menuentry.c - menuentry command */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +static const struct grub_arg_option options[] = + { + {"class", 1, GRUB_ARG_OPTION_REPEATABLE, + N_("Menu entry type."), "STRING", ARG_TYPE_STRING}, + {"users", 2, 0, + N_("Users allowed to boot this entry."), "USERNAME", ARG_TYPE_STRING}, + {"hotkey", 3, 0, + N_("Keyboard key for this entry."), "KEY", ARG_TYPE_STRING}, + {"source", 4, 0, + N_("Menu entry definition as a string."), "STRING", ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +static struct +{ + char *name; + int key; +} hotkey_aliases[] = + { + {"backspace", '\b'}, + {"tab", '\t'}, + {"delete", GRUB_TERM_DC} + }; + +/* Add a menu entry to the current menu context (as given by the environment + variable data slot `menu'). As the configuration file is read, the script + parser calls this when a menu entry is to be created. */ +static grub_err_t +append_menu_entry (int argc, const char **args, char **classes, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode) +{ + unsigned i; + int menu_hotkey = 0; + char **menu_args = NULL; + char *menu_users = NULL; + char *menu_title = NULL; + char *menu_sourcecode = NULL; + struct grub_menu_entry_class *menu_classes = NULL; + + grub_menu_t menu; + grub_menu_entry_t *last; + + menu = grub_env_get_menu (); + if (! menu) + return grub_error (GRUB_ERR_MENU, "no menu context"); + + last = &menu->entry_list; + + menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode); + if (! menu_sourcecode) + return grub_errno; + + if (classes) + { + for (i = 0; classes[i]; i++); /* count # of menuentry classes */ + menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class) * i); + if (! menu_classes) + goto fail; + + for (i = 0; classes[i]; i++) + { + menu_classes[i].name = grub_strdup (classes[i]); + if (! menu_classes[i].name) + goto fail; + menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL; + } + } + + if (users) + { + menu_users = grub_strdup (users); + if (! menu_users) + goto fail; + } + + if (hotkey) + { + for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++) + if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0) + { + menu_hotkey = hotkey_aliases[i].key; + break; + } + if (i == ARRAY_SIZE (hotkey_aliases)) + menu_hotkey = hotkey[0]; + } + + if (! argc) + { + grub_error (GRUB_ERR_MENU, "menuentry is missing title"); + goto fail; + } + + menu_title = grub_strdup (args[0]); + if (! menu_title) + goto fail; + + /* Save argc, args to pass as parameters to block arg later. */ + menu_args = grub_malloc (sizeof (char*) * (argc + 1)); + if (! menu_args) + goto fail; + + for (i = 0; args[i]; i++) + { + menu_args[i] = grub_strdup (args[i]); + if (! menu_args[i]) + goto fail; + } + menu_args[argc] = NULL; + + /* Add the menu entry at the end of the list. */ + while (*last) + last = &(*last)->next; + + *last = grub_zalloc (sizeof (**last)); + if (! *last) + goto fail; + + (*last)->title = menu_title; + (*last)->hotkey = menu_hotkey; + (*last)->classes = menu_classes; + if (menu_users) + (*last)->restricted = 1; + (*last)->users = menu_users; + (*last)->argc = argc; + (*last)->args = menu_args; + (*last)->sourcecode = menu_sourcecode; + + menu->size++; + return GRUB_ERR_NONE; + + fail: + + grub_free (menu_sourcecode); + for (i = 0; menu_classes && menu_classes[i].name; i++) + grub_free (menu_classes[i].name); + grub_free (menu_classes); + + for (i = 0; menu_args && menu_args[i]; i++) + grub_free (menu_args[i]); + grub_free (menu_args); + + grub_free (menu_users); + grub_free (menu_title); + return grub_errno; +} + +static char * +setparams_prefix (int argc, char **args) +{ + int i; + int j; + char *p; + char *result; + grub_size_t len = 10; + static const char *escape_characters = "\"\\"; + + auto char *strescpy (char *, const char *, const char *); + char * strescpy (char *d, const char *s, const char *escapes) + { + while (*s) + { + if (grub_strchr (escapes, *s)) + *d++ = '\\'; + *d++ = *s++; + } + *d = '\0'; + return d; + } + + /* Count resulting string length */ + for (i = 0; i < argc; i++) + { + len += 3; /* 3 = 1 space + 2 quotes */ + p = args[i]; + while (*p) + len += grub_strchr (escape_characters, *p++) ? 2 : 1; + } + + result = grub_malloc (len + 2); + if (! result) + return 0; + + grub_strcpy (result, "setparams"); + i = 9; + + for (j = 0; j < argc; j++) + { + result[i++] = ' '; + result[i++] = '"'; + i = strescpy (result + i, args[j], escape_characters) - result; + result[i++] = '"'; + } + result[i++] = '\n'; + result[i] = '\0'; + return result; +} + +static grub_err_t +grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) +{ + char ch; + char *src; + char *prefix; + unsigned len; + grub_err_t r; + + if (! argc) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments"); + + if (ctxt->state[3].set && ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions"); + + if (! ctxt->state[3].set && ! ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition"); + + if (! ctxt->script) + return append_menu_entry (argc, (const char **) args, + ctxt->state[0].args, ctxt->state[1].arg, + ctxt->state[2].arg, 0, ctxt->state[3].arg); + + src = args[argc - 1]; + args[argc - 1] = NULL; + + len = grub_strlen(src); + ch = src[len - 1]; + src[len - 1] = '\0'; + + prefix = setparams_prefix (argc - 1, args); + if (! prefix) + return grub_errno; + + r = append_menu_entry (argc - 1, (const char **) args, + ctxt->state[0].args, ctxt->state[1].arg, + ctxt->state[2].arg, prefix, src + 1); + + src[len - 1] = ch; + args[argc - 1] = src; + grub_free (prefix); + return r; +} + +static grub_extcmd_t cmd; + +void +grub_menu_init (void) +{ + cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry, + GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS, + N_("BLOCK"), N_("Define a menuentry."), options); +} + +void +grub_menu_fini (void) +{ + grub_unregister_extcmd (cmd); +} diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c index d71174598..3d5f59719 100644 --- a/grub-core/commands/minicmd.c +++ b/grub-core/commands/minicmd.c @@ -142,112 +142,6 @@ grub_mini_cmd_root (struct grub_command *cmd __attribute__ ((unused)), return 0; } -#if 0 -static void -grub_rescue_cmd_testload (int argc, char *argv[]) -{ - grub_file_t file; - char *buf; - grub_ssize_t size; - grub_ssize_t pos; - auto void read_func (unsigned long sector, unsigned offset, unsigned len); - - void read_func (unsigned long sector __attribute__ ((unused)), - unsigned offset __attribute__ ((unused)), - unsigned len __attribute__ ((unused))) - { - grub_putchar ('.'); - grub_refresh (); - } - - if (argc < 1) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); - return; - } - - file = grub_file_open (argv[0]); - if (! file) - return; - - size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1); - if (size == 0) - { - grub_file_close (file); - return; - } - - buf = grub_malloc (size); - if (! buf) - goto fail; - - grub_printf ("Reading %s sequentially", argv[0]); - file->read_hook = read_func; - if (grub_file_read (file, buf, size) != size) - goto fail; - grub_printf (" Done.\n"); - - /* Read sequentially again. */ - grub_printf ("Reading %s sequentially again", argv[0]); - if (grub_file_seek (file, 0) < 0) - goto fail; - - for (pos = 0; pos < size; pos += GRUB_DISK_SECTOR_SIZE) - { - char sector[GRUB_DISK_SECTOR_SIZE]; - - if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE) - != GRUB_DISK_SECTOR_SIZE) - goto fail; - - if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0) - { - grub_printf ("\nDiffers in %d\n", pos); - goto fail; - } - } - grub_printf (" Done.\n"); - - /* Read backwards and compare. */ - grub_printf ("Reading %s backwards", argv[0]); - pos = size; - while (pos > 0) - { - char sector[GRUB_DISK_SECTOR_SIZE]; - - pos -= GRUB_DISK_SECTOR_SIZE; - - if (grub_file_seek (file, pos) < 0) - goto fail; - - if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE) - != GRUB_DISK_SECTOR_SIZE) - goto fail; - - if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0) - { - int i; - - grub_printf ("\nDiffers in %d\n", pos); - - for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++) - grub_putchar (buf[pos + i]); - - if (i) - grub_refresh (); - - goto fail; - } - } - grub_printf (" Done.\n"); - - fail: - - grub_file_close (file); - grub_free (buf); -} -#endif - /* dump ADDRESS [SIZE] */ static grub_err_t grub_mini_cmd_dump (struct grub_command *cmd __attribute__ ((unused)), diff --git a/grub-core/commands/probe.c b/grub-core/commands/probe.c index c2cc599e9..f3941e029 100644 --- a/grub-core/commands/probe.c +++ b/grub-core/commands/probe.c @@ -45,9 +45,9 @@ static const struct grub_arg_option options[] = }; static grub_err_t -grub_cmd_probe (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_probe (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_device_t dev; grub_fs_t fs; char *ptr; diff --git a/grub-core/commands/regexp.c b/grub-core/commands/regexp.c index e8e8243b5..4329483af 100644 --- a/grub-core/commands/regexp.c +++ b/grub-core/commands/regexp.c @@ -20,37 +20,104 @@ #include #include #include -#include +#include +#include +#include #include +#include #include +static const struct grub_arg_option options[] = + { + { "set", 's', GRUB_ARG_OPTION_REPEATABLE, + N_("Variable names to update with matches."), + N_("[NUMBER:]VARNAME"), ARG_TYPE_STRING }, + { 0, 0, 0, 0, 0, 0 } + }; + static grub_err_t -grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), - int argc, char **args) +set_matches (char **varnames, char *str, grub_size_t nmatches, + regmatch_t *matches) +{ + int i; + char ch; + char *p; + char *q; + grub_err_t err; + unsigned long j; + + auto void setvar (char *v, regmatch_t *m); + void setvar (char *v, regmatch_t *m) + { + ch = str[m->rm_eo]; + str[m->rm_eo] = '\0'; + err = grub_env_set (v, str + m->rm_so); + str[m->rm_eo] = ch; + } + + for (i = 0; varnames && varnames[i]; i++) + { + if (! (p = grub_strchr (varnames[i], ':'))) + { + /* varname w/o index defaults to 1 */ + if (nmatches < 2 || matches[1].rm_so == -1) + grub_env_unset (varnames[i]); + else + setvar (varnames[i], &matches[1]); + } + else + { + j = grub_strtoul (varnames[i], &q, 10); + if (q != p) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "invalid variable name format %s", varnames[i]); + + if (nmatches <= j || matches[j].rm_so == -1) + grub_env_unset (p + 1); + else + setvar (p + 1, &matches[j]); + } + + if (err != GRUB_ERR_NONE) + return err; + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_regexp (grub_extcmd_context_t ctxt, int argc, char **args) { int argn = 0; - int matches = 0; regex_t regex; int ret; grub_size_t s; char *comperr; grub_err_t err; + regmatch_t *matches = 0; if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected"); - ret = regcomp (®ex, args[0], RE_SYNTAX_GNU_AWK); + ret = regcomp (®ex, args[0], REG_EXTENDED); if (ret) goto fail; - ret = regexec (®ex, args[1], 0, 0, 0); + matches = grub_zalloc (sizeof (*matches) * (regex.re_nsub + 1)); + if (! matches) + goto fail; + + ret = regexec (®ex, args[1], regex.re_nsub + 1, matches, 0); if (!ret) { + err = set_matches (ctxt->state[0].args, args[1], + regex.re_nsub + 1, matches); regfree (®ex); - return GRUB_ERR_NONE; + grub_free (matches); + return err; } fail: + grub_free (matches); s = regerror (ret, ®ex, 0, 0); comperr = grub_malloc (s); if (!comperr) @@ -65,16 +132,20 @@ grub_cmd_regexp (grub_command_t cmd __attribute__ ((unused)), return err; } -static grub_command_t cmd; +static grub_extcmd_t cmd; GRUB_MOD_INIT(regexp) { - cmd = grub_register_command ("regexp", grub_cmd_regexp, - N_("REGEXP STRING"), - N_("Test if REGEXP matches STRING.")); + cmd = grub_register_extcmd ("regexp", grub_cmd_regexp, + GRUB_COMMAND_FLAG_BOTH, N_("REGEXP STRING"), + N_("Test if REGEXP matches STRING."), options); + + /* Setup GRUB script wildcard translator. */ + grub_wildcard_translator = &grub_filename_translator; } GRUB_MOD_FINI(regexp) { - grub_unregister_command (cmd); + grub_unregister_extcmd (cmd); + grub_wildcard_translator = 0; } diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index 71267b117..8a646b452 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -54,6 +54,7 @@ FUNC_NAME (const char *key, const char *var, int no_floppy) if (! buf) return 1; + grub_file_filter_disable_compression (); file = grub_file_open (buf); if (file) { diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c index 2891d85d7..fff3fb47a 100644 --- a/grub-core/commands/search_wrap.c +++ b/grub-core/commands/search_wrap.c @@ -50,9 +50,9 @@ enum options }; static grub_err_t -grub_cmd_search (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; const char *var = 0; if (argc == 0) diff --git a/grub-core/commands/setpci.c b/grub-core/commands/setpci.c index aa09f5bbb..5e947cd7d 100644 --- a/grub-core/commands/setpci.c +++ b/grub-core/commands/setpci.c @@ -155,7 +155,7 @@ grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) } static grub_err_t -grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) +grub_cmd_setpci (grub_extcmd_context_t ctxt, int argc, char **argv) { const char *ptr; unsigned i; @@ -163,14 +163,14 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) pciid_check_value = 0; pciid_check_mask = 0; - if (cmd->state[0].set) + if (ctxt->state[0].set) { - ptr = cmd->state[0].arg; + ptr = ctxt->state[0].arg; pciid_check_value |= (grub_strtoul (ptr, (char **) &ptr, 16) & 0xffff); if (grub_errno == GRUB_ERR_BAD_NUMBER) { grub_errno = GRUB_ERR_NONE; - ptr = cmd->state[0].arg; + ptr = ctxt->state[0].arg; } else pciid_check_mask |= 0xffff; @@ -191,11 +191,11 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) check_bus = check_device = check_function = 0; - if (cmd->state[1].set) + if (ctxt->state[1].set) { const char *optr; - ptr = cmd->state[1].arg; + ptr = ctxt->state[1].arg; optr = ptr; bus = grub_strtoul (ptr, (char **) &ptr, 16); if (grub_errno == GRUB_ERR_BAD_NUMBER) @@ -229,8 +229,8 @@ grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) } } - if (cmd->state[2].set) - varname = cmd->state[2].arg; + if (ctxt->state[2].set) + varname = ctxt->state[2].arg; else varname = NULL; diff --git a/grub-core/commands/sleep.c b/grub-core/commands/sleep.c index ead279506..ee0875cf7 100644 --- a/grub-core/commands/sleep.c +++ b/grub-core/commands/sleep.c @@ -60,9 +60,9 @@ grub_interruptible_millisleep (grub_uint32_t ms) } static grub_err_t -grub_cmd_sleep (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_sleep (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; int n; if (argc != 1) diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c index 6995165cf..97b7fe6e4 100644 --- a/grub-core/commands/test.c +++ b/grub-core/commands/test.c @@ -334,6 +334,7 @@ test_parse (char **args, int *argn, int argc) if (grub_strcmp (args[*argn], "-s") == 0) { grub_file_t file; + grub_file_filter_disable_compression (); file = grub_file_open (args[*argn + 1]); update_val (file && (grub_file_size (file) != 0)); if (file) diff --git a/grub-core/commands/testload.c b/grub-core/commands/testload.c new file mode 100644 index 000000000..3b6ddfae3 --- /dev/null +++ b/grub-core/commands/testload.c @@ -0,0 +1,155 @@ +/* minicmd.c - commands for the rescue mode */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2005,2006,2007,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_err_t +grub_cmd_testload (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file; + char *buf; + grub_size_t size; + grub_off_t pos; + auto void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector, unsigned offset, unsigned len); + + void NESTED_FUNC_ATTR read_func (grub_disk_addr_t sector __attribute__ ((unused)), + unsigned offset __attribute__ ((unused)), + unsigned len __attribute__ ((unused))) + { + grub_xputs ("."); + grub_refresh (); + } + + if (argc < 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); + + file = grub_file_open (argv[0]); + if (! file) + return grub_errno; + + size = grub_file_size (file) & ~(GRUB_DISK_SECTOR_SIZE - 1); + if (size == 0) + { + grub_file_close (file); + return GRUB_ERR_NONE; + } + + buf = grub_malloc (size); + if (! buf) + goto fail; + + grub_printf ("Reading %s sequentially", argv[0]); + file->read_hook = read_func; + if (grub_file_read (file, buf, size) != (grub_ssize_t) size) + goto fail; + grub_printf (" Done.\n"); + + /* Read sequentially again. */ + grub_printf ("Reading %s sequentially again", argv[0]); + grub_file_seek (file, 0); + + for (pos = 0; pos < size; pos += GRUB_DISK_SECTOR_SIZE) + { + char sector[GRUB_DISK_SECTOR_SIZE]; + + if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE) + != GRUB_DISK_SECTOR_SIZE) + goto fail; + + if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0) + { + grub_printf ("\nDiffers in %lld\n", (unsigned long long) pos); + goto fail; + } + } + grub_printf (" Done.\n"); + + /* Read backwards and compare. */ + grub_printf ("Reading %s backwards", argv[0]); + pos = size; + while (pos > 0) + { + char sector[GRUB_DISK_SECTOR_SIZE]; + + pos -= GRUB_DISK_SECTOR_SIZE; + + grub_file_seek (file, pos); + + if (grub_file_read (file, sector, GRUB_DISK_SECTOR_SIZE) + != GRUB_DISK_SECTOR_SIZE) + goto fail; + + if (grub_memcmp (sector, buf + pos, GRUB_DISK_SECTOR_SIZE) != 0) + { + int i; + + grub_printf ("\nDiffers in %lld\n", (unsigned long long) pos); + + for (i = 0; i < GRUB_DISK_SECTOR_SIZE; i++) + { + grub_printf ("%02x ", buf[pos + i]); + if ((i & 15) == 15) + grub_printf ("\n"); + } + + if (i) + grub_refresh (); + + goto fail; + } + } + grub_printf (" Done.\n"); + + return GRUB_ERR_NONE; + + fail: + + grub_file_close (file); + grub_free (buf); + + if (!grub_errno) + grub_error (GRUB_ERR_IO, "bad read"); + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(testload) +{ + cmd = + grub_register_command ("testload", grub_cmd_testload, + N_("FILE"), + N_("Load the same file in multiple ways.")); +} + +GRUB_MOD_FINI(testload) +{ + grub_unregister_command (cmd); +} diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c new file mode 100644 index 000000000..cbe32e0ff --- /dev/null +++ b/grub-core/commands/wildcard.c @@ -0,0 +1,494 @@ +/* wildcard.c - Wildcard character expansion for GRUB script. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +static inline int isregexop (char ch); +static char ** merge (char **lhs, char **rhs); +static char *make_dir (const char *prefix, const char *start, const char *end); +static int make_regex (const char *regex_start, const char *regex_end, + regex_t *regexp); +static void split_path (const char *path, const char **suffix_end, const char **regex_end); +static char ** match_devices (const regex_t *regexp, int noparts); +static char ** match_files (const char *prefix, const char *suffix_start, + const char *suffix_end, const regex_t *regexp); + +static char* wildcard_escape (const char *s); +static char* wildcard_unescape (const char *s); +static grub_err_t wildcard_expand (const char *s, char ***strs); + +struct grub_script_wildcard_translator grub_filename_translator = { + .expand = wildcard_expand, + .escape = wildcard_escape, + .unescape = wildcard_unescape +}; + +static char ** +merge (char **dest, char **ps) +{ + int i; + int j; + char **p; + + if (! dest) + return ps; + + if (! ps) + return dest; + + for (i = 0; dest[i]; i++) + ; + for (j = 0; ps[j]; j++) + ; + + p = grub_realloc (dest, sizeof (char*) * (i + j + 1)); + if (! p) + { + grub_free (dest); + grub_free (ps); + return 0; + } + + dest = p; + for (j = 0; ps[j]; j++) + dest[i++] = ps[j]; + dest[i] = 0; + + grub_free (ps); + return dest; +} + +static inline int +isregexop (char ch) +{ + return grub_strchr ("*.\\", ch) ? 1 : 0; +} + +static char * +make_dir (const char *prefix, const char *start, const char *end) +{ + char ch; + unsigned i; + unsigned n; + char *result; + + i = grub_strlen (prefix); + n = i + end - start; + + result = grub_malloc (n + 1); + if (! result) + return 0; + + grub_strcpy (result, prefix); + while (start < end && (ch = *start++)) + if (ch == '\\' && isregexop (*start)) + result[i++] = *start++; + else + result[i++] = ch; + + result[i] = '\0'; + return result; +} + +static int +make_regex (const char *start, const char *end, regex_t *regexp) +{ + char ch; + int i = 0; + unsigned len = end - start; + char *buffer = grub_malloc (len * 2 + 2 + 1); /* worst case size. */ + + if (! buffer) + return 1; + + buffer[i++] = '^'; + while (start < end) + { + /* XXX Only * expansion for now. */ + switch ((ch = *start++)) + { + case '\\': + buffer[i++] = ch; + if (*start != '\0') + buffer[i++] = *start++; + break; + + case '.': + buffer[i++] = '\\'; + buffer[i++] = '.'; + break; + + case '*': + buffer[i++] = '.'; + buffer[i++] = '*'; + break; + + default: + buffer[i++] = ch; + } + } + buffer[i++] = '$'; + buffer[i] = '\0'; + + if (regcomp (regexp, buffer, RE_SYNTAX_GNU_AWK)) + { + grub_free (buffer); + return 1; + } + + grub_free (buffer); + return 0; +} + +/* Split `str' into two parts: (1) dirname that is regexop free (2) + dirname that has a regexop. */ +static void +split_path (const char *str, const char **noregexop, const char **regexop) +{ + char ch = 0; + int regex = 0; + + const char *end; + const char *split; /* points till the end of dirnaname that doesn't + need expansion. */ + + split = end = str; + while ((ch = *end)) + { + if (ch == '\\' && end[1]) + end++; + + else if (isregexop (ch)) + regex = 1; + + else if (ch == '/' && ! regex) + split = end + 1; /* forward to next regexop-free dirname */ + + else if (ch == '/' && regex) + break; /* stop at the first dirname with a regexop */ + + end++; + } + + *regexop = end; + if (! regex) + *noregexop = end; + else + *noregexop = split; +} + +static char ** +match_devices (const regex_t *regexp, int noparts) +{ + int i; + int ndev; + char **devs; + + auto int match (const char *name); + int match (const char *name) + { + char **t; + char *buffer; + + /* skip partitions if asked to. */ + if (noparts && grub_strchr(name, ',')) + return 0; + + buffer = grub_xasprintf ("(%s)", name); + if (! buffer) + return 1; + + grub_dprintf ("expand", "matching: %s\n", buffer); + if (regexec (regexp, buffer, 0, 0, 0)) + { + grub_free (buffer); + return 0; + } + + t = grub_realloc (devs, sizeof (char*) * (ndev + 2)); + if (! t) + return 1; + + devs = t; + devs[ndev++] = buffer; + devs[ndev] = 0; + return 0; + } + + ndev = 0; + devs = 0; + + if (grub_device_iterate (match)) + goto fail; + + return devs; + + fail: + + for (i = 0; devs && devs[i]; i++) + grub_free (devs[i]); + + if (devs) + grub_free (devs); + + return 0; +} + +static char ** +match_files (const char *prefix, const char *suffix, const char *end, + const regex_t *regexp) +{ + int i; + int error; + char **files; + unsigned nfile; + char *dir; + const char *path; + char *device_name; + grub_fs_t fs; + grub_device_t dev; + + auto int match (const char *name, const struct grub_dirhook_info *info); + int match (const char *name, const struct grub_dirhook_info *info) + { + char **t; + char *buffer; + + /* skip . and .. names */ + if (grub_strcmp(".", name) == 0 || grub_strcmp("..", name) == 0) + return 0; + + grub_dprintf ("expand", "matching: %s in %s\n", name, dir); + if (regexec (regexp, name, 0, 0, 0)) + return 0; + + buffer = grub_xasprintf ("%s%s", dir, name); + if (! buffer) + return 1; + + t = grub_realloc (files, sizeof (char*) * (nfile + 2)); + if (! t) + { + grub_free (buffer); + return 1; + } + + files = t; + files[nfile++] = buffer; + files[nfile] = 0; + return 0; + } + + nfile = 0; + files = 0; + dev = 0; + device_name = 0; + grub_error_push (); + + dir = make_dir (prefix, suffix, end); + if (! dir) + goto fail; + + device_name = grub_file_get_device_name (dir); + dev = grub_device_open (device_name); + if (! dev) + goto fail; + + fs = grub_fs_probe (dev); + if (! fs) + goto fail; + + path = grub_strchr (dir, ')'); + if (! path) + goto fail; + path++; + + if (fs->dir (dev, path, match)) + goto fail; + + grub_free (dir); + grub_device_close (dev); + grub_free (device_name); + grub_error_pop (); + return files; + + fail: + + if (dir) + grub_free (dir); + + for (i = 0; files && files[i]; i++) + grub_free (files[i]); + + if (files) + grub_free (files); + + if (dev) + grub_device_close (dev); + + if (device_name) + grub_free (device_name); + + grub_error_pop (); + return 0; +} + +static char* +wildcard_escape (const char *s) +{ + int i; + int len; + char ch; + char *p; + + len = grub_strlen (s); + p = grub_malloc (len * 2 + 1); + if (! p) + return NULL; + + i = 0; + while ((ch = *s++)) + { + if (isregexop (ch)) + p[i++] = '\\'; + p[i++] = ch; + } + p[i] = '\0'; + return p; +} + +static char* +wildcard_unescape (const char *s) +{ + int i; + int len; + char ch; + char *p; + + len = grub_strlen (s); + p = grub_malloc (len + 1); + if (! p) + return NULL; + + i = 0; + while ((ch = *s++)) + { + if (ch == '\\' && isregexop (*s)) + p[i++] = *s++; + else + p[i++] = ch; + } + p[i] = '\0'; + return p; +} + +static grub_err_t +wildcard_expand (const char *s, char ***strs) +{ + const char *start; + const char *regexop; + const char *noregexop; + char **paths = 0; + + unsigned i; + regex_t regexp; + + start = s; + while (*start) + { + split_path (start, &noregexop, ®exop); + if (noregexop >= regexop) /* no more wildcards */ + break; + + if (make_regex (noregexop, regexop, ®exp)) + goto fail; + + if (paths == 0) + { + if (start == noregexop) /* device part has regexop */ + paths = match_devices (®exp, *start != '('); + + else if (*start == '(') /* device part explicit wo regexop */ + paths = match_files ("", start, noregexop, ®exp); + + else if (*start == '/') /* no device part */ + { + char **r; + unsigned n; + char *root; + char *prefix; + + root = grub_env_get ("root"); + if (! root) + goto fail; + + prefix = grub_xasprintf ("(%s)", root); + if (! prefix) + goto fail; + + paths = match_files (prefix, start, noregexop, ®exp); + grub_free (prefix); + } + } + else + { + char **r = 0; + + for (i = 0; paths[i]; i++) + { + char **p; + + p = match_files (paths[i], start, noregexop, ®exp); + if (! p) + continue; + + r = merge (r, p); + if (! r) + goto fail; + } + paths = r; + } + + regfree (®exp); + if (! paths) + goto done; + + start = regexop; + } + + done: + + *strs = paths; + return 0; + + fail: + + for (i = 0; paths && paths[i]; i++) + grub_free (paths[i]); + grub_free (paths[i]); + regfree (®exp); + return grub_errno; +} diff --git a/grub-core/disk/i386/pc/biosdisk.c b/grub-core/disk/i386/pc/biosdisk.c index a00236e50..17de0c1a1 100644 --- a/grub-core/disk/i386/pc/biosdisk.c +++ b/grub-core/disk/i386/pc/biosdisk.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,219 @@ #include static int cd_drive = 0; +static int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap); + +static int grub_biosdisk_get_num_floppies (void) +{ + struct grub_bios_int_registers regs; + int drive; + + /* reset the disk system first */ + regs.eax = 0; + regs.edx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + grub_bios_interrupt (0x13, ®s); + + for (drive = 0; drive < 2; drive++) + { + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT | GRUB_CPU_INT_FLAGS_CARRY; + regs.edx = drive; + + /* call GET DISK TYPE */ + regs.eax = 0x1500; + grub_bios_interrupt (0x13, ®s); + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + break; + + /* check if this drive exists */ + if (!(regs.eax & 0x300)) + break; + } + + return drive; +} + +/* + * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP + * is passed for disk address packet. If an error occurs, return + * non-zero, otherwise zero. + */ + +static int +grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap) +{ + struct grub_bios_int_registers regs; + regs.eax = ah << 8; + /* compute the address of disk_address_packet */ + regs.ds = (((grub_addr_t) dap) & 0xffff0000) >> 4; + regs.esi = (((grub_addr_t) dap) & 0xffff); + regs.edx = drive; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + grub_bios_interrupt (0x13, ®s); + return (regs.eax >> 8) & 0xff; +} + +/* + * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write + * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs, + * return non-zero, otherwise zero. + */ +static int +grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff, + int soff, int nsec, int segment) +{ + int ret, i; + + /* Try 3 times. */ + for (i = 0; i < 3; i++) + { + struct grub_bios_int_registers regs; + + /* set up CHS information */ + /* set %ch to low eight bits of cylinder */ + regs.ecx = (coff << 8) & 0xff00; + /* set bits 6-7 of %cl to high two bits of cylinder */ + regs.ecx |= (coff >> 2) & 0xc0; + /* set bits 0-5 of %cl to sector */ + regs.ecx |= soff & 0x3f; + + /* set %dh to head and %dl to drive */ + regs.edx = (drive & 0xff) | ((hoff << 8) & 0xff00); + /* set %ah to AH */ + regs.eax = (ah << 8) & 0xff00; + /* set %al to NSEC */ + regs.eax |= nsec & 0xff; + + regs.ebx = 0; + regs.es = segment; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + grub_bios_interrupt (0x13, ®s); + /* check if successful */ + if (!(regs.flags & GRUB_CPU_INT_FLAGS_CARRY)) + return 0; + + /* save return value */ + ret = regs.eax >> 8; + + /* if fail, reset the disk system */ + regs.eax = 0; + regs.edx = (drive & 0xff); + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x13, ®s); + } + return ret; +} + +/* + * Check if LBA is supported for DRIVE. If it is supported, then return + * the major version of extensions, otherwise zero. + */ +static int +grub_biosdisk_check_int13_extensions (int drive) +{ + struct grub_bios_int_registers regs; + + regs.edx = drive & 0xff; + regs.eax = 0x4100; + regs.ebx = 0x55aa; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x13, ®s); + + if (regs.flags & GRUB_CPU_INT_FLAGS_CARRY) + return 0; + + if ((regs.ebx & 0xffff) != 0xaa55) + return 0; + + /* check if AH=0x42 is supported */ + if (!(regs.ecx & 1)) + return 0; + + return (regs.eax >> 8) & 0xff; +} + +/* + * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an + * error occurs, then return non-zero, otherwise zero. + */ +static int +grub_biosdisk_get_diskinfo_standard (int drive, + unsigned long *cylinders, + unsigned long *heads, + unsigned long *sectors) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x0800; + regs.edx = drive & 0xff; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x13, ®s); + + /* Check if unsuccessful. Ignore return value if carry isn't set to + workaround some buggy BIOSes. */ + if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0)) + return (regs.eax & 0xff00) >> 8; + + /* bogus BIOSes may not return an error number */ + /* 0 sectors means no disk */ + if (!(regs.ecx & 0x3f)) + /* XXX 0x60 is one of the unused error numbers */ + return 0x60; + + /* the number of heads is counted from zero */ + *heads = ((regs.edx >> 8) & 0xff) + 1; + *cylinders = (((regs.ecx >> 8) & 0xff) | ((regs.ecx << 2) & 0x0300)) + 1; + *sectors = regs.ecx & 0x3f; + return 0; +} + +static int +grub_biosdisk_get_diskinfo_real (int drive, void *drp, grub_uint16_t ax) +{ + struct grub_bios_int_registers regs; + + regs.eax = ax; + + /* compute the address of drive parameters */ + regs.esi = ((grub_addr_t) drp) & 0xf; + regs.ds = ((grub_addr_t) drp) >> 4; + regs.edx = drive & 0xff; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x13, ®s); + + /* Check if unsuccessful. Ignore return value if carry isn't set to + workaround some buggy BIOSes. */ + if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) && ((regs.eax & 0xff00) != 0)) + return (regs.eax & 0xff00) >> 8; + + return 0; +} + +/* + * Return the cdrom information of DRIVE in CDRP. If an error occurs, + * then return non-zero, otherwise zero. + */ +static int +grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp) +{ + return grub_biosdisk_get_diskinfo_real (drive, cdrp, 0x4b01); +} + +/* + * Return the geometry of DRIVE in a drive parameters, DRP. If an error + * occurs, then return non-zero, otherwise zero. + */ +static int +grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp) +{ + return grub_biosdisk_get_diskinfo_real (drive, drp, 0x4800); +} static int grub_biosdisk_get_drive (const char *name) diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c index 509e9e33f..878369e5f 100644 --- a/grub-core/disk/loopback.c +++ b/grub-core/disk/loopback.c @@ -71,9 +71,9 @@ delete_loopback (const char *name) /* The command to add and remove loopback devices. */ static grub_err_t -grub_cmd_loopback (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = state = cmd->state; + struct grub_arg_list *state = ctxt->state; grub_file_t file; struct grub_loopback *newdev; grub_err_t ret; @@ -167,8 +167,11 @@ grub_loopback_open (const char *name, grub_disk_t disk) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); /* Use the filesize for the disk size, round up to a complete sector. */ - disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1) - / GRUB_DISK_SECTOR_SIZE); + if (dev->file->size != GRUB_FILE_SIZE_UNKNOWN) + disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1) + / GRUB_DISK_SECTOR_SIZE); + else + disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; disk->id = (unsigned long) dev; disk->has_partitions = dev->has_partitions; diff --git a/grub-core/efiemu/i386/coredetect.c b/grub-core/efiemu/i386/coredetect.c index 828508dee..975c4aa5d 100644 --- a/grub-core/efiemu/i386/coredetect.c +++ b/grub-core/efiemu/i386/coredetect.c @@ -17,7 +17,6 @@ */ #include -#include #include #define cpuid(num,a,b,c,d) \ diff --git a/include/grub/sparc64/ieee1275/loader.h b/grub-core/efiemu/i386/nocfgtables.c similarity index 71% rename from include/grub/sparc64/ieee1275/loader.h rename to grub-core/efiemu/i386/nocfgtables.c index 12bb2a69b..775f1d03a 100644 --- a/include/grub/sparc64/ieee1275/loader.h +++ b/grub-core/efiemu/i386/nocfgtables.c @@ -1,3 +1,4 @@ +/* Register SMBIOS and ACPI tables. */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2009 Free Software Foundation, Inc. @@ -16,12 +17,14 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 +#include +#include +#include +#include +#include -/* The symbol shared between the normal mode and rescue mode - loader. */ -void grub_rescue_cmd_linux (int argc, char *argv[]); -void grub_rescue_cmd_initrd (int argc, char *argv[]); - -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ +grub_err_t +grub_machine_efiemu_init_tables (void) +{ + return GRUB_ERR_NONE; +} diff --git a/grub-core/efiemu/i386/pc/cfgtables.c b/grub-core/efiemu/i386/pc/cfgtables.c index 9c6b4e55e..9287d3a94 100644 --- a/grub-core/efiemu/i386/pc/cfgtables.c +++ b/grub-core/efiemu/i386/pc/cfgtables.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/grub-core/efiemu/loadcore.c b/grub-core/efiemu/loadcore.c index 4bf26ee44..edadd4580 100644 --- a/grub-core/efiemu/loadcore.c +++ b/grub-core/efiemu/loadcore.c @@ -22,7 +22,6 @@ #include #include #include -#include #include /* ELF symbols and their values */ diff --git a/grub-core/efiemu/main.c b/grub-core/efiemu/main.c index b197a8b2c..ee78afe7d 100644 --- a/grub-core/efiemu/main.c +++ b/grub-core/efiemu/main.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -183,22 +182,6 @@ grub_cmd_efiemu_prepare (grub_command_t cmd __attribute__ ((unused)), - -int -grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key - __attribute__ ((unused))) -{ - /* Nothing to do here yet */ - return 1; -} - -int -grub_efiemu_finish_boot_services (void) -{ - /* Nothing to do here yet */ - return 1; -} - /* Load the runtime from the file FILENAME. */ static grub_err_t grub_efiemu_load_file (const char *filename) diff --git a/grub-core/efiemu/mm.c b/grub-core/efiemu/mm.c index 4b293606f..de7d309be 100644 --- a/grub-core/efiemu/mm.c +++ b/grub-core/efiemu/mm.c @@ -323,6 +323,25 @@ grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size, return 1; } +grub_err_t +grub_efiemu_finish_boot_services (grub_efi_uintn_t *memory_map_size, + grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version) +{ + int val = grub_efiemu_get_memory_map (memory_map_size, + memory_map, map_key, + descriptor_size, + descriptor_version); + if (val == 1) + return GRUB_ERR_NONE; + if (val == -1) + return grub_errno; + return grub_error (GRUB_ERR_IO, "memory map buffer is too small"); +} + + /* Free everything */ grub_err_t grub_efiemu_mm_unload (void) diff --git a/grub-core/efiemu/runtime/efiemu.sh b/grub-core/efiemu/runtime/efiemu.sh deleted file mode 100644 index 5a492dc2f..000000000 --- a/grub-core/efiemu/runtime/efiemu.sh +++ /dev/null @@ -1,4 +0,0 @@ -gcc -c -m32 -DELF32 -o efiemu32.o ./efiemu.c -Wall -Werror -nostdlib -O2 -I. -I../../include -gcc -c -m64 -DELF64 -o efiemu64_c.o ./efiemu.c -Wall -Werror -mcmodel=large -O2 -I. -I../../include -gcc -c -m64 -DELF64 -o efiemu64_s.o ./efiemu.S -Wall -Werror -mcmodel=large -O2 -I. -I../../include -ld -o efiemu64.o -r efiemu64_s.o efiemu64_c.o -nostdlib diff --git a/grub-core/fs/i386/pc/pxe.c b/grub-core/fs/i386/pc/pxe.c index e4d481a8e..baaff0ffc 100644 --- a/grub-core/fs/i386/pc/pxe.c +++ b/grub-core/fs/i386/pc/pxe.c @@ -27,6 +27,7 @@ #include #include +#include #include #define SEGMENT(x) ((x) >> 4) @@ -40,7 +41,7 @@ struct grub_pxe_disk_data grub_uint32_t gateway_ip; }; -struct grub_pxenv *grub_pxe_pxenv; +struct grub_pxe_bangpxe *grub_pxe_pxenv; static grub_uint32_t grub_pxe_your_ip; static grub_uint32_t grub_pxe_default_server_ip; static grub_uint32_t grub_pxe_default_gateway_ip; @@ -55,6 +56,51 @@ struct grub_pxe_data char filename[0]; }; +static grub_uint32_t pxe_rm_entry = 0; + +static struct grub_pxe_bangpxe * +grub_pxe_scan (void) +{ + struct grub_bios_int_registers regs; + struct grub_pxenv *pxenv; + struct grub_pxe_bangpxe *bangpxe; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + regs.ebx = 0; + regs.ecx = 0; + regs.eax = 0x5650; + regs.es = 0; + + grub_bios_interrupt (0x1a, ®s); + + if ((regs.eax & 0xffff) != 0x564e) + return NULL; + + pxenv = (struct grub_pxenv *) ((regs.es << 4) + (regs.ebx & 0xffff)); + if (grub_memcmp (pxenv->signature, GRUB_PXE_SIGNATURE, + sizeof (pxenv->signature)) + != 0) + return NULL; + + if (pxenv->version < 0x201) + return NULL; + + bangpxe = (void *) ((((pxenv->pxe_ptr & 0xffff0000) >> 16) << 4) + + (pxenv->pxe_ptr & 0xffff)); + + if (!bangpxe) + return NULL; + + if (grub_memcmp (bangpxe->signature, GRUB_PXE_BANGPXE_SIGNATURE, + sizeof (bangpxe->signature)) != 0) + return NULL; + + pxe_rm_entry = bangpxe->rm_entry; + + return bangpxe; +} + static int grub_pxe_iterate (int (*hook) (const char *name)) { @@ -202,14 +248,14 @@ grub_pxefs_open (struct grub_file *file, const char *name) if (curr_file != 0) { - grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c.c2); + grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c.c2, pxe_rm_entry); curr_file = 0; } c.c1.server_ip = disk_data->server_ip; c.c1.gateway_ip = disk_data->gateway_ip; grub_strcpy ((char *)&c.c1.filename[0], name); - grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1); + grub_pxe_call (GRUB_PXENV_TFTP_GET_FSIZE, &c.c1, pxe_rm_entry); if (c.c1.status) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); @@ -217,7 +263,7 @@ grub_pxefs_open (struct grub_file *file, const char *name) c.c2.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT); c.c2.packet_size = grub_pxe_blksize; - grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &c.c2); + grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &c.c2, pxe_rm_entry); if (c.c2.status) return grub_error (GRUB_ERR_BAD_FS, "open fails"); @@ -236,6 +282,7 @@ grub_pxefs_open (struct grub_file *file, const char *name) } file->data = data; + file->not_easly_seekable = 1; grub_memcpy (file_int, file, sizeof (struct grub_file)); curr_file = file_int; @@ -275,14 +322,14 @@ grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len) struct grub_pxenv_tftp_open o; if (curr_file != 0) - grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o); + grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &o, pxe_rm_entry); o.server_ip = disk_data->server_ip; o.gateway_ip = disk_data->gateway_ip; grub_strcpy ((char *)&o.filename[0], data->filename); o.tftp_port = grub_cpu_to_be16 (GRUB_PXE_TFTP_PORT); - o.packet_size = grub_pxe_blksize; - grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &o); + o.packet_size = data->block_size; + grub_pxe_call (GRUB_PXENV_TFTP_OPEN, &o, pxe_rm_entry); if (o.status) { grub_error (GRUB_ERR_BAD_FS, "open fails"); @@ -297,7 +344,7 @@ grub_pxefs_read (grub_file_t file, char *buf, grub_size_t len) while (pn >= data->packet_number) { c.buffer_size = data->block_size; - grub_pxe_call (GRUB_PXENV_TFTP_READ, &c); + grub_pxe_call (GRUB_PXENV_TFTP_READ, &c, pxe_rm_entry); if (c.status) { grub_error (GRUB_ERR_BAD_FS, "read fails"); @@ -318,7 +365,7 @@ grub_pxefs_close (grub_file_t file) if (curr_file == file) { - grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c); + grub_pxe_call (GRUB_PXENV_TFTP_CLOSE, &c, pxe_rm_entry); curr_file = 0; } @@ -443,7 +490,7 @@ parse_dhcp_vendor (void *vend, int limit) static void grub_pxe_detect (void) { - struct grub_pxenv *pxenv; + struct grub_pxe_bangpxe *pxenv; struct grub_pxenv_get_cached_info ci; struct grub_pxenv_boot_player *bp; @@ -454,7 +501,7 @@ grub_pxe_detect (void) ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK; ci.buffer = 0; ci.buffer_size = 0; - grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci); + grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci, pxe_rm_entry); if (ci.status) return; diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c index 8329c01a1..e529775f4 100644 --- a/grub-core/fs/nilfs2.c +++ b/grub-core/fs/nilfs2.c @@ -718,10 +718,13 @@ grub_nilfs2_load_sb (struct grub_nilfs2_data *data) grub_uint64_t partition_size; int valid[2]; int swp = 0; + grub_err_t err; /* Read first super block. */ - grub_disk_read (disk, NILFS_1ST_SUPER_BLOCK, 0, - sizeof (struct grub_nilfs2_super_block), &data->sblock); + err = grub_disk_read (disk, NILFS_1ST_SUPER_BLOCK, 0, + sizeof (struct grub_nilfs2_super_block), &data->sblock); + if (err) + return err; /* Make sure if 1st super block is valid. */ valid[0] = grub_nilfs2_valid_sb (&data->sblock); @@ -729,17 +732,21 @@ grub_nilfs2_load_sb (struct grub_nilfs2_data *data) if (partition_size != GRUB_DISK_SIZE_UNKNOWN) { /* Read second super block. */ - 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); + err = grub_disk_read (disk, NILFS_2ND_SUPER_BLOCK (partition_size), 0, + sizeof (struct grub_nilfs2_super_block), &sb2); + if (err) + { + valid[1] = 0; + grub_errno = GRUB_ERR_NONE; + } + else + /* Make sure if 2nd super block is valid. */ + valid[1] = grub_nilfs2_valid_sb (&sb2); } else /* 2nd super block may not exist, so it's invalid. */ valid[1] = 0; - - if (!valid[0] && !valid[1]) return grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem"); @@ -752,8 +759,7 @@ grub_nilfs2_load_sb (struct grub_nilfs2_data *data) grub_memcpy (&data->sblock, &sb2, sizeof (struct grub_nilfs2_super_block)); - grub_errno = GRUB_ERR_NONE; - return grub_errno; + return GRUB_ERR_NONE; } static struct grub_nilfs2_data * diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c index bc7d42824..2f94ac030 100644 --- a/grub-core/gettext/gettext.c +++ b/grub-core/gettext/gettext.c @@ -26,7 +26,6 @@ #include #include #include -#include #include /* @@ -219,7 +218,7 @@ grub_gettext_translate (const char *orig) return ret; } -/* This is similar to grub_gzfile_open. */ +/* This is similar to grub_file_open. */ static grub_file_t grub_mofile_open (const char *filename) { @@ -229,7 +228,7 @@ grub_mofile_open (const char *filename) /* Using fd_mo and not another variable because it's needed for grub_gettext_get_info. */ - fd_mo = grub_gzfile_open (filename, 1); + fd_mo = grub_file_open (filename); grub_errno = GRUB_ERR_NONE; if (!fd_mo) diff --git a/grub-core/hello/hello.c b/grub-core/hello/hello.c index eff07d941..183ee7798 100644 --- a/grub-core/hello/hello.c +++ b/grub-core/hello/hello.c @@ -27,7 +27,7 @@ #include static grub_err_t -grub_cmd_hello (struct grub_extcmd *cmd __attribute__ ((unused)), +grub_cmd_hello (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c index 92f29279e..8a72ecd79 100644 --- a/grub-core/io/bufio.c +++ b/grub-core/io/bufio.c @@ -74,6 +74,7 @@ grub_bufio_open (grub_file_t io, int size) file->data = bufio; file->read_hook = 0; file->fs = &grub_bufio_fs; + file->not_easly_seekable = io->not_easly_seekable; return file; } diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c index 9bf609105..43b67c373 100644 --- a/grub-core/io/gzio.c +++ b/grub-core/io/gzio.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include /* * Window Size @@ -206,7 +206,7 @@ test_header (grub_file_t file) || ((hdr.flags & ORIG_NAME) && eat_field (gzio->file, -1)) || ((hdr.flags & COMMENT) && eat_field (gzio->file, -1))) { - grub_error (GRUB_ERR_BAD_GZIP_DATA, "unsupported gzip format"); + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "unsupported gzip format"); return 0; } @@ -214,12 +214,14 @@ test_header (grub_file_t file) grub_file_seek (gzio->file, grub_file_size (gzio->file) - 4); - if (grub_file_read (gzio->file, &orig_len, 4) != 4) + if (grub_file_seekable (gzio->file)) { - grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported gzip format"); - return 0; + if (grub_file_read (gzio->file, &orig_len, 4) != 4) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "unsupported gzip format"); + return 0; + } } - /* FIXME: this does not handle files whose original size is over 4GB. But how can we know the real original size? */ file->size = grub_le_to_cpu32 (orig_len); @@ -644,7 +646,7 @@ inflate_codes_in_window (grub_file_t file) { if (e == 99) { - grub_error (GRUB_ERR_BAD_GZIP_DATA, + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "an unused code found"); return 1; } @@ -683,7 +685,7 @@ inflate_codes_in_window (grub_file_t file) { if (e == 99) { - grub_error (GRUB_ERR_BAD_GZIP_DATA, + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "an unused code found"); return 1; } @@ -769,7 +771,7 @@ init_stored_block (grub_file_t file) DUMPBITS (16); NEEDBITS (16); if (gzio->block_len != (int) ((~b) & 0xffff)) - grub_error (GRUB_ERR_BAD_GZIP_DATA, + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "the length of a stored block does not match"); DUMPBITS (16); @@ -803,7 +805,7 @@ init_fixed_block (grub_file_t file) if (huft_build (l, 288, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0) { if (grub_errno == GRUB_ERR_NONE) - grub_error (GRUB_ERR_BAD_GZIP_DATA, + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "failed in building a Huffman code table"); return; } @@ -815,7 +817,7 @@ init_fixed_block (grub_file_t file) if (huft_build (l, 30, 0, cpdist, cpdext, &gzio->td, &gzio->bd) > 1) { if (grub_errno == GRUB_ERR_NONE) - grub_error (GRUB_ERR_BAD_GZIP_DATA, + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "failed in building a Huffman code table"); huft_free (gzio->tl); gzio->tl = 0; @@ -862,7 +864,7 @@ init_dynamic_block (grub_file_t file) DUMPBITS (4); if (nl > 286 || nd > 30) { - grub_error (GRUB_ERR_BAD_GZIP_DATA, "too much data"); + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too much data"); return; } @@ -880,7 +882,7 @@ init_dynamic_block (grub_file_t file) gzio->bl = 7; if (huft_build (ll, 19, 19, NULL, NULL, &gzio->tl, &gzio->bl) != 0) { - grub_error (GRUB_ERR_BAD_GZIP_DATA, + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "failed in building a Huffman code table"); return; } @@ -904,7 +906,7 @@ init_dynamic_block (grub_file_t file) DUMPBITS (2); if ((unsigned) i + j > n) { - grub_error (GRUB_ERR_BAD_GZIP_DATA, "too many codes found"); + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found"); return; } while (j--) @@ -917,7 +919,7 @@ init_dynamic_block (grub_file_t file) DUMPBITS (3); if ((unsigned) i + j > n) { - grub_error (GRUB_ERR_BAD_GZIP_DATA, "too many codes found"); + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found"); return; } while (j--) @@ -932,7 +934,7 @@ init_dynamic_block (grub_file_t file) DUMPBITS (7); if ((unsigned) i + j > n) { - grub_error (GRUB_ERR_BAD_GZIP_DATA, "too many codes found"); + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "too many codes found"); return; } while (j--) @@ -954,7 +956,7 @@ init_dynamic_block (grub_file_t file) gzio->bl = lbits; if (huft_build (ll, nl, 257, cplens, cplext, &gzio->tl, &gzio->bl) != 0) { - grub_error (GRUB_ERR_BAD_GZIP_DATA, + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "failed in building a Huffman code table"); return; } @@ -963,7 +965,7 @@ init_dynamic_block (grub_file_t file) { huft_free (gzio->tl); gzio->tl = 0; - grub_error (GRUB_ERR_BAD_GZIP_DATA, + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "failed in building a Huffman code table"); return; } @@ -1039,7 +1041,7 @@ inflate_window (grub_file_t file) } if (gzio->block_type > INFLATE_DYNAMIC) - grub_error (GRUB_ERR_BAD_GZIP_DATA, + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "unknown block type %d", gzio->block_type); if (grub_errno != GRUB_ERR_NONE) @@ -1111,8 +1113,8 @@ initialize_tables (grub_file_t file) /* Open a new decompressing object on the top of IO. If TRANSPARENT is true, even if IO does not contain data compressed by gzip, return a valid file object. Note that this function won't close IO, even if an error occurs. */ -grub_file_t -grub_gzio_open (grub_file_t io, int transparent) +static grub_file_t +grub_gzio_open (grub_file_t io) { grub_file_t file; grub_gzio_t gzio = 0; @@ -1135,6 +1137,7 @@ grub_gzio_open (grub_file_t io, int transparent) file->data = gzio; file->read_hook = 0; file->fs = &grub_gzio_fs; + file->not_easly_seekable = 1; if (! test_header (file)) { @@ -1142,33 +1145,11 @@ grub_gzio_open (grub_file_t io, int transparent) grub_free (file); grub_file_seek (io, 0); - if (grub_errno == GRUB_ERR_BAD_FILE_TYPE && transparent) + if (grub_errno == GRUB_ERR_BAD_FILE_TYPE) { grub_errno = GRUB_ERR_NONE; return io; } - else - return 0; - } - - return file; -} - -/* This is similar to grub_gzio_open, but takes a file name as an argument. */ -grub_file_t -grub_gzfile_open (const char *name, int transparent) -{ - grub_file_t io, file; - - io = grub_file_open (name); - if (! io) - return 0; - - file = grub_gzio_open (io, transparent); - if (! file) - { - grub_file_close (io); - return 0; } return file; @@ -1249,3 +1230,13 @@ static struct grub_fs grub_gzio_fs = .label = 0, .next = 0 }; + +GRUB_MOD_INIT(gzio) +{ + grub_file_filter_register (GRUB_FILE_FILTER_GZIO, grub_gzio_open); +} + +GRUB_MOD_FINI(gzio) +{ + grub_file_filter_unregister (GRUB_FILE_FILTER_GZIO); +} diff --git a/grub-core/io/xzio.c b/grub-core/io/xzio.c new file mode 100644 index 000000000..1a22bdc70 --- /dev/null +++ b/grub-core/io/xzio.c @@ -0,0 +1,353 @@ +/* xzio.c - decompression support for xz */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "xz.h" +#include "xz_stream.h" + +#define XZBUFSIZ 0x2000 +#define VLI_MAX_DIGITS 9 +#define XZ_STREAM_FOOTER_SIZE 12 + +struct grub_xzio +{ + grub_file_t file; + struct xz_buf buf; + struct xz_dec *dec; + grub_uint8_t inbuf[XZBUFSIZ]; + grub_uint8_t outbuf[XZBUFSIZ]; + grub_off_t saved_offset; +}; + +typedef struct grub_xzio *grub_xzio_t; +static struct grub_fs grub_xzio_fs; + +static grub_size_t +decode_vli (const grub_uint8_t buf[], grub_size_t size_max, + grub_uint64_t * num) +{ + if (size_max == 0) + return 0; + + if (size_max > VLI_MAX_DIGITS) + size_max = VLI_MAX_DIGITS; + + *num = buf[0] & 0x7F; + grub_size_t i = 0; + + while (buf[i++] & 0x80) + { + if (i >= size_max || buf[i] == 0x00) + return 0; + + *num |= (uint64_t) (buf[i] & 0x7F) << (i * 7); + } + + return i; +} + +static grub_ssize_t +read_vli (grub_file_t file, grub_uint64_t * num) +{ + grub_uint8_t buf[VLI_MAX_DIGITS]; + grub_ssize_t read; + grub_size_t dec; + + read = grub_file_read (file, buf, VLI_MAX_DIGITS); + if (read < 0) + return -1; + + dec = decode_vli (buf, read, num); + grub_file_seek (file, file->offset - (read - dec)); + return dec; +} + +/* Function xz_dec_run() should consume header and ask for more (XZ_OK) + * else file is corrupted (or options not supported) or not xz. */ +static int +test_header (grub_file_t file) +{ + grub_xzio_t xzio = file->data; + xzio->buf.in_size = grub_file_read (xzio->file, xzio->inbuf, + STREAM_HEADER_SIZE); + + if (xzio->buf.in_size != STREAM_HEADER_SIZE) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "no xz magic found"); + return 0; + } + + enum xz_ret ret = xz_dec_run (xzio->dec, &xzio->buf); + + if (ret == XZ_FORMAT_ERROR) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "no xz magic found"); + return 0; + } + + if (ret != XZ_OK) + { + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "not supported xz options"); + return 0; + } + + return 1; +} + +/* Try to find out size of uncompressed data, + * also do some footer sanity checks. */ +static int +test_footer (grub_file_t file) +{ + grub_xzio_t xzio = file->data; + grub_uint8_t footer[FOOTER_MAGIC_SIZE]; + grub_uint32_t backsize; + grub_uint8_t imarker; + grub_uint64_t uncompressed_size_total = 0; + grub_uint64_t uncompressed_size; + grub_uint64_t records; + + grub_file_seek (xzio->file, xzio->file->size - FOOTER_MAGIC_SIZE); + if (grub_file_read (xzio->file, footer, FOOTER_MAGIC_SIZE) != + FOOTER_MAGIC_SIZE + || grub_memcmp (footer, FOOTER_MAGIC, FOOTER_MAGIC_SIZE) != 0) + goto ERROR; + + grub_file_seek (xzio->file, xzio->file->size - 8); + if (grub_file_read (xzio->file, &backsize, sizeof (backsize)) + != sizeof (backsize)) + goto ERROR; + + /* Calculate real backward size. */ + backsize = (grub_le_to_cpu32 (backsize) + 1) * 4; + + /* Set file to the beginning of stream index. */ + grub_file_seek (xzio->file, + xzio->file->size - XZ_STREAM_FOOTER_SIZE - backsize); + + /* Test index marker. */ + if (grub_file_read (xzio->file, &imarker, sizeof (imarker)) != + sizeof (imarker) && imarker != 0x00) + goto ERROR; + + if (read_vli (xzio->file, &records) <= 0) + goto ERROR; + + for (; records != 0; records--) + { + if (read_vli (xzio->file, &uncompressed_size) <= 0) /* Ignore unpadded. */ + goto ERROR; + if (read_vli (xzio->file, &uncompressed_size) <= 0) /* Uncompressed. */ + goto ERROR; + + uncompressed_size_total += uncompressed_size; + } + + file->size = uncompressed_size_total; + grub_file_seek (xzio->file, STREAM_HEADER_SIZE); + return 1; + +ERROR: + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, "bad footer magic"); + return 0; +} + +static grub_file_t +grub_xzio_open (grub_file_t io) +{ + grub_file_t file; + grub_xzio_t xzio; + + file = (grub_file_t) grub_zalloc (sizeof (*file)); + if (!file) + return 0; + + xzio = grub_zalloc (sizeof (*xzio)); + if (!xzio) + { + grub_free (file); + return 0; + } + + xzio->file = io; + xzio->saved_offset = 0; + + file->device = io->device; + file->offset = 0; + file->data = xzio; + file->read_hook = 0; + file->fs = &grub_xzio_fs; + file->size = GRUB_FILE_SIZE_UNKNOWN; + file->not_easly_seekable = 1; + + if (grub_file_tell (xzio->file) != 0) + grub_file_seek (xzio->file, 0); + + /* Allocated 64KiB for dictionary. + * Decoder will relocate if bigger is needed. */ + xzio->dec = xz_dec_init (1 << 16); + if (!xzio->dec) + { + grub_free (file); + grub_free (xzio); + return 0; + } + + xzio->buf.in = xzio->inbuf; + xzio->buf.in_pos = 0; + xzio->buf.in_size = 0; + xzio->buf.out = xzio->outbuf; + xzio->buf.out_pos = 0; + xzio->buf.out_size = XZBUFSIZ; + + if (!test_header (file) || !(grub_file_seekable (io) && test_footer (file))) + { + grub_errno = GRUB_ERR_NONE; + grub_file_seek (io, 0); + xz_dec_end (xzio->dec); + grub_free (xzio); + grub_free (file); + + return io; + } + + return file; +} + +static grub_ssize_t +grub_xzio_read (grub_file_t file, char *buf, grub_size_t len) +{ + grub_ssize_t ret = 0; + grub_ssize_t readret; + enum xz_ret xzret; + grub_xzio_t xzio = file->data; + grub_off_t current_offset; + + /* If seek backward need to reset decoder and start from beginning of file. + TODO Possible improvement by jumping blocks. */ + if (file->offset < xzio->saved_offset) + { + xz_dec_reset (xzio->dec); + xzio->saved_offset = 0; + xzio->buf.out_pos = 0; + xzio->buf.in_pos = 0; + xzio->buf.in_size = 0; + grub_file_seek (xzio->file, 0); + } + + current_offset = xzio->saved_offset; + + while (len > 0) + { + xzio->buf.out_size = grub_min (file->offset + ret + len - current_offset, + XZBUFSIZ); + + /* Feed input. */ + if (xzio->buf.in_pos == xzio->buf.in_size) + { + readret = grub_file_read (xzio->file, xzio->inbuf, XZBUFSIZ); + if (readret < 0) + return -1; + xzio->buf.in_size = readret; + xzio->buf.in_pos = 0; + } + + xzret = xz_dec_run (xzio->dec, &xzio->buf); + switch (xzret) + { + case XZ_MEMLIMIT_ERROR: + case XZ_FORMAT_ERROR: + case XZ_OPTIONS_ERROR: + case XZ_DATA_ERROR: + case XZ_BUF_ERROR: + grub_error (GRUB_ERR_BAD_COMPRESSED_DATA, + "file corrupted or unsupported block options"); + return -1; + default: + break; + } + + { + grub_off_t new_offset = current_offset + xzio->buf.out_pos; + + if (file->offset <= new_offset) + /* Store first chunk of data in buffer. */ + { + grub_size_t delta = new_offset - (file->offset + ret); + grub_memmove (buf, xzio->buf.out + (xzio->buf.out_pos - delta), + delta); + len -= delta; + buf += delta; + ret += delta; + } + current_offset = new_offset; + } + xzio->buf.out_pos = 0; + + if (xzret == XZ_STREAM_END) /* Stream end, EOF. */ + break; + } + + if (ret >= 0) + xzio->saved_offset = file->offset + ret; + + return ret; +} + +/* Release everything, including the underlying file object. */ +static grub_err_t +grub_xzio_close (grub_file_t file) +{ + grub_xzio_t xzio = file->data; + + xz_dec_end (xzio->dec); + + grub_file_close (xzio->file); + grub_free (xzio); + + /* Device must not be closed twice. */ + file->device = 0; + return grub_errno; +} + +static struct grub_fs grub_xzio_fs = { + .name = "xzio", + .dir = 0, + .open = 0, + .read = grub_xzio_read, + .close = grub_xzio_close, + .label = 0, + .next = 0 +}; + +GRUB_MOD_INIT (xzio) +{ + grub_file_filter_register (GRUB_FILE_FILTER_XZIO, grub_xzio_open); +} + +GRUB_MOD_FINI (xzio) +{ + grub_file_filter_unregister (GRUB_FILE_FILTER_XZIO); +} diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index 09849f174..02d785b9b 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -682,20 +682,3 @@ grub_dl_unload_unneeded (void) p = p->next; } } - -/* Unload all modules. */ -void -grub_dl_unload_all (void) -{ - while (grub_dl_head) - { - grub_dl_t p; - - grub_dl_unload_unneeded (); - - /* Force to decrement the ref count. This will purge pre-loaded - modules and manually inserted modules. */ - for (p = grub_dl_head; p; p = p->next) - p->ref_count--; - } -} diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c index 126e40901..fa1d0c730 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -174,26 +174,6 @@ grub_reboot (void) } #endif -void -grub_halt (void) -{ - grub_efi_fini (); - efi_call_4 (grub_efi_system_table->runtime_services->reset_system, - GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL); - for (;;) ; -} - -int -grub_efi_exit_boot_services (grub_efi_uintn_t map_key) -{ - grub_efi_boot_services_t *b; - grub_efi_status_t status; - - b = grub_efi_system_table->boot_services; - status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle, map_key); - return status == GRUB_EFI_SUCCESS; -} - grub_err_t grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size, grub_efi_uintn_t descriptor_size, @@ -760,26 +740,3 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) dp = (grub_efi_device_path_t *) ((char *) dp + len); } } - -int -grub_efi_finish_boot_services (void) -{ - grub_efi_uintn_t mmap_size = 0; - grub_efi_uintn_t map_key; - grub_efi_uintn_t desc_size; - grub_efi_uint32_t desc_version; - void *mmap_buf = 0; - - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, - &desc_size, &desc_version) < 0) - return 0; - - mmap_buf = grub_malloc (mmap_size); - - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, - &desc_size, &desc_version) <= 0) - return 0; - - return grub_efi_exit_boot_services (map_key); -} - diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index 2abd6325d..c845d7df1 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -49,6 +49,12 @@ static struct allocated_page *allocated_pages = 0; #define MIN_HEAP_SIZE 0x100000 #define MAX_HEAP_SIZE (1600 * 0x100000) +static void *finish_mmap_buf = 0; +static grub_efi_uintn_t finish_mmap_size = 0; +static grub_efi_uintn_t finish_key = 0; +static grub_efi_uintn_t finish_desc_size; +static grub_efi_uint32_t finish_desc_version; +int grub_efi_is_finished = 0; /* Allocate pages. Return the pointer to the first of allocated pages. */ void * @@ -140,6 +146,51 @@ grub_efi_free_pages (grub_efi_physical_address_t address, efi_call_2 (b->free_pages, address, pages); } +grub_err_t +grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *efi_desc_size, + grub_efi_uint32_t *efi_desc_version) +{ + grub_efi_boot_services_t *b; + grub_efi_status_t status; + + if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf, &finish_key, + &finish_desc_size, &finish_desc_version) < 0) + return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map"); + + if (outbuf && *outbuf_size < finish_mmap_size) + return grub_error (GRUB_ERR_IO, "memory map buffer is too small"); + + finish_mmap_buf = grub_malloc (finish_mmap_size); + if (!finish_mmap_buf) + return grub_errno; + + if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf, &finish_key, + &finish_desc_size, &finish_desc_version) <= 0) + return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map"); + + b = grub_efi_system_table->boot_services; + status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle, + finish_key); + if (status != GRUB_EFI_SUCCESS) + return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services"); + + grub_efi_is_finished = 1; + if (outbuf_size) + *outbuf_size = finish_mmap_size; + if (outbuf) + grub_memcpy (outbuf, finish_mmap_buf, finish_mmap_size); + if (map_key) + *map_key = finish_key; + if (efi_desc_size) + *efi_desc_size = finish_desc_size; + if (efi_desc_version) + *efi_desc_version = finish_desc_version; + + return GRUB_ERR_NONE; +} + /* Get the memory map as defined in the EFI spec. Return 1 if successful, return 0 if partial, or return -1 if an error occurs. */ int @@ -154,6 +205,29 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size, grub_efi_uintn_t key; grub_efi_uint32_t version; + if (grub_efi_is_finished) + { + int ret = 1; + if (*memory_map_size < finish_mmap_size) + { + grub_memcpy (memory_map, finish_mmap_buf, *memory_map_size); + ret = 0; + } + else + { + grub_memcpy (memory_map, finish_mmap_buf, finish_mmap_size); + ret = 1; + } + *memory_map_size = finish_mmap_size; + if (map_key) + *map_key = finish_key; + if (descriptor_size) + *descriptor_size = finish_desc_size; + if (descriptor_version) + *descriptor_version = finish_desc_version; + return ret; + } + /* Allow some parameters to be missing. */ if (! map_key) map_key = &key; diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c index d9948a822..4be408c31 100644 --- a/grub-core/kern/elf.c +++ b/grub-core/kern/elf.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -95,7 +94,7 @@ grub_elf_open (const char *name) grub_file_t file; grub_elf_t elf; - file = grub_gzfile_open (name, 1); + file = grub_file_open (name); if (! file) return 0; @@ -140,7 +139,7 @@ grub_elf32_load_phdrs (grub_elf_t elf) return GRUB_ERR_NONE; } -static grub_err_t +grub_err_t grub_elf32_phdr_iterate (grub_elf_t elf, int NESTED_FUNC_ATTR (*hook) (grub_elf_t, Elf32_Phdr *, void *), void *hook_arg) @@ -326,7 +325,7 @@ grub_elf64_load_phdrs (grub_elf_t elf) return GRUB_ERR_NONE; } -static grub_err_t +grub_err_t grub_elf64_phdr_iterate (grub_elf_t elf, int NESTED_FUNC_ATTR (*hook) (grub_elf_t, Elf64_Phdr *, void *), void *hook_arg) diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c index 59f5934e6..9156aa890 100644 --- a/grub-core/kern/emu/main.c +++ b/grub-core/kern/emu/main.c @@ -66,16 +66,6 @@ grub_reboot (void) longjmp (main_env, 1); } -void -grub_halt ( -#ifdef GRUB_MACHINE_PCBIOS - int no_apm __attribute__ ((unused)) -#endif - ) -{ - grub_reboot (); -} - void grub_machine_init (void) { diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c index e17c35f95..c93fbf737 100644 --- a/grub-core/kern/file.c +++ b/grub-core/kern/file.c @@ -24,6 +24,9 @@ #include #include +grub_file_filter_t grub_file_filters_all[GRUB_FILE_FILTER_MAX]; +grub_file_filter_t grub_file_filters_enabled[GRUB_FILE_FILTER_MAX]; + /* Get the device part of the filename NAME. It is enclosed by parentheses. */ char * grub_file_get_device_name (const char *name) @@ -54,14 +57,15 @@ grub_file_get_device_name (const char *name) grub_file_t grub_file_open (const char *name) { - grub_device_t device; - grub_file_t file = 0; + grub_device_t device = 0; + grub_file_t file = 0, last_file = 0; char *device_name; char *file_name; + grub_file_filter_id_t filter; device_name = grub_file_get_device_name (name); if (grub_errno) - return 0; + goto fail; /* Get the file part of NAME. */ file_name = grub_strchr (name, ')'); @@ -94,6 +98,19 @@ grub_file_open (const char *name) if ((file->fs->open) (file, file_name) != GRUB_ERR_NONE) goto fail; + for (filter = 0; file && filter < ARRAY_SIZE (grub_file_filters_enabled); + filter++) + if (grub_file_filters_enabled[filter]) + { + last_file = file; + file = grub_file_filters_enabled[filter] (file); + } + if (!file) + grub_file_close (last_file); + + grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, + sizeof (grub_file_filters_enabled)); + return file; fail: @@ -104,6 +121,9 @@ grub_file_open (const char *name) grub_free (file); + grub_memcpy (grub_file_filters_enabled, grub_file_filters_all, + sizeof (grub_file_filters_enabled)); + return 0; } diff --git a/grub-core/kern/i386/coreboot/init.c b/grub-core/kern/i386/coreboot/init.c index 0afbfd3af..75f385b56 100644 --- a/grub-core/kern/i386/coreboot/init.c +++ b/grub-core/kern/i386/coreboot/init.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -32,33 +31,21 @@ #include #include #include +#include #include #ifdef GRUB_MACHINE_QEMU #include #endif -#define GRUB_FLOPPY_REG_DIGITAL_OUTPUT 0x3f2 - extern char _start[]; extern char _end[]; -grub_addr_t grub_os_area_addr; -grub_size_t grub_os_area_size; - grub_uint32_t grub_get_rtc (void) { grub_fatal ("grub_get_rtc() is not implemented.\n"); } -/* Stop the floppy drive from spinning, so that other software is - jumped to with a known state. */ -void -grub_stop_floppy (void) -{ - grub_outb (0, GRUB_FLOPPY_REG_DIGITAL_OUTPUT); -} - void grub_exit (void) { @@ -103,20 +90,7 @@ grub_machine_init (void) } } - if (addr == GRUB_MEMORY_MACHINE_UPPER_START - || (addr >= GRUB_MEMORY_MACHINE_LOWER_SIZE - && addr <= GRUB_MEMORY_MACHINE_UPPER_START - && (addr + size > GRUB_MEMORY_MACHINE_UPPER_START))) - { - grub_size_t quarter = size >> 2; - - grub_os_area_addr = addr; - grub_os_area_size = size - quarter; - grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size), - quarter); - } - else - grub_mm_init_region ((void *) (grub_addr_t) addr, (grub_size_t) size); + grub_mm_init_region ((void *) (grub_addr_t) addr, (grub_size_t) size); return 0; } diff --git a/grub-core/kern/i386/coreboot/startup.S b/grub-core/kern/i386/coreboot/startup.S index bcc0d14ab..592073776 100644 --- a/grub-core/kern/i386/coreboot/startup.S +++ b/grub-core/kern/i386/coreboot/startup.S @@ -51,7 +51,7 @@ VARIABLE(grub_prefix) * Leave some breathing room for the prefix. */ - . = _start + GRUB_KERNEL_MACHINE_DATA_END + . = _start + GRUB_KERNEL_MACHINE_PREFIX_END /* * Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself). @@ -85,7 +85,3 @@ codestart: */ #include "../realmode.S" -/* - * Routines needed by Linux and Multiboot loaders. - */ -#include "../loader.S" diff --git a/grub-core/kern/i386/ieee1275/startup.S b/grub-core/kern/i386/ieee1275/startup.S index c0a08a954..3ecf09598 100644 --- a/grub-core/kern/i386/ieee1275/startup.S +++ b/grub-core/kern/i386/ieee1275/startup.S @@ -51,7 +51,7 @@ VARIABLE(grub_prefix) * Leave some breathing room for the prefix. */ - . = _start + GRUB_KERNEL_MACHINE_DATA_END + . = _start + GRUB_KERNEL_MACHINE_PREFIX_END codestart: movl %eax, EXT_C(grub_ieee1275_entry_fn) @@ -63,7 +63,3 @@ codestart: */ #include "../realmode.S" -/* - * Routines needed by Linux and Multiboot loaders. - */ -#include "../loader.S" diff --git a/grub-core/kern/i386/loader.S b/grub-core/kern/i386/loader.S deleted file mode 100644 index ed57c43ca..000000000 --- a/grub-core/kern/i386/loader.S +++ /dev/null @@ -1,120 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - - -/* - * Note: These functions defined in this file may be called from C. - * Be careful of that you must not modify some registers. Quote - * from gcc-2.95.2/gcc/config/i386/i386.h: - - 1 for registers not available across function calls. - These must include the FIXED_REGISTERS and also any - registers that can be used without being saved. - The latter must include the registers where values are returned - and the register where structure-value addresses are passed. - Aside from that, you can include as many other registers as you like. - - ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg -{ 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } - */ - -/* - * Note: GRUB is compiled with the options -mrtd and -mregparm=3. - * So the first three arguments are passed in %eax, %edx, and %ecx, - * respectively, and if a function has a fixed number of arguments - * and the number if greater than three, the function must return - * with "ret $N" where N is ((the number of arguments) - 3) * 4. - */ - -/* - * This is the area for all of the special variables. - */ - - .p2align 2 /* force 4-byte alignment */ - -/* - * void grub_linux_boot_zimage (void) - */ -VARIABLE(grub_linux_prot_size) - .long 0 -VARIABLE(grub_linux_tmp_addr) - .long 0 -VARIABLE(grub_linux_real_addr) - .long 0 -VARIABLE(grub_linux_is_bzimage) - .long 0 - -FUNCTION(grub_linux16_real_boot) - /* Must be done before zImage copy. */ - call EXT_C(grub_dl_unload_all) - - movl EXT_C(grub_linux_is_bzimage), %ebx - test %ebx, %ebx - jne bzimage - - /* copy the kernel */ - movl EXT_C(grub_linux_prot_size), %ecx - addl $3, %ecx - shrl $2, %ecx - movl $GRUB_LINUX_BZIMAGE_ADDR, %esi - movl $GRUB_LINUX_ZIMAGE_ADDR, %edi - cld - rep - movsl - -bzimage: - movl EXT_C(grub_linux_real_addr), %ebx - - /* copy the real mode code */ - movl EXT_C(grub_linux_tmp_addr), %esi - movl %ebx, %edi - movl $GRUB_LINUX_SETUP_MOVE_SIZE, %ecx - cld - rep - movsb - - /* change %ebx to the segment address */ - shrl $4, %ebx - movl %ebx, %eax - addl $0x20, %eax - movw %ax, linux_setup_seg - - /* XXX new stack pointer in safe area for calling functions */ - movl $0x4000, %esp - call EXT_C(grub_stop_floppy) - - /* final setup for linux boot */ - call prot_to_real - .code16 - - cli - movw %bx, %ss - movw $GRUB_LINUX_SETUP_STACK, %sp - - movw %bx, %ds - movw %bx, %es - movw %bx, %fs - movw %bx, %gs - - /* ljmp */ - .byte 0xea - .word 0 -linux_setup_seg: - .word 0 - .code32 - diff --git a/grub-core/kern/i386/misc.S b/grub-core/kern/i386/misc.S deleted file mode 100644 index 7d57df9b9..000000000 --- a/grub-core/kern/i386/misc.S +++ /dev/null @@ -1,29 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include - - .text -/* - * This call is special... it never returns... in fact it should simply - * hang at this point! - */ -FUNCTION(grub_stop) - cli -1: hlt - jmp 1b diff --git a/grub-core/kern/i386/multiboot_mmap.c b/grub-core/kern/i386/multiboot_mmap.c index 0f463c23c..73c82049f 100644 --- a/grub-core/kern/i386/multiboot_mmap.c +++ b/grub-core/kern/i386/multiboot_mmap.c @@ -16,7 +16,6 @@ * along with GRUB. If not, see . */ -#include #include #include #include diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c index 8cbc757b2..57e33569e 100644 --- a/grub-core/kern/i386/pc/init.c +++ b/grub-core/kern/i386/pc/init.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -44,9 +45,6 @@ struct mem_region static struct mem_region mem_regions[MAX_REGIONS]; static int num_regions; -grub_addr_t grub_os_area_addr; -grub_size_t grub_os_area_size; - static char * make_install_device (void) { @@ -142,6 +140,22 @@ compact_mem_regions (void) } } +/* + * + * grub_get_conv_memsize(i) : return the conventional memory size in KB. + * BIOS call "INT 12H" to get conventional memory size + * The return value in AX. + */ +static inline grub_uint16_t +grub_get_conv_memsize (void) +{ + struct grub_bios_int_registers regs; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x12, ®s); + return regs.eax & 0xffff; +} + void grub_machine_init (void) { @@ -151,7 +165,7 @@ grub_machine_init (void) /* Initialize the console as early as possible. */ grub_console_init (); - grub_lower_mem = grub_get_memsize (0) << 10; + grub_lower_mem = grub_get_conv_memsize () << 10; /* Sanity check. */ if (grub_lower_mem < GRUB_MEMORY_MACHINE_RESERVED_END) @@ -203,25 +217,9 @@ grub_machine_init (void) compact_mem_regions (); - /* Add the memory regions to free memory, except for the region starting - from 1MB. This region is partially used for loading OS images. - For now, 1/4 of this is added to free memory. */ for (i = 0; i < num_regions; i++) - if (mem_regions[i].addr == 0x100000) - { - grub_size_t quarter = mem_regions[i].size >> 2; - - grub_os_area_addr = mem_regions[i].addr; - grub_os_area_size = mem_regions[i].size - quarter; - grub_mm_init_region ((void *) (grub_os_area_addr + grub_os_area_size), - quarter); - } - else grub_mm_init_region ((void *) mem_regions[i].addr, mem_regions[i].size); - if (! grub_os_area_addr) - grub_fatal ("no upper memory"); - grub_tsc_init (); } diff --git a/grub-core/kern/i386/pc/mmap.c b/grub-core/kern/i386/pc/mmap.c index 72a6b3539..b174bc441 100644 --- a/grub-core/kern/i386/pc/mmap.c +++ b/grub-core/kern/i386/pc/mmap.c @@ -17,11 +17,98 @@ */ #include +#include #include #include #include #include +/* + * grub_get_ext_memsize() : return the extended memory size in KB. + * BIOS call "INT 15H, AH=88H" to get extended memory size + * The return value in AX. + * + */ +static inline grub_uint16_t +grub_get_ext_memsize (void) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x8800; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x15, ®s); + return regs.eax & 0xffff; +} + +/* Get a packed EISA memory map. Lower 16 bits are between 1MB and 16MB + in 1KB parts, and upper 16 bits are above 16MB in 64KB parts. If error, return zero. + BIOS call "INT 15H, AH=E801H" to get EISA memory map, + AX = memory between 1M and 16M in 1K parts. + BX = memory above 16M in 64K parts. +*/ + +static inline grub_uint32_t +grub_get_eisa_mmap (void) +{ + struct grub_bios_int_registers regs; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + regs.eax = 0xe801; + grub_bios_interrupt (0x15, ®s); + + if ((regs.eax & 0xff00) == 0x8600) + return 0; + + return (regs.eax & 0xffff) | (regs.ebx << 16); +} + +/* + * + * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to + * start), for the Query System Address Map BIOS call. + * + * Sets the first 4-byte int value of "addr" to the size returned by + * the call. If the call fails, sets it to zero. + * + * Returns: new (non-zero) continuation value, 0 if done. + */ +/* Get a memory map entry. Return next continuation value. Zero means + the end. */ +static grub_uint32_t +grub_get_mmap_entry (struct grub_machine_mmap_entry *entry, + grub_uint32_t cont) +{ + struct grub_bios_int_registers regs; + + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + + /* place address (+4) in ES:DI */ + regs.es = ((grub_addr_t) &entry->addr) >> 4; + regs.edi = ((grub_addr_t) &entry->addr) & 0xf; + + /* set continuation value */ + regs.ebx = cont; + + /* set default maximum buffer size */ + regs.ecx = sizeof (*entry) - sizeof (entry->size); + + /* set EDX to 'SMAP' */ + regs.edx = 0x534d4150; + + regs.eax = 0xe820; + grub_bios_interrupt (0x15, ®s); + + /* write length of buffer (zero if error) into ADDR */ + if ((regs.flags & GRUB_CPU_INT_FLAGS_CARRY) || regs.eax != 0x534d4150 + || regs.ecx < 0x14 || regs.ecx > 0x400) + entry->size = 0; + else + entry->size = regs.ecx; + + /* return the continuation value */ + return regs.ebx; +} + grub_err_t grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)) { @@ -61,7 +148,7 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin hook (0x1000000, eisa_mmap & ~0xFFFF, GRUB_MACHINE_MEMORY_AVAILABLE); } else - hook (0x100000, grub_get_memsize (1) << 10, GRUB_MACHINE_MEMORY_AVAILABLE); + hook (0x100000, grub_get_ext_memsize () << 10, GRUB_MACHINE_MEMORY_AVAILABLE); } return 0; diff --git a/grub-core/kern/i386/pc/startup.S b/grub-core/kern/i386/pc/startup.S index 761eb53fe..9b53deeb2 100644 --- a/grub-core/kern/i386/pc/startup.S +++ b/grub-core/kern/i386/pc/startup.S @@ -100,14 +100,6 @@ VARIABLE(grub_install_dos_part) .long 0xFFFFFFFF VARIABLE(grub_install_bsd_part) .long 0xFFFFFFFF -VARIABLE(grub_prefix) - /* to be filled by grub-mkimage */ - - /* - * Leave some breathing room for the prefix. - */ - - . = _start + GRUB_KERNEL_MACHINE_DATA_END #ifdef APPLE_CC bss_start: @@ -450,28 +442,16 @@ gate_a20_check_state: */ . = _start + GRUB_KERNEL_MACHINE_RAW_SIZE + . = _start + GRUB_KERNEL_MACHINE_PREFIX +VARIABLE(grub_prefix) + /* to be filled by grub-mkimage */ + /* - * This next part is sort of evil. It takes advantage of the - * byte ordering on the x86 to work in either 16-bit or 32-bit - * mode, so think about it before changing it. + * Leave some breathing room for the prefix. */ - -FUNCTION(grub_hard_stop) - hlt - jmp EXT_C(grub_hard_stop) + . = _start + GRUB_KERNEL_MACHINE_PREFIX_END -/* - * grub_stop_floppy() - * - * Stop the floppy drive from spinning, so that other software is - * jumped to with a known state. - */ -FUNCTION(grub_stop_floppy) - movw $0x3F2, %dx - xorb %al, %al - outb %al, %dx - ret /* * grub_exit() @@ -486,56 +466,6 @@ FUNCTION(grub_exit) jmp cold_reboot .code32 -/* - * grub_halt(int no_apm) - * - * Halt the system, using APM if possible. If NO_APM is true, don't use - * APM even if it is available. - */ -FUNCTION(grub_halt) - /* see if zero */ - testl %eax, %eax - jnz EXT_C(grub_stop) - - call prot_to_real - .code16 - - /* detect APM */ - movw $0x5300, %ax - xorw %bx, %bx - int $0x15 - jc EXT_C(grub_hard_stop) - /* don't check %bx for buggy BIOSes... */ - - /* disconnect APM first */ - movw $0x5304, %ax - xorw %bx, %bx - int $0x15 - - /* connect APM */ - movw $0x5301, %ax - xorw %bx, %bx - int $0x15 - jc EXT_C(grub_hard_stop) - - /* set APM protocol level - 1.1 or bust. (this covers APM 1.2 also) */ - movw $0x530E, %ax - xorw %bx, %bx - movw $0x0101, %cx - int $0x15 - jc EXT_C(grub_hard_stop) - - /* set the power state to off */ - movw $0x5307, %ax - movw $1, %bx - movw $3, %cx - int $0x15 - - /* shouldn't reach here */ - jmp EXT_C(grub_hard_stop) - .code32 - - /* * void grub_chainloader_real_boot (int drive, void *part_addr) * @@ -546,8 +476,6 @@ FUNCTION(grub_chainloader_real_boot) pushl %edx pushl %eax - call EXT_C(grub_dl_unload_all) - /* Turn off Gate A20 */ xorl %eax, %eax call EXT_C(grub_gate_a20) @@ -563,507 +491,8 @@ FUNCTION(grub_chainloader_real_boot) ljmp $0, $GRUB_MEMORY_MACHINE_BOOT_LOADER_ADDR .code32 -#include "../loader.S" - /* - * int grub_biosdisk_rw_int13_extensions (int ah, int drive, void *dap) - * - * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP - * is passed for disk address packet. If an error occurs, return - * non-zero, otherwise zero. - */ - -FUNCTION(grub_biosdisk_rw_int13_extensions) - pushl %ebp - pushl %esi - - /* compute the address of disk_address_packet */ - movw %cx, %si - xorw %cx, %cx - shrl $4, %ecx /* save the segment to cx */ - - /* ah */ - movb %al, %dh - /* enter real mode */ - call prot_to_real - - .code16 - movb %dh, %ah - movw %cx, %ds - int $0x13 /* do the operation */ - movb %ah, %dl /* save return value */ - /* back to protected mode */ - DATA32 call real_to_prot - .code32 - - movb %dl, %al /* return value in %eax */ - - popl %esi - popl %ebp - - ret - -/* - * int grub_biosdisk_rw_standard (int ah, int drive, int coff, int hoff, - * int soff, int nsec, int segment) - * - * Call standard and old INT13 (int 13 %ah=AH) for DRIVE. Read/write - * NSEC sectors from COFF/HOFF/SOFF into SEGMENT. If an error occurs, - * return non-zero, otherwise zero. - */ - -FUNCTION(grub_biosdisk_rw_standard) - pushl %ebp - movl %esp, %ebp - - pushl %ebx - pushl %edi - pushl %esi - - /* set up CHS information */ - - /* set %ch to low eight bits of cylinder */ - xchgb %cl, %ch - /* set bits 6-7 of %cl to high two bits of cylinder */ - shlb $6, %cl - /* set bits 0-5 of %cl to sector */ - addb 0xc(%ebp), %cl - /* set %dh to head */ - movb 0x8(%ebp), %dh - /* set %ah to AH */ - movb %al, %ah - /* set %al to NSEC */ - movb 0x10(%ebp), %al - /* save %ax in %di */ - movw %ax, %di - /* save SEGMENT in %bx */ - movw 0x14(%ebp), %bx - - /* enter real mode */ - call prot_to_real - - .code16 - movw %bx, %es - xorw %bx, %bx - movw $3, %si /* attempt at least three times */ - -1: - movw %di, %ax - int $0x13 /* do the operation */ - jnc 2f /* check if successful */ - - movb %ah, %bl /* save return value */ - /* if fail, reset the disk system */ - xorw %ax, %ax - int $0x13 - - decw %si - cmpw $0, %si - je 2f - xorb %bl, %bl - jmp 1b /* retry */ -2: - /* back to protected mode */ - DATA32 call real_to_prot - .code32 - - movb %bl, %al /* return value in %eax */ - - popl %esi - popl %edi - popl %ebx - popl %ebp - - ret $(4 * 4) - - -/* - * int grub_biosdisk_check_int13_extensions (int drive) - * - * Check if LBA is supported for DRIVE. If it is supported, then return - * the major version of extensions, otherwise zero. - */ - -FUNCTION(grub_biosdisk_check_int13_extensions) - pushl %ebp - pushl %ebx - - /* drive */ - movb %al, %dl - /* enter real mode */ - call prot_to_real - - .code16 - movb $0x41, %ah - movw $0x55aa, %bx - int $0x13 /* do the operation */ - - /* check the result */ - jc 1f - cmpw $0xaa55, %bx - jne 1f - - movb %ah, %bl /* save the major version into %bl */ - - /* check if AH=0x42 is supported */ - andw $1, %cx - jnz 2f - -1: - xorb %bl, %bl -2: - /* back to protected mode */ - DATA32 call real_to_prot - .code32 - - movb %bl, %al /* return value in %eax */ - - popl %ebx - popl %ebp - - ret - - -/* - * int grub_biosdisk_get_cdinfo_int13_extensions (int drive, void *cdrp) - * - * Return the cdrom information of DRIVE in CDRP. If an error occurs, - * then return non-zero, otherwise zero. - */ - -FUNCTION(grub_biosdisk_get_cdinfo_int13_extensions) - movw $0x4B01, %cx - jmp 1f - -/* - * int grub_biosdisk_get_diskinfo_int13_extensions (int drive, void *drp) - * - * Return the geometry of DRIVE in a drive parameters, DRP. If an error - * occurs, then return non-zero, otherwise zero. - */ - -FUNCTION(grub_biosdisk_get_diskinfo_int13_extensions) - movb $0x48, %ch -1: - pushl %ebp - pushl %ebx - pushl %esi - - /* compute the address of drive parameters */ - movw %dx, %si - andl $0xf, %esi - shrl $4, %edx - movw %dx, %bx /* save the segment into %bx */ - /* drive */ - movb %al, %dl - /* enter real mode */ - call prot_to_real - - .code16 - movw %cx, %ax - movw %bx, %ds - int $0x13 /* do the operation */ - jc noclean - /* Clean return value if carry isn't set to workaround - some buggy BIOSes. */ - xor %ax, %ax -noclean: - movb %ah, %bl /* save return value in %bl */ - /* back to protected mode */ - DATA32 call real_to_prot - .code32 - - movb %bl, %al /* return value in %eax */ - - popl %esi - popl %ebx - popl %ebp - - ret - - -/* - * int grub_biosdisk_get_diskinfo_standard (int drive, - * unsigned long *cylinders, - * unsigned long *heads, - * unsigned long *sectors) - * - * Return the geometry of DRIVE in CYLINDERS, HEADS and SECTORS. If an - * error occurs, then return non-zero, otherwise zero. - */ - -FUNCTION(grub_biosdisk_get_diskinfo_standard) - pushl %ebp - pushl %ebx - pushl %edi - - /* push CYLINDERS */ - pushl %edx - /* push HEADS */ - pushl %ecx - /* SECTORS is on the stack */ - - /* drive */ - movb %al, %dl - /* enter real mode */ - call prot_to_real - - .code16 - movb $0x8, %ah - int $0x13 /* do the operation */ - jc noclean2 - /* Clean return value if carry isn't set to workaround - some buggy BIOSes. */ - xor %ax, %ax -noclean2: - /* check if successful */ - testb %ah, %ah - jnz 1f - /* bogus BIOSes may not return an error number */ - testb $0x3f, %cl /* 0 sectors means no disk */ - jnz 1f /* if non-zero, then succeed */ - /* XXX 0x60 is one of the unused error numbers */ - movb $0x60, %ah -1: - movb %ah, %bl /* save return value in %bl */ - /* back to protected mode */ - DATA32 call real_to_prot - .code32 - - /* pop HEADS */ - popl %edi - movb %dh, %al - incl %eax /* the number of heads is counted from zero */ - movl %eax, (%edi) - - /* pop CYLINDERS */ - popl %edi - movb %ch, %al - movb %cl, %ah - shrb $6, %ah /* the number of cylinders is counted from zero */ - incl %eax - movl %eax, (%edi) - - /* SECTORS */ - movl 0x10(%esp), %edi - andb $0x3f, %cl - movzbl %cl, %eax - movl %eax, (%edi) - - xorl %eax, %eax - movb %bl, %al /* return value in %eax */ - - popl %edi - popl %ebx - popl %ebp - - ret $4 - - -/* - * int grub_biosdisk_get_num_floppies (void) - */ -FUNCTION(grub_biosdisk_get_num_floppies) - pushl %ebp - - xorl %edx, %edx - call prot_to_real - - .code16 - /* reset the disk system first */ - int $0x13 -1: - stc - - /* call GET DISK TYPE */ - movb $0x15, %ah - int $0x13 - - jc 2f - - /* check if this drive exists */ - testb $0x3, %ah - jz 2f - - incb %dl - cmpb $2, %dl - jne 1b -2: - DATA32 call real_to_prot - .code32 - - movl %edx, %eax - popl %ebp - ret - - -/* - * - * grub_get_memsize(i) : return the memory size in KB. i == 0 for conventional - * memory, i == 1 for extended memory - * BIOS call "INT 12H" to get conventional memory size - * BIOS call "INT 15H, AH=88H" to get extended memory size - * Both have the return value in AX. - * - */ - -FUNCTION(grub_get_memsize) - pushl %ebp - - movl %eax, %edx - - call prot_to_real /* enter real mode */ - .code16 - - testl %edx, %edx - jnz xext - - int $0x12 - jmp xdone - -xext: - movb $0x88, %ah - int $0x15 - -xdone: - movw %ax, %dx - - DATA32 call real_to_prot - .code32 - - movw %dx, %ax - - popl %ebp - ret - - -/* - * - * grub_get_eisa_mmap() : return packed EISA memory map, lower 16 bits is - * memory between 1M and 16M in 1K parts, upper 16 bits is - * memory above 16M in 64K parts. If error, return zero. - * BIOS call "INT 15H, AH=E801H" to get EISA memory map, - * AX = memory between 1M and 16M in 1K parts. - * BX = memory above 16M in 64K parts. - * - */ - -FUNCTION(grub_get_eisa_mmap) - pushl %ebp - pushl %ebx - - call prot_to_real /* enter real mode */ - .code16 - - movw $0xe801, %ax - int $0x15 - - shll $16, %ebx - movw %ax, %bx - - DATA32 call real_to_prot - .code32 - - cmpb $0x86, %bh - je xnoteisa - - movl %ebx, %eax - -xnoteisa: - popl %ebx - popl %ebp - ret - -/* - * - * grub_get_mmap_entry(addr, cont) : address and old continuation value (zero to - * start), for the Query System Address Map BIOS call. - * - * Sets the first 4-byte int value of "addr" to the size returned by - * the call. If the call fails, sets it to zero. - * - * Returns: new (non-zero) continuation value, 0 if done. - */ - -FUNCTION(grub_get_mmap_entry) - pushl %ebp - pushl %ebx - pushl %edi - pushl %esi - - /* push ADDR */ - pushl %eax - - /* place address (+4) in ES:DI */ - addl $4, %eax - movl %eax, %edi - andl $0xf, %edi - shrl $4, %eax - movl %eax, %esi - - /* set continuation value */ - movl %edx, %ebx - - /* set default maximum buffer size */ - movl $0x14, %ecx - - /* set EDX to 'SMAP' */ - movl $0x534d4150, %edx - - call prot_to_real /* enter real mode */ - .code16 - - movw %si, %es - movl $0xe820, %eax - int $0x15 - - DATA32 jc xnosmap - - cmpl $0x534d4150, %eax - jne xnosmap - - cmpl $0x14, %ecx - jl xnosmap - - cmpl $0x400, %ecx - jg xnosmap - - jmp xsmap - -xnosmap: - xorl %ecx, %ecx - -/* Apple's cc jumps few bytes before the correct - label in this context. Hence nops. */ -#ifdef APPLE_CC - nop - nop - nop - nop - nop - nop -#endif - -xsmap: - DATA32 call real_to_prot - .code32 - - /* write length of buffer (zero if error) into ADDR */ - popl %eax - movl %ecx, (%eax) - - /* set return value to continuation */ - movl %ebx, %eax - - popl %esi - popl %edi - popl %ebx - popl %ebp - ret - - -/* - * void grub_console_putchar (const struct grub_unicode_glyph *c) + * void grub_console_putchar (int c) * * Put the character C on the console. Because GRUB wants to write a * character with an attribute, this implementation is a bit tricky. @@ -1469,572 +898,8 @@ FUNCTION(grub_get_rtc) popl %ebp ret - /* - * unsigned char grub_vga_set_mode (unsigned char mode) - */ -FUNCTION(grub_vga_set_mode) - pushl %ebp - pushl %ebx - movl %eax, %ecx - - call prot_to_real - .code16 - /* get current mode */ - xorw %bx, %bx - movb $0x0f, %ah - int $0x10 - movb %al, %dl - - /* set the new mode */ - movb %cl, %al - xorb %ah, %ah - int $0x10 - - DATA32 call real_to_prot - .code32 - - movb %dl, %al - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_bios_status_t grub_vbe_get_controller_info (struct grub_vbe_info_block *controller_info) - * - * Register allocations for parameters: - * %eax *controller_info - */ -FUNCTION(grub_vbe_bios_get_controller_info) - pushl %ebp - pushl %edi - pushl %edx - - movw %ax, %di /* Store *controller_info to %edx:%di. */ - xorw %ax, %ax - shrl $4, %eax - mov %eax, %edx /* prot_to_real destroys %eax. */ - - call prot_to_real - .code16 - - pushw %es - - movw %dx, %es /* *controller_info is now on %es:%di. */ - movw $0x4f00, %ax - int $0x10 - - movw %ax, %dx /* real_to_prot destroys %eax. */ - - popw %es - - DATA32 call real_to_prot - .code32 - - movl %edx, %eax - andl $0x0FFFF, %eax /* Return value in %eax. */ - - pop %edx - popl %edi - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_get_mode_info (grub_uint32_t mode, - * struct grub_vbe_mode_info_block *mode_info) - * - * Register allocations for parameters: - * %eax mode - * %edx *mode_info - */ -FUNCTION(grub_vbe_bios_get_mode_info) - pushl %ebp - pushl %edi - - movl %eax, %ecx /* Store mode number to %ecx. */ - - movw %dx, %di /* Store *mode_info to %edx:%di. */ - xorw %dx, %dx - shrl $4, %edx - - call prot_to_real - .code16 - - pushw %es - - movw %dx, %es /* *mode_info is now on %es:%di. */ - movw $0x4f01, %ax - int $0x10 - - movw %ax, %dx /* real_to_prot destroys %eax. */ - - popw %es - - DATA32 call real_to_prot - .code32 - - movl %edx, %eax - andl $0x0FFFF, %eax /* Return value in %eax. */ - - popl %edi - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_set_mode (grub_uint32_t mode, - * struct grub_vbe_crtc_info_block *crtc_info) - * - * Register allocations for parameters: - * %eax mode - * %edx *crtc_info - */ -FUNCTION(grub_vbe_bios_set_mode) - pushl %ebp - pushl %ebx - pushl %edi - - movl %eax, %ebx /* Store mode in %ebx. */ - - movw %dx, %di /* Store *crtc_info to %edx:%di. */ - xorw %dx, %dx - shrl $4, %edx - - call prot_to_real - .code16 - - pushw %es - - movw %dx, %es /* *crtc_info is now on %es:%di. */ - - movw $0x4f02, %ax - int $0x10 - - movw %ax, %dx /* real_to_prot destroys %eax. */ - - popw %es - - DATA32 call real_to_prot - .code32 - - movw %dx, %ax - andl $0xFFFF, %eax /* Return value in %eax. */ - - popl %edi - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_get_mode (grub_uint32_t *mode) - * - * Register allocations for parameters: - * %eax *mode - */ -FUNCTION(grub_vbe_bios_get_mode) - pushl %ebp - pushl %ebx - pushl %edi - pushl %edx - pushl %eax /* Push *mode to stack. */ - - call prot_to_real - .code16 - - movw $0x4f03, %ax - int $0x10 - - movw %ax, %dx /* real_to_prot destroys %eax. */ - - DATA32 call real_to_prot - .code32 - - popl %edi /* Pops *mode from stack to %edi. */ - andl $0xFFFF, %ebx - movl %ebx, (%edi) - - movw %dx, %ax - andl $0xFFFF, %eax /* Return value in %eax. */ - - popl %edx - popl %edi - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_getset_dac_palette_width (int set, int *dac_mask_size) - * - * Register allocations for parameters: - * %eax set - * %edx *dac_mask_size - */ -FUNCTION(grub_vbe_bios_getset_dac_palette_width) - pushl %ebp - pushl %ebx - - xorl %ebx, %ebx - - /* If we only want to fetch the value, set %bl to 1. */ - testl %eax, %eax - jne 1f - incb %bl -1: - - /* Put desired width in %bh. */ - movl (%edx), %eax - movb %al, %bh - - call prot_to_real - .code16 - - movw $0x4f08, %ax - int $0x10 - - movw %ax, %cx /* real_to_prot destroys %eax. */ - - DATA32 call real_to_prot - .code32 - - /* Move result back to *dac_mask_size. */ - xorl %eax, %eax - movb %bh, %al - movl %eax, (%edx) - - /* Return value in %eax. */ - movw %cx, %ax - - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window, - * grub_uint32_t position); - * - * Register allocations for parameters: - * %eax window - * %edx position - */ -FUNCTION(grub_vbe_bios_set_memory_window) - pushl %ebp - pushl %ebx - - movl %eax, %ebx - - call prot_to_real - .code16 - - movw $0x4f05, %ax - andw $0x00ff, %bx /* BL = window, BH = 0, Set memory window. */ - int $0x10 - - movw %ax, %dx /* real_to_prot destroys %eax. */ - - DATA32 call real_to_prot - .code32 - - movw %dx, %ax - andl $0xFFFF, %eax /* Return value in %eax. */ - - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_get_memory_window (grub_uint32_t window, - * grub_uint32_t *position); - * - * Register allocations for parameters: - * %eax window - * %edx *position - */ -FUNCTION(grub_vbe_bios_get_memory_window) - pushl %ebp - pushl %ebx - pushl %edi - pushl %edx /* Push *position to stack. */ - - movl %eax, %ebx /* Store window in %ebx. */ - - call prot_to_real - .code16 - - movw $0x4f05, %ax - andw $0x00ff, %bx /* BL = window. */ - orw $0x0100, %bx /* BH = 1, Get memory window. */ - int $0x10 - - movw %ax, %bx /* real_to_prot destroys %eax. */ - - DATA32 call real_to_prot - .code32 - - popl %edi /* pops *position from stack to %edi. */ - andl $0xFFFF, %edx - movl %edx, (%edi) /* Return position to caller. */ - - movw %bx, %ax - andl $0xFFFF, %eax /* Return value in %eax. */ - - popl %edi - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_set_scanline_length (grub_uint32_t length) - * - * Register allocations for parameters: - * %eax length - */ -FUNCTION(grub_vbe_bios_set_scanline_length) - pushl %ebp - pushl %ebx - pushl %edx - - movl %eax, %ecx /* Store length in %ecx. */ - - call prot_to_real - .code16 - - movw $0x4f06, %ax - movw $0x0002, %bx /* BL = 2, Set Scan Line in Bytes. */ - int $0x10 - - movw %ax, %dx /* real_to_prot destroys %eax. */ - - DATA32 call real_to_prot - .code32 - - movw %dx, %ax - andl $0xFFFF, %eax /* Return value in %eax. */ - - popl %edx - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_get_scanline_length (grub_uint32_t *length) - * - * Register allocations for parameters: - * %eax *length - */ -FUNCTION(grub_vbe_bios_get_scanline_length) - pushl %ebp - pushl %ebx - pushl %edi - pushl %edx /* Push *length to stack. */ - - call prot_to_real - .code16 - - movw $0x4f06, %ax - movw $0x0001, %bx /* BL = 1, Get Scan Line Length (in bytes). */ - int $0x10 - - movw %ax, %dx /* real_to_prot destroys %eax. */ - - DATA32 call real_to_prot - .code32 - - popl %edi /* Pops *length from stack to %edi. */ - andl $0xFFFF, %ebx - movl %ebx, (%edi) /* Return length to caller. */ - - movw %dx, %ax - andl $0xFFFF, %eax /* Return value in %eax. */ - - popl %edi - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_set_display_start (grub_uint32_t x, - * grub_uint32_t y) - * - * Register allocations for parameters: - * %eax x - * %edx y - */ -FUNCTION(grub_vbe_bios_set_display_start) - pushl %ebp - pushl %ebx - - movl %eax, %ecx /* Store x in %ecx. */ - - call prot_to_real - .code16 - - movw $0x4f07, %ax - movw $0x0080, %bx /* BL = 80h, Set Display Start - during Vertical Retrace. */ - int $0x10 - - movw %ax, %dx /* real_to_prot destroys %eax. */ - - DATA32 call real_to_prot - .code32 - - movw %dx, %ax - andl $0xFFFF, %eax /* Return value in %eax. */ - - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_get_display_start (grub_uint32_t *x, - * grub_uint32_t *y) - * - * Register allocations for parameters: - * %eax *x - * %edx *y - */ -FUNCTION(grub_vbe_bios_get_display_start) - pushl %ebp - pushl %ebx - pushl %edi - pushl %eax /* Push *x to stack. */ - pushl %edx /* Push *y to stack. */ - - call prot_to_real - .code16 - - movw $0x4f07, %ax - movw $0x0001, %bx /* BL = 1, Get Display Start. */ - int $0x10 - - movw %ax, %bx /* real_to_prot destroys %eax. */ - - DATA32 call real_to_prot - .code32 - - popl %edi /* Pops *y from stack to %edi. */ - andl $0xFFFF, %edx - movl %edx, (%edi) /* Return y-position to caller. */ - - popl %edi /* Pops *x from stack to %edi. */ - andl $0xFFFF, %ecx - movl %ecx, (%edi) /* Return x-position to caller. */ - - movw %bx, %ax - andl $0xFFFF, %eax /* Return value in %eax. */ - - popl %edi - popl %ebx - popl %ebp - ret - -/* - * grub_vbe_status_t grub_vbe_bios_set_palette_data (grub_uint32_t color_count, - * grub_uint32_t start_index, - * struct grub_vbe_palette_data *palette_data) - * - * Register allocations for parameters: - * %eax color_count - * %edx start_index - * %ecx *palette_data - */ -FUNCTION(grub_vbe_bios_set_palette_data) - pushl %ebp - pushl %ebx - pushl %edi - - movl %eax, %ebx /* Store color_count in %ebx. */ - - movw %cx, %di /* Store *palette_data to %ecx:%di. */ - xorw %cx, %cx - shrl $4, %ecx - - call prot_to_real - .code16 - - pushw %es - - movw %cx, %es /* *palette_data is now on %es:%di. */ - movw %bx, %cx /* color_count is now on %cx. */ - - movw $0x4f09, %ax - xorw %bx, %bx /* BL = 0, Set Palette Data. */ - int $0x10 - - movw %ax, %dx /* real_to_prot destroys %eax. */ - - popw %es - - DATA32 call real_to_prot - .code32 - - movw %dx, %ax - andl $0xFFFF, %eax /* Return value in %eax. */ - - popl %edi - popl %ebx - popl %ebp - ret - - -pxe_rm_entry: - .long 0 - -/* - * struct grub_pxenv *grub_pxe_scan (void); - */ -FUNCTION(grub_pxe_scan) - pushl %ebp - pushl %ebx - - xorl %ebx, %ebx - xorl %ecx, %ecx - - call prot_to_real - .code16 - - pushw %es - - movw $0x5650, %ax - int $0x1A - cmpw $0x564E, %ax - jnz 1f - cmpl $0x4E455850, %es:(%bx) /* PXEN(V+) */ - jnz 1f - cmpw $0x201, %es:6(%bx) /* API version */ - jb 1f - lesw %es:0x28(%bx), %bx /* !PXE structure */ - cmpl $0x45585021, %es:(%bx) /* !PXE */ - jnz 1f - movw %es, %cx - jmp 2f -1: - xorw %bx, %bx - xorw %cx, %cx -2: - - popw %es - - DATA32 call real_to_prot - .code32 - - xorl %eax, %eax - leal (%eax, %ecx, 4), %ecx - leal (%ebx, %ecx, 4), %eax /* eax = ecx * 16 + ebx */ - - orl %eax, %eax - jz 1f - - movl 0x10(%eax), %ecx - movl %ecx, pxe_rm_entry - -1: - - popl %ebx - popl %ebp - ret - -/* - * int grub_pxe_call (int func, void* data); + * int grub_pxe_call (int func, void* data, grub_uint32_t pxe_rm_entry); */ FUNCTION(grub_pxe_call) pushl %ebp @@ -2043,13 +908,13 @@ FUNCTION(grub_pxe_call) pushl %edi pushl %ebx + movl %ecx, %ebx movl %eax, %ecx movl %edx, %eax andl $0xF, %eax shrl $4, %edx shll $16, %edx addl %eax, %edx - movl pxe_rm_entry, %ebx call prot_to_real .code16 @@ -2073,3 +938,103 @@ FUNCTION(grub_pxe_call) popl %esi popl %ebp ret + +FUNCTION(grub_bios_interrupt) + pushl %ebp + pushl %ecx + pushl %eax + pushl %ebx + pushl %esi + pushl %edi + pushl %edx + + movb %al, intno + movl (%edx), %eax + movl %eax, LOCAL(bios_register_eax) + movw 4(%edx), %ax + movw %ax, LOCAL(bios_register_es) + movw 6(%edx), %ax + movw %ax, LOCAL(bios_register_ds) + movw 8(%edx), %ax + movw %ax, LOCAL(bios_register_flags) + + movl 12(%edx), %ebx + movl 16(%edx), %ecx + movl 20(%edx), %edi + movl 24(%edx), %esi + movl 28(%edx), %edx + + call prot_to_real + .code16 + + mov %ds, %ax + push %ax + + /* movw imm16, %ax*/ + .byte 0xb8 +LOCAL(bios_register_es): + .short 0 + movw %ax, %es + /* movw imm16, %ax*/ + .byte 0xb8 +LOCAL(bios_register_ds): + .short 0 + movw %ax, %ds + + /* movw imm16, %ax*/ + .byte 0xb8 +LOCAL(bios_register_flags): + .short 0 + push %ax + popf + + /* movl imm32, %eax*/ + .byte 0x66, 0xb8 +LOCAL(bios_register_eax): + .long 0 + + /* int imm8. */ + .byte 0xcd +intno: + .byte 0 + + movl %eax, %cs:LOCAL(bios_register_eax) + movw %ds, %ax + movw %ax, %cs:LOCAL(bios_register_ds) + pop %ax + mov %ax, %ds + pushf + pop %ax + movw %ax, LOCAL(bios_register_flags) + mov %es, %ax + movw %ax, LOCAL(bios_register_es) + + DATA32 call real_to_prot + .code32 + + popl %eax + + movl %ebx, 12(%eax) + movl %ecx, 16(%eax) + movl %edi, 20(%eax) + movl %esi, 24(%eax) + movl %edx, 28(%eax) + + movl %eax, %edx + + movl LOCAL(bios_register_eax), %eax + movl %eax, (%edx) + movw LOCAL(bios_register_es), %ax + movw %ax, 4(%edx) + movw LOCAL(bios_register_ds), %ax + movw %ax, 6(%edx) + movw LOCAL(bios_register_flags), %ax + movw %ax, 8(%edx) + + popl %edi + popl %esi + popl %ebx + popl %eax + popl %ecx + popl %ebp + ret diff --git a/grub-core/kern/i386/qemu/mmap.c b/grub-core/kern/i386/qemu/mmap.c index f2a998e78..f8b4b9b4f 100644 --- a/grub-core/kern/i386/qemu/mmap.c +++ b/grub-core/kern/i386/qemu/mmap.c @@ -16,7 +16,6 @@ * along with GRUB. If not, see . */ -#include #include #include #include @@ -68,6 +67,11 @@ grub_machine_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uin GRUB_MACHINE_MEMORY_AVAILABLE)) return 1; + if (hook ((grub_addr_t) _end, + 0xa0000 - (grub_addr_t) _end, + GRUB_MACHINE_MEMORY_AVAILABLE)) + return 1; + if (hook (GRUB_MEMORY_MACHINE_UPPER, 0x100000 - GRUB_MEMORY_MACHINE_UPPER, GRUB_MACHINE_MEMORY_RESERVED)) diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S index dc40cc4a2..680de9dc4 100644 --- a/grub-core/kern/i386/qemu/startup.S +++ b/grub-core/kern/i386/qemu/startup.S @@ -39,7 +39,7 @@ VARIABLE(grub_prefix) * Leave some breathing room for the prefix. */ - . = _start + GRUB_KERNEL_MACHINE_DATA_END + . = _start + GRUB_KERNEL_MACHINE_PREFIX_END codestart: /* Relocate to low memory. First we figure out our location. @@ -94,6 +94,9 @@ codestart: call EXT_C(grub_main) /* This should never happen. */ - jmp EXT_C(grub_stop) + cli +1: + hlt + jmp 1b #include "../realmode.S" diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c index 75767d13c..fcd43f617 100644 --- a/grub-core/kern/ieee1275/openfw.c +++ b/grub-core/kern/ieee1275/openfw.c @@ -423,14 +423,3 @@ grub_reboot (void) for (;;) ; } #endif - -void -grub_halt (void) -{ - /* Not standardized. We try three known commands. */ - - grub_ieee1275_interpret ("shut-down", 0); - grub_ieee1275_interpret ("power-off", 0); - grub_ieee1275_interpret ("poweroff", 0); - for (;;) ; -} diff --git a/grub-core/kern/mips/startup.S b/grub-core/kern/mips/startup.S index 134853a9d..6811353ea 100644 --- a/grub-core/kern/mips/startup.S +++ b/grub-core/kern/mips/startup.S @@ -154,7 +154,7 @@ VARIABLE(grub_prefix) * Leave some breathing room for the prefix. */ - . = _start + GRUB_KERNEL_MACHINE_DATA_END + . = _start + GRUB_KERNEL_MACHINE_PREFIX_END #ifdef GRUB_MACHINE_MIPS_YEELOONG VARIABLE (grub_arch_busclock) .long 0 diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c index b37ef230c..0bfa08992 100644 --- a/grub-core/kern/misc.c +++ b/grub-core/kern/misc.c @@ -184,6 +184,7 @@ grub_real_dprintf (const char *file, const int line, const char *condition, va_start (args, fmt); grub_vprintf (fmt, args); va_end (args); + grub_refresh (); } } @@ -989,7 +990,7 @@ grub_abort (void) grub_exit (); } -#ifndef APPLE_CC +#if ! defined (APPLE_CC) && !defined (GRUB_UTIL) /* GCC emits references to abort(). */ void abort (void) __attribute__ ((alias ("grub_abort"))); #endif diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 47324a662..8d9b5db78 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -65,6 +65,7 @@ #include #include #include +#include #ifdef MM_DEBUG # undef grub_malloc @@ -74,45 +75,9 @@ # undef grub_memalign #endif -/* Magic words. */ -#define GRUB_MM_FREE_MAGIC 0x2d3c2808 -#define GRUB_MM_ALLOC_MAGIC 0x6db08fa4 - -typedef struct grub_mm_header -{ - struct grub_mm_header *next; - grub_size_t size; - grub_size_t magic; -#if GRUB_CPU_SIZEOF_VOID_P == 4 - char padding[4]; -#elif GRUB_CPU_SIZEOF_VOID_P == 8 - char padding[8]; -#else -# error "unknown word size" -#endif -} -*grub_mm_header_t; - -#if GRUB_CPU_SIZEOF_VOID_P == 4 -# define GRUB_MM_ALIGN_LOG2 4 -#elif GRUB_CPU_SIZEOF_VOID_P == 8 -# define GRUB_MM_ALIGN_LOG2 5 -#endif - -#define GRUB_MM_ALIGN (1 << GRUB_MM_ALIGN_LOG2) - -typedef struct grub_mm_region -{ - struct grub_mm_header *first; - struct grub_mm_region *next; - grub_addr_t addr; - grub_size_t size; -} -*grub_mm_region_t; - -static grub_mm_region_t base; +grub_mm_region_t grub_mm_base; /* Get a header from the pointer PTR, and set *P and *R to a pointer to the header and a pointer to its region, respectively. PTR must @@ -123,9 +88,9 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r) if ((grub_addr_t) ptr & (GRUB_MM_ALIGN - 1)) grub_fatal ("unaligned pointer %p", ptr); - for (*r = base; *r; *r = (*r)->next) - if ((grub_addr_t) ptr > (*r)->addr - && (grub_addr_t) ptr <= (*r)->addr + (*r)->size) + for (*r = grub_mm_base; *r; *r = (*r)->next) + if ((grub_addr_t) ptr > (grub_addr_t) ((*r) + 1) + && (grub_addr_t) ptr <= (grub_addr_t) ((*r) + 1) + (*r)->size) break; if (! *r) @@ -156,18 +121,18 @@ grub_mm_init_region (void *addr, grub_size_t size) if (size < GRUB_MM_ALIGN) return; - h = (grub_mm_header_t) ((char *) r + GRUB_MM_ALIGN); + h = (grub_mm_header_t) (r + 1); h->next = h; h->magic = GRUB_MM_FREE_MAGIC; h->size = (size >> GRUB_MM_ALIGN_LOG2); r->first = h; - r->addr = (grub_addr_t) h; + r->pre_size = (grub_addr_t) r - (grub_addr_t) addr; r->size = (h->size << GRUB_MM_ALIGN_LOG2); /* Find where to insert this region. Put a smaller one before bigger ones, to prevent fragmentation. */ - for (p = &base, q = *p; q; p = &(q->next), q = *p) + for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p) if (q->size > r->size) break; @@ -206,6 +171,7 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) if (p->size >= n + extra) { + extra += (p->size - extra - n) & (~(align - 1)); if (extra == 0 && p->size == n) { /* There is no special alignment requirement and memory block @@ -284,10 +250,10 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) r = p + extra + n; r->magic = GRUB_MM_FREE_MAGIC; r->size = p->size - extra - n; - r->next = p->next; + r->next = p; p->size = extra; - p->next = r; + q->next = r; p += extra; } @@ -318,13 +284,16 @@ grub_memalign (grub_size_t align, grub_size_t size) grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1; int count = 0; + if (!grub_mm_base) + goto fail; + align = (align >> GRUB_MM_ALIGN_LOG2); if (align == 0) align = 1; again: - for (r = base; r; r = r->next) + for (r = grub_mm_base; r; r = r->next) { void *p; @@ -352,6 +321,7 @@ grub_memalign (grub_size_t align, grub_size_t size) break; } + fail: grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); return 0; } @@ -485,7 +455,7 @@ grub_mm_dump_free (void) { grub_mm_region_t r; - for (r = base; r; r = r->next) + for (r = grub_mm_base; r; r = r->next) { grub_mm_header_t p; @@ -512,13 +482,13 @@ grub_mm_dump (unsigned lineno) grub_mm_region_t r; grub_printf ("called at line %u\n", lineno); - for (r = base; r; r = r->next) + for (r = grub_mm_base; r; r = r->next) { grub_mm_header_t p; - for (p = (grub_mm_header_t) ((r->addr + GRUB_MM_ALIGN - 1) - & (~(GRUB_MM_ALIGN - 1))); - (grub_addr_t) p < r->addr + r->size; + for (p = (grub_mm_header_t) ALIGN_UP ((grub_addr_t) (r + 1), + GRUB_MM_ALIGN); + (grub_addr_t) p < (grub_addr_t) (r+1) + r->size; p++) { switch (p->magic) diff --git a/grub-core/kern/powerpc/cache.S b/grub-core/kern/powerpc/cache.S index da982afa0..d85e68d42 100644 --- a/grub-core/kern/powerpc/cache.S +++ b/grub-core/kern/powerpc/cache.S @@ -1,7 +1,7 @@ /* cache.S - Flush the processor cache for a specific region. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2007 Free Software Foundation, Inc. + * Copyright (C) 2004,2007,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,32 +17,10 @@ * along with GRUB. If not, see . */ -#define CACHE_LINE_BYTES 32 - .text .align 2 .globl grub_arch_sync_caches grub_arch_sync_caches: - /* `address' may not be CACHE_LINE_BYTES-aligned. */ - andi. 6, 3, CACHE_LINE_BYTES - 1 /* Find the misalignment. */ - add 4, 4, 6 /* Adjust `size' to compensate. */ - - /* Force the dcache lines to memory. */ - li 5, 0 -1: dcbst 5, 3 - addi 5, 5, CACHE_LINE_BYTES - cmpw 5, 4 - blt 1b - sync /* Force all dcbsts to complete. */ - - /* Invalidate the icache lines. */ - li 5, 0 -1: icbi 5, 3 - addi 5, 5, CACHE_LINE_BYTES - cmpw 5, 4 - blt 1b - sync /* Force all icbis to complete. */ - isync /* Discard partially executed instructions that were - loaded from the invalid icache. */ +#include "cache_flush.S" blr diff --git a/grub-core/kern/powerpc/cache_flush.S b/grub-core/kern/powerpc/cache_flush.S new file mode 100644 index 000000000..1410f78b1 --- /dev/null +++ b/grub-core/kern/powerpc/cache_flush.S @@ -0,0 +1,43 @@ +/* cache.S - Flush the processor cache for a specific region. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2007,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#undef CACHE_LINE_BYTES +#define CACHE_LINE_BYTES 32 + + /* `address' may not be CACHE_LINE_BYTES-aligned. */ + andi. 6, 3, CACHE_LINE_BYTES - 1 /* Find the misalignment. */ + add 4, 4, 6 /* Adjust `size' to compensate. */ + + /* Force the dcache lines to memory. */ + li 5, 0 +1: dcbst 5, 3 + addi 5, 5, CACHE_LINE_BYTES + cmpw 5, 4 + blt 1b + sync /* Force all dcbsts to complete. */ + + /* Invalidate the icache lines. */ + li 5, 0 +1: icbi 5, 3 + addi 5, 5, CACHE_LINE_BYTES + cmpw 5, 4 + blt 1b + sync /* Force all icbis to complete. */ + isync /* Discard partially executed instructions that were + loaded from the invalid icache. */ diff --git a/grub-core/kern/powerpc/ieee1275/startup.S b/grub-core/kern/powerpc/ieee1275/startup.S index 526df1d91..0b1c23346 100644 --- a/grub-core/kern/powerpc/ieee1275/startup.S +++ b/grub-core/kern/powerpc/ieee1275/startup.S @@ -39,7 +39,7 @@ VARIABLE(grub_prefix) * Leave some breathing room for the prefix. */ - . = _start + GRUB_KERNEL_MACHINE_DATA_END + . = _start + GRUB_KERNEL_MACHINE_PREFIX_END codestart: li 2, 0 diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S index f0f47416d..f178f5d3c 100644 --- a/grub-core/kern/sparc64/ieee1275/crt0.S +++ b/grub-core/kern/sparc64/ieee1275/crt0.S @@ -42,7 +42,7 @@ VARIABLE(grub_prefix) * Leave some breathing room for the prefix. */ - . = EXT_C(_start) + GRUB_KERNEL_MACHINE_DATA_END + . = EXT_C(_start) + GRUB_KERNEL_MACHINE_PREFIX_END codestart: /* Copy the modules past the end of the kernel image. diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c index a9b8a520e..f3352520b 100644 --- a/grub-core/lib/arg.c +++ b/grub-core/lib/arg.c @@ -209,8 +209,16 @@ parse_option (grub_extcmd_t cmd, int key, char *arg, struct grub_arg_list *usr) if (found == -1) return -1; - usr[found].set = 1; - usr[found].arg = arg; + if (opt->flags & GRUB_ARG_OPTION_REPEATABLE) + { + usr[found].args[usr[found].set++] = arg; + usr[found].args[usr[found].set] = NULL; + } + else + { + usr[found].set = 1; + usr[found].arg = arg; + } } } @@ -230,10 +238,15 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, grub_err_t add_arg (char *s) { - argl = grub_realloc (argl, (++num) * sizeof (char *)); + char **p = argl; + argl = grub_realloc (argl, (++num + 1) * sizeof (char *)); if (! argl) - return grub_errno; + { + grub_free (p); + return grub_errno; + } argl[num - 1] = s; + argl[num] = NULL; return 0; } @@ -310,8 +323,11 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, if (option) { arglen = option - arg - 2; option++; - } else + } else { arglen = grub_strlen (arg) - 2; + if (argv[curarg + 1]) + option = argv[curarg + 1][0] == '-' ? 0 : argv[++curarg]; + } opt = find_long (cmd->options, arg + 2, arglen); if (! opt) @@ -390,3 +406,43 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, fail: return complete; } + +struct grub_arg_list* +grub_arg_list_alloc(grub_extcmd_t extcmd, int argc, + char **argv __attribute__((unused))) +{ + int i; + char **args; + unsigned argcnt; + struct grub_arg_list *list; + const struct grub_arg_option *options; + + options = extcmd->options; + if (! options) + return 0; + + argcnt = 0; + for (i = 0; options[i].doc; i++) + { + if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE) + argcnt += (argc + 1) / 2 + 1; /* max possible for any option */ + } + + list = grub_zalloc (sizeof (*list) * i + sizeof (char*) * argcnt); + if (! list) + return 0; + + args = (char**) (list + i); + for (i = 0; options[i].doc; i++) + { + list[i].set = 0; + list[i].arg = 0; + + if (options[i].flags & GRUB_ARG_OPTION_REPEATABLE) + { + list[i].args = args; + args += argc / 2 + 1; + } + } + return list; +} diff --git a/include/grub/i386/efi/loader.h b/grub-core/lib/efi/halt.c similarity index 62% rename from include/grub/i386/efi/loader.h rename to grub-core/lib/efi/halt.c index 222dae82d..ed3e1e1c0 100644 --- a/include/grub/i386/efi/loader.h +++ b/grub-core/lib/efi/halt.c @@ -1,6 +1,7 @@ +/* efi.c - generic EFI support */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2006,2007 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 @@ -16,7 +17,18 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 +#include +#include +#include +#include +#include -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ +void +grub_halt (void) +{ + grub_machine_fini (); + efi_call_4 (grub_efi_system_table->runtime_services->reset_system, + GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL); + + while (1); +} diff --git a/grub-core/lib/efi/relocator.c b/grub-core/lib/efi/relocator.c new file mode 100644 index 000000000..fc4de834b --- /dev/null +++ b/grub-core/lib/efi/relocator.c @@ -0,0 +1,104 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define NEXT_MEMORY_DESCRIPTOR(desc, size) \ + ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) + +unsigned +grub_relocator_firmware_get_max_events (void) +{ + grub_efi_uintn_t mmapsize = 0, descriptor_size = 0; + grub_efi_uint32_t descriptor_version = 0; + grub_efi_uintn_t key; + grub_efi_get_memory_map (&mmapsize, NULL, &key, &descriptor_size, + &descriptor_version); + /* Since grub_relocator_firmware_fill_events uses malloc + we need some reserve. Hence +10. */ + return 2 * (mmapsize / descriptor_size + 10); +} + +unsigned +grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events) +{ + grub_efi_uintn_t mmapsize = 0, desc_size = 0; + grub_efi_uint32_t descriptor_version = 0; + grub_efi_memory_descriptor_t *descs = NULL; + grub_efi_uintn_t key; + int counter = 0; + grub_efi_memory_descriptor_t *desc; + + grub_efi_get_memory_map (&mmapsize, NULL, &key, &desc_size, + &descriptor_version); + descs = grub_malloc (mmapsize); + if (!descs) + return 0; + + grub_efi_get_memory_map (&mmapsize, descs, &key, &desc_size, + &descriptor_version); + + for (desc = descs; + (char *) desc < ((char *) descs + mmapsize); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + { + if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) + continue; + events[counter].type = REG_FIRMWARE_START; + events[counter].pos = desc->physical_start; + counter++; + events[counter].type = REG_FIRMWARE_END; + events[counter].pos = desc->physical_start + (desc->num_pages << 12); + counter++; + } + + return counter; +} + +int +grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size) +{ + grub_efi_boot_services_t *b; + grub_efi_physical_address_t address = start; + grub_efi_status_t status; + + if (grub_efi_is_finished) + return 1; + + b = grub_efi_system_table->boot_services; + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ADDRESS, + GRUB_EFI_LOADER_DATA, size >> 12, &address); + return (status == GRUB_EFI_SUCCESS); +} + +void +grub_relocator_firmware_free_region (grub_addr_t start, grub_size_t size) +{ + grub_efi_boot_services_t *b; + + if (grub_efi_is_finished) + return; + + b = grub_efi_system_table->boot_services; + efi_call_2 (b->free_pages, start, size >> 12); +} diff --git a/include/grub/i386/pc/efiemu.h b/grub-core/lib/emu/halt.c similarity index 78% rename from include/grub/i386/pc/efiemu.h rename to grub-core/lib/emu/halt.c index f269dd085..620935b5a 100644 --- a/include/grub/i386/pc/efiemu.h +++ b/grub-core/lib/emu/halt.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,9 +16,10 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_MACHINE_EFI_EMU_HEADER -#define GRUB_MACHINE_EFI_EMU_HEADER 1 +#include -grub_err_t grub_machine_efiemu_init_tables (void); - -#endif +void +grub_halt (void) +{ + grub_reboot (); +} diff --git a/grub-core/kern/i386/halt.c b/grub-core/lib/i386/halt.c similarity index 83% rename from grub-core/kern/i386/halt.c rename to grub-core/lib/i386/halt.c index 10805e42b..74e0c7301 100644 --- a/grub-core/kern/i386/halt.c +++ b/grub-core/lib/i386/halt.c @@ -17,11 +17,24 @@ */ #include -#include #include const char bochs_shutdown[] = "Shutdown"; +/* + * This call is special... it never returns... in fact it should simply + * hang at this point! + */ +static inline void __attribute__ ((noreturn)) +stop (void) +{ + asm volatile ("cli"); + while (1) + { + asm volatile ("hlt"); + } +} + void grub_halt (void) { @@ -38,5 +51,5 @@ grub_halt (void) /* In order to return we'd have to check what the previous status of IF flag was. But user most likely doesn't want to return anyway ... */ - grub_stop (); + stop (); } diff --git a/grub-core/lib/i386/relocator.c b/grub-core/lib/i386/relocator.c index 453f73fdd..1bc4240c3 100644 --- a/grub-core/lib/i386/relocator.c +++ b/grub-core/lib/i386/relocator.c @@ -19,84 +19,252 @@ #include #include -#include #include #include +#include #include +#include -extern grub_uint8_t grub_relocator32_forward_start; -extern grub_uint8_t grub_relocator32_forward_end; -extern grub_uint8_t grub_relocator32_backward_start; -extern grub_uint8_t grub_relocator32_backward_end; +extern grub_uint8_t grub_relocator_forward_start; +extern grub_uint8_t grub_relocator_forward_end; +extern grub_uint8_t grub_relocator_backward_start; +extern grub_uint8_t grub_relocator_backward_end; -extern grub_uint32_t grub_relocator32_backward_dest; -extern grub_uint32_t grub_relocator32_backward_size; -extern grub_addr_t grub_relocator32_backward_src; +extern void *grub_relocator_backward_dest; +extern void *grub_relocator_backward_src; +extern grub_size_t grub_relocator_backward_chunk_size; -extern grub_uint32_t grub_relocator32_forward_dest; -extern grub_uint32_t grub_relocator32_forward_size; -extern grub_addr_t grub_relocator32_forward_src; +extern void *grub_relocator_forward_dest; +extern void *grub_relocator_forward_src; +extern grub_size_t grub_relocator_forward_chunk_size; -extern grub_uint32_t grub_relocator32_forward_eax; -extern grub_uint32_t grub_relocator32_forward_ebx; -extern grub_uint32_t grub_relocator32_forward_ecx; -extern grub_uint32_t grub_relocator32_forward_edx; -extern grub_uint32_t grub_relocator32_forward_eip; -extern grub_uint32_t grub_relocator32_forward_esp; +extern grub_uint8_t grub_relocator16_start; +extern grub_uint8_t grub_relocator16_end; +extern grub_uint16_t grub_relocator16_cs; +extern grub_uint16_t grub_relocator16_ip; +extern grub_uint16_t grub_relocator16_ds; +extern grub_uint16_t grub_relocator16_es; +extern grub_uint16_t grub_relocator16_fs; +extern grub_uint16_t grub_relocator16_gs; +extern grub_uint16_t grub_relocator16_ss; +extern grub_uint16_t grub_relocator16_sp; +extern grub_uint32_t grub_relocator16_edx; -extern grub_uint32_t grub_relocator32_backward_eax; -extern grub_uint32_t grub_relocator32_backward_ebx; -extern grub_uint32_t grub_relocator32_backward_ecx; -extern grub_uint32_t grub_relocator32_backward_edx; -extern grub_uint32_t grub_relocator32_backward_eip; -extern grub_uint32_t grub_relocator32_backward_esp; +extern grub_uint8_t grub_relocator32_start; +extern grub_uint8_t grub_relocator32_end; +extern grub_uint32_t grub_relocator32_eax; +extern grub_uint32_t grub_relocator32_ebx; +extern grub_uint32_t grub_relocator32_ecx; +extern grub_uint32_t grub_relocator32_edx; +extern grub_uint32_t grub_relocator32_eip; +extern grub_uint32_t grub_relocator32_esp; +extern grub_uint32_t grub_relocator32_ebp; +extern grub_uint32_t grub_relocator32_esi; +extern grub_uint32_t grub_relocator32_edi; -#define RELOCATOR_SIZEOF(x) (&grub_relocator32_##x##_end - &grub_relocator32_##x##_start) -#define RELOCATOR_ALIGN 16 -#define PREFIX(x) grub_relocator32_ ## x +extern grub_uint8_t grub_relocator64_start; +extern grub_uint8_t grub_relocator64_end; +extern grub_uint64_t grub_relocator64_rax; +extern grub_uint64_t grub_relocator64_rbx; +extern grub_uint64_t grub_relocator64_rcx; +extern grub_uint64_t grub_relocator64_rdx; +extern grub_uint64_t grub_relocator64_rip; +extern grub_uint64_t grub_relocator64_rip_addr; +extern grub_uint64_t grub_relocator64_rsp; +extern grub_uint64_t grub_relocator64_rsi; +extern grub_addr_t grub_relocator64_cr3; -static void -write_call_relocator_bw (void *ptr, void *src, grub_uint32_t dest, - grub_size_t size, struct grub_relocator32_state state) +#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start) + +grub_size_t grub_relocator_align = 1; +grub_size_t grub_relocator_forward_size; +grub_size_t grub_relocator_backward_size; +#ifdef __x86_64__ +grub_size_t grub_relocator_jumper_size = 12; +#else +grub_size_t grub_relocator_jumper_size = 7; +#endif + +void +grub_cpu_relocator_init (void) { - grub_relocator32_backward_dest = dest; - grub_relocator32_backward_src = PTR_TO_UINT64 (src); - grub_relocator32_backward_size = size; - - grub_relocator32_backward_eax = state.eax; - grub_relocator32_backward_ebx = state.ebx; - grub_relocator32_backward_ecx = state.ecx; - grub_relocator32_backward_edx = state.edx; - grub_relocator32_backward_eip = state.eip; - grub_relocator32_backward_esp = state.esp; - - grub_memmove (ptr, - &grub_relocator32_backward_start, - RELOCATOR_SIZEOF (backward)); - ((void (*) (void)) ptr) (); + grub_relocator_forward_size = RELOCATOR_SIZEOF(_forward); + grub_relocator_backward_size = RELOCATOR_SIZEOF(_backward); } -static void -write_call_relocator_fw (void *ptr, void *src, grub_uint32_t dest, - grub_size_t size, struct grub_relocator32_state state) +void +grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) { - - grub_relocator32_forward_dest = dest; - grub_relocator32_forward_src = PTR_TO_UINT64 (src); - grub_relocator32_forward_size = size; - - grub_relocator32_forward_eax = state.eax; - grub_relocator32_forward_ebx = state.ebx; - grub_relocator32_forward_ecx = state.ecx; - grub_relocator32_forward_edx = state.edx; - grub_relocator32_forward_eip = state.eip; - grub_relocator32_forward_esp = state.esp; - - grub_memmove (ptr, - &grub_relocator32_forward_start, - RELOCATOR_SIZEOF (forward)); - ((void (*) (void)) ptr) (); + grub_uint8_t *ptr; + ptr = rels; +#ifdef __x86_64__ + /* movq imm64, %rax (for relocator) */ + *(grub_uint8_t *) ptr = 0x48; + ptr++; + *(grub_uint8_t *) ptr = 0xb8; + ptr++; + *(grub_uint64_t *) ptr = addr; + ptr += sizeof (grub_uint64_t); +#else + /* movl imm32, %eax (for relocator) */ + *(grub_uint8_t *) ptr = 0xb8; + ptr++; + *(grub_uint32_t *) ptr = addr; + ptr += sizeof (grub_uint32_t); +#endif + /* jmp $eax/$rax */ + *(grub_uint8_t *) ptr = 0xff; + ptr++; + *(grub_uint8_t *) ptr = 0xe0; + ptr++; } -#include "../relocator.c" +void +grub_cpu_relocator_backward (void *ptr, void *src, void *dest, + grub_size_t size) +{ + grub_relocator_backward_dest = dest; + grub_relocator_backward_src = src; + grub_relocator_backward_chunk_size = size; + + grub_memmove (ptr, + &grub_relocator_backward_start, + RELOCATOR_SIZEOF (_backward)); +} + +void +grub_cpu_relocator_forward (void *ptr, void *src, void *dest, + grub_size_t size) +{ + grub_relocator_forward_dest = dest; + grub_relocator_forward_src = src; + grub_relocator_forward_chunk_size = size; + + grub_memmove (ptr, + &grub_relocator_forward_start, + RELOCATOR_SIZEOF (_forward)); +} + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state) +{ + grub_err_t err; + void *relst; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + (0xffffffff - RELOCATOR_SIZEOF (32)) + + 1, RELOCATOR_SIZEOF (32), 16, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + grub_relocator32_eax = state.eax; + grub_relocator32_ebx = state.ebx; + grub_relocator32_ecx = state.ecx; + grub_relocator32_edx = state.edx; + grub_relocator32_eip = state.eip; + grub_relocator32_esp = state.esp; + grub_relocator32_ebp = state.ebp; + grub_relocator32_esi = state.esi; + grub_relocator32_edi = state.edi; + + grub_memmove (get_virtual_current_address (ch), &grub_relocator32_start, + RELOCATOR_SIZEOF (32)); + + err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), + &relst, NULL); + if (err) + return err; + + asm volatile ("cli"); + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +grub_err_t +grub_relocator16_boot (struct grub_relocator *rel, + struct grub_relocator16_state state) +{ + grub_err_t err; + void *relst; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + 0xa0000 - RELOCATOR_SIZEOF (16), + RELOCATOR_SIZEOF (16), 16, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + grub_relocator16_cs = state.cs; + grub_relocator16_ip = state.ip; + + grub_relocator16_ds = state.ds; + grub_relocator16_es = state.es; + grub_relocator16_fs = state.fs; + grub_relocator16_gs = state.gs; + + grub_relocator16_ss = state.ss; + grub_relocator16_sp = state.sp; + + grub_relocator16_edx = state.edx; + + grub_memmove (get_virtual_current_address (ch), &grub_relocator16_start, + RELOCATOR_SIZEOF (16)); + + err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), + &relst, NULL); + if (err) + return err; + + asm volatile ("cli"); + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +grub_err_t +grub_relocator64_boot (struct grub_relocator *rel, + struct grub_relocator64_state state, + grub_addr_t min_addr, grub_addr_t max_addr) +{ + grub_err_t err; + void *relst; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_align (rel, &ch, min_addr, + max_addr - RELOCATOR_SIZEOF (64), + RELOCATOR_SIZEOF (64), 16, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + grub_relocator64_rax = state.rax; + grub_relocator64_rbx = state.rbx; + grub_relocator64_rcx = state.rcx; + grub_relocator64_rdx = state.rdx; + grub_relocator64_rip = state.rip; + grub_relocator64_rsp = state.rsp; + grub_relocator64_rsi = state.rsi; + grub_relocator64_cr3 = state.cr3; + + grub_memmove (get_virtual_current_address (ch), &grub_relocator64_start, + RELOCATOR_SIZEOF (64)); + + err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), + &relst, NULL); + if (err) + return err; + + asm volatile ("cli"); + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} diff --git a/grub-core/lib/i386/relocator16.S b/grub-core/lib/i386/relocator16.S new file mode 100644 index 000000000..c3768f4eb --- /dev/null +++ b/grub-core/lib/i386/relocator16.S @@ -0,0 +1,193 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +/* The code segment of the protected mode. */ +#define CODE_SEGMENT 0x08 + +/* The data segment of the protected mode. */ +#define DATA_SEGMENT 0x10 + +#define PSEUDO_REAL_CSEG 0x18 + +#define PSEUDO_REAL_DSEG 0x20 + +#include "relocator_common.S" + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE(grub_relocator16_start) + PREAMBLE + + movl %esi, %eax + movw %ax, (LOCAL (cs_base_bytes12) - LOCAL (base)) (RSI, 1) + shrl $16, %eax + movb %al, (LOCAL (cs_base_byte3) - LOCAL (base)) (RSI, 1) + + RELOAD_GDT + .code32 + /* Update other registers. */ + movl $DATA_SEGMENT, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + DISABLE_PAGING + +#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 + andl $(~GRUB_MEMORY_CPU_CR4_PAE_ON), %eax + movl %eax, %cr4 + + /* Update other registers. */ + movl $PSEUDO_REAL_DSEG, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + movl %esi, %eax + shrl $4, %eax + movw %ax, (LOCAL (segment) - LOCAL (base)) (%esi, 1) + + /* jump to a 16 bit segment */ + ljmp $PSEUDO_REAL_CSEG, $(LOCAL (cont2) - LOCAL(base)) +LOCAL(cont2): + .code16 + + /* clear the PE bit of CR0 */ + movl %cr0, %eax + andl $(~GRUB_MEMORY_CPU_CR0_PE_ON), %eax + movl %eax, %cr0 + + /* flush prefetch queue, reload %cs */ + /* ljmp */ + .byte 0xea + .word LOCAL(cont3)-LOCAL(base) +LOCAL(segment): + .word 0 + +LOCAL(cont3): + /* we are in real mode now + * set up the real mode segment registers : DS, SS, ES + */ + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_ds) + .word 0 + movw %ax, %ds + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_es) + .word 0 + movw %ax, %es + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_fs) + .word 0 + movw %ax, %fs + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_gs) + .word 0 + movw %ax, %gs + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_ss) + .word 0 + movw %ax, %ss + + /* movw imm16, %ax. */ + .byte 0xb8 +VARIABLE(grub_relocator16_sp) + .word 0 + movw %ax, %ss + + /* movw imm32, %edx. */ + .byte 0x66, 0xba +VARIABLE(grub_relocator16_edx) + .long 0 + + /* Cleared direction flag is of no problem with any current + payload and makes this implementation easier. */ + cld + + /* ljmp */ + .byte 0xea +VARIABLE(grub_relocator16_ip) + .word 0 +VARIABLE(grub_relocator16_cs) + .word 0 + + .code32 + + /* GDT. Copied from loader/i386/linux.c. */ + .p2align 4 +LOCAL(gdt): + .word 0, 0 + .byte 0, 0, 0, 0 + + /* -- code segment -- + * base = 0x00000000, limit = 0xFFFFF (4 KiB Granularity), present + * type = 32bit code execute/read, DPL = 0 + */ + .word 0xFFFF, 0 + .byte 0, 0x9A, 0xCF, 0 + + /* -- data segment -- + * base = 0x00000000, limit 0xFFFFF (4 KiB Granularity), present + * type = 32 bit data read/write, DPL = 0 + */ + .word 0xFFFF, 0 + .byte 0, 0x92, 0xCF, 0 + + /* -- 16 bit real mode CS -- + * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present + * type = 16 bit code execute/read only/conforming, DPL = 0 + */ + .word 0xFFFF +LOCAL(cs_base_bytes12): + .word 0 +LOCAL(cs_base_byte3): + .byte 0 + + .byte 0x9E, 0, 0 + + /* -- 16 bit real mode DS -- + * base = 0x00000000, limit 0x0FFFF (1 B Granularity), present + * type = 16 bit data read/write, DPL = 0 + */ + .word 0xFFFF, 0 + .byte 0, 0x92, 0, 0 +LOCAL(gdt_end): + +VARIABLE(grub_relocator16_end) diff --git a/grub-core/lib/i386/relocator32.S b/grub-core/lib/i386/relocator32.S new file mode 100644 index 000000000..09ce56ad0 --- /dev/null +++ b/grub-core/lib/i386/relocator32.S @@ -0,0 +1,134 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +/* The code segment of the protected mode. */ +#define CODE_SEGMENT 0x10 + +/* The data segment of the protected mode. */ +#define DATA_SEGMENT 0x18 + +#include "relocator_common.S" + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE(grub_relocator32_start) + PREAMBLE + + RELOAD_GDT + .code32 + /* Update other registers. */ + movl $DATA_SEGMENT, %eax + movl %eax, %ds + movl %eax, %es + movl %eax, %fs + movl %eax, %gs + movl %eax, %ss + + DISABLE_PAGING + +#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 + andl $(~GRUB_MEMORY_CPU_CR4_PAE_ON), %eax + movl %eax, %cr4 + + jmp LOCAL(cont2) +LOCAL(cont2): + .code32 + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator32_esp) + .long 0 + + movl %eax, %esp + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator32_ebp) + .long 0 + + movl %eax, %ebp + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator32_esi) + .long 0 + + movl %eax, %esi + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator32_edi) + .long 0 + + movl %eax, %edi + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator32_eax) + .long 0 + + /* mov imm32, %ebx */ + .byte 0xbb +VARIABLE(grub_relocator32_ebx) + .long 0 + + /* mov imm32, %ecx */ + .byte 0xb9 +VARIABLE(grub_relocator32_ecx) + .long 0 + + /* mov imm32, %edx */ + .byte 0xba +VARIABLE(grub_relocator32_edx) + .long 0 + + /* Cleared direction flag is of no problem with any current + payload and makes this implementation easier. */ + cld + + .byte 0xea +VARIABLE(grub_relocator32_eip) + .long 0 + .word CODE_SEGMENT + + /* GDT. Copied from loader/i386/linux.c. */ + .p2align 4 +LOCAL(gdt): + /* NULL. */ + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + /* Reserved. */ + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + /* Code segment. */ + .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00 + + /* Data segment. */ + .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 +LOCAL(gdt_end): + +VARIABLE(grub_relocator32_end) diff --git a/grub-core/lib/i386/relocator64.S b/grub-core/lib/i386/relocator64.S new file mode 100644 index 000000000..bb086418c --- /dev/null +++ b/grub-core/lib/i386/relocator64.S @@ -0,0 +1,160 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 . + */ + +#define CODE32_SEGMENT 0x18 +#define CODE_SEGMENT 0x08 + +/* The data segment of the protected mode. */ +#define DATA_SEGMENT 0x10 + +#include "relocator_common.S" + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE(grub_relocator64_start) + PREAMBLE +#ifndef __x86_64__ + DISABLE_PAGING + + /* Turn on PAE. */ + movl %cr4, %eax + orl $(GRUB_MEMORY_CPU_CR4_PAE_ON | GRUB_MEMORY_CPU_CR4_PSE_ON), %eax + movl %eax, %cr4 + + /* mov imm32, %eax */ + .byte 0xb8 +VARIABLE(grub_relocator64_cr3) + .long 0 + movl %eax, %cr3 + + /* Turn on amd64. */ + movl $GRUB_MEMORY_CPU_AMD64_MSR, %ecx + rdmsr + orl $GRUB_MEMORY_CPU_AMD64_MSR_ON, %eax + wrmsr + + /* Enable paging. */ + movl %cr0, %eax + orl $GRUB_MEMORY_CPU_CR0_PAGING_ON, %eax + movl %eax, %cr0 + + RELOAD_GDT +#else + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator64_cr3) + .quad 0 + movq %rax, %cr3 +#endif + + .code64 + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator64_rsp) + .quad 0 + + movq %rax, %rsp + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator64_rsi) + .quad 0 + + movq %rax, %rsi + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator64_rax) + .quad 0 + + /* mov imm64, %rbx */ + .byte 0x48 + .byte 0xbb +VARIABLE(grub_relocator64_rbx) + .quad 0 + + /* mov imm64, %rcx */ + .byte 0x48 + .byte 0xb9 +VARIABLE(grub_relocator64_rcx) + .quad 0 + + /* mov imm64, %rdx */ + .byte 0x48 + .byte 0xba +VARIABLE(grub_relocator64_rdx) + .quad 0 + + /* Cleared direction flag is of no problem with any current + payload and makes this implementation easier. */ + cld + + jmp *LOCAL(jump_addr) (%rip) + +LOCAL(jump_addr): +VARIABLE(grub_relocator64_rip) + .quad 0 + +#ifndef __x86_64__ + .p2align 4 +LOCAL(gdt): + /* NULL. */ + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + + /* 64-bit segment. */ + .word 0xffff /* Limit xffff. */ + .word 0x0000 /* Base xxxx0000. */ + .byte 0x00 /* Base xx00xxxx. */ + .byte (0x8 /* Type 8. */ | (1 << 4) /* Code. */ \ + | (0 << 5) /* Ring 0. */ | (1 << 7) /* Present. */) + .byte (0xf /* Limit fxxxx. */ | (0 << 4) /* AVL flag. */ \ + | (1 << 5) /* 64-bit. */ | (0 << 6) \ + | (1 << 7) /* 4K granular. */) + .byte 0x00 /* Base 00xxxxxx. */ + + /* Data segment*/ + .word 0xffff /* Limit xffff. */ + .word 0x0000 /* Base xxxx0000. */ + .byte 0x00 /* Base xx00xxxx. */ + .byte (0x0 /* Type 0. */ | (0 << 4) /* Data. */ \ + | (0 << 5) /* Ring 0. */ | (1 << 7) /* Present. */) + .byte (0xf /* Limit fxxxx. */ | (0 << 4) /* AVL flag. */ \ + | (0 << 5) /* Data. */ | (0 << 6) \ + | (1 << 7) /* 4K granular. */) + .byte 0x00 /* Base 00xxxxxx. */ + + /* Compatibility segment. */ + .word 0xffff /* Limit xffff. */ + .word 0x0000 /* Base xxxx0000. */ + .byte 0x00 /* Base xx00xxxx. */ + .byte (0x8 /* Type 8. */ | (1 << 4) /* Code. */ \ + | (0 << 5) /* Ring 0. */ | (1 << 7) /* Present. */) + .byte (0xf /* Limit fxxxx. */ | (0 << 4) /* AVL flag. */ \ + | (0 << 5) /* 32-bit. */ | (1 << 6) /* 32-bit. */ \ + | (1 << 7) /* 4K granular. */) + .byte 0x00 /* Base 00xxxxxx. */ + +LOCAL(gdt_end): +#endif + +VARIABLE(grub_relocator64_end) diff --git a/grub-core/lib/i386/relocator_asm.S b/grub-core/lib/i386/relocator_asm.S index 22490a3f8..f273586fe 100644 --- a/grub-core/lib/i386/relocator_asm.S +++ b/grub-core/lib/i386/relocator_asm.S @@ -19,232 +19,62 @@ #include #include -#ifdef BACKWARD -#define RELOCATOR_VARIABLE(x) VARIABLE(grub_relocator32_backward_ ## x) -#else -#define RELOCATOR_VARIABLE(x) VARIABLE(grub_relocator32_forward_ ## x) -#endif -#ifdef __x86_64__ -#define RAX %rax -#define RCX %rcx -#define RDI %rdi -#define RSI %rdi -#else -#define RAX %eax -#define RCX %ecx -#define RDI %edi -#define RSI %esi -#endif + .p2align 2 -/* The code segment of the protected mode. */ -#define CODE_SEGMENT 0x10 - -/* The data segment of the protected mode. */ -#define DATA_SEGMENT 0x18 - - .p2align 4 /* force 16-byte alignment */ - -RELOCATOR_VARIABLE(start) -#ifdef BACKWARD -LOCAL(base): -#endif - cli - -#ifndef __x86_64__ +VARIABLE(grub_relocator_backward_start) /* mov imm32, %eax */ .byte 0xb8 -RELOCATOR_VARIABLE(dest) +VARIABLE(grub_relocator_backward_dest) .long 0 movl %eax, %edi /* mov imm32, %eax */ .byte 0xb8 -RELOCATOR_VARIABLE(src) +VARIABLE(grub_relocator_backward_src) .long 0 movl %eax, %esi /* mov imm32, %ecx */ .byte 0xb9 -RELOCATOR_VARIABLE(size) +VARIABLE(grub_relocator_backward_chunk_size) .long 0 -#else - xorq %rax, %rax - - /* mov imm32, %eax */ - .byte 0xb8 -RELOCATOR_VARIABLE(dest) - .long 0 - movq %rax, %rdi - - /* mov imm64, %rax */ - .byte 0x48 - .byte 0xb8 -RELOCATOR_VARIABLE(src) - .long 0, 0 - movq %rax, %rsi - - xorq %rcx, %rcx - /* mov imm32, %ecx */ - .byte 0xb9 -RELOCATOR_VARIABLE(size) - .long 0 - -#endif - - mov RDI, RAX - -#ifdef BACKWARD - add RCX, RSI - add RCX, RDI -#endif - -#ifndef BACKWARD - add RCX, RAX -#endif - add $0x3, RCX - shr $2, RCX + + add %ecx, %esi + add %ecx, %edi -#ifdef BACKWARD - /* Backward movsl is implicitly off-by-four. compensate that. */ - sub $4, RSI - sub $4, RDI + /* Backward movsb is implicitly off-by-one. compensate that. */ + sub $1, %esi + sub $1, %edi /* Backward copy. */ std rep - movsl + movsb +VARIABLE(grub_relocator_backward_end) -#else - /* Forward copy. */ - cld - rep - movsl -#endif - - /* %rax contains now our new 'base'. */ - mov RAX, RSI - add $(LOCAL(cont0) - LOCAL(base)), RAX - jmp *RAX -LOCAL(cont0): - lea (LOCAL(cont1) - LOCAL(base)) (RSI, 1), RAX - movl %eax, (LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) - - lea (LOCAL(gdt) - LOCAL(base)) (RSI, 1), RAX - mov RAX, (LOCAL(gdt_addr) - LOCAL(base)) (RSI, 1) - - /* Switch to compatibility mode. */ - - lgdt (LOCAL(gdtdesc) - LOCAL(base)) (RSI, 1) - - /* Update %cs. */ - ljmp *(LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) - -LOCAL(cont1): - .code32 - - /* Update other registers. */ - movl $DATA_SEGMENT, %eax - movl %eax, %ds - movl %eax, %es - movl %eax, %fs - movl %eax, %gs - movl %eax, %ss - - /* Disable paging. */ - movl %cr0, %eax - 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 - andl $GRUB_MEMORY_CPU_CR4_PAE_ON, %eax - movl %eax, %cr4 - - jmp LOCAL(cont2) -LOCAL(cont2): - .code32 +VARIABLE(grub_relocator_forward_start) /* mov imm32, %eax */ .byte 0xb8 -RELOCATOR_VARIABLE (esp) +VARIABLE(grub_relocator_forward_dest) .long 0 + movl %eax, %edi - movl %eax, %esp - - /* mov imm32, %eax */ + /* mov imm32, %rax */ .byte 0xb8 -RELOCATOR_VARIABLE (eax) - .long 0 - - /* mov imm32, %ebx */ - .byte 0xbb -RELOCATOR_VARIABLE (ebx) +VARIABLE(grub_relocator_forward_src) .long 0 + movl %eax, %esi /* mov imm32, %ecx */ .byte 0xb9 -RELOCATOR_VARIABLE (ecx) +VARIABLE(grub_relocator_forward_chunk_size) .long 0 - /* mov imm32, %edx */ - .byte 0xba -RELOCATOR_VARIABLE (edx) - .long 0 - - /* Cleared direction flag is of no problem with any current - payload and makes this implementation easier. */ + /* Forward copy. */ cld - - .byte 0xea -RELOCATOR_VARIABLE (eip) - .long 0 - .word CODE_SEGMENT - - /* GDT. Copied from loader/i386/linux.c. */ - .p2align 4 -LOCAL(gdt): - /* NULL. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Reserved. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Code segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00 - - /* Data segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 - - .p2align 4 -LOCAL(gdtdesc): - .word 0x27 -LOCAL(gdt_addr): -#ifdef __x86_64__ - /* Filled by the code. */ - .quad 0 -#else - /* Filled by the code. */ - .long 0 -#endif - - .p2align 4 -LOCAL(jump_vector): - /* Jump location. Is filled by the code */ - .long 0 - .long CODE_SEGMENT - -#ifndef BACKWARD -LOCAL(base): -#endif - -RELOCATOR_VARIABLE(end) + rep + movsb +VARIABLE(grub_relocator_forward_end) diff --git a/grub-core/lib/i386/relocator_common.S b/grub-core/lib/i386/relocator_common.S new file mode 100644 index 000000000..bd5b53f95 --- /dev/null +++ b/grub-core/lib/i386/relocator_common.S @@ -0,0 +1,82 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 + +#ifdef __x86_64__ +#define RAX %rax +#define RSI %rsi +#else +#define RAX %eax +#define RSI %esi +#endif + + .macro DISABLE_PAGING +#ifdef GRUB_MACHINE_IEEE1275 +#endif + + movl %cr0, %eax + andl $(~GRUB_MEMORY_CPU_CR0_PAGING_ON), %eax + movl %eax, %cr0 + .endm + + .macro PREAMBLE +LOCAL(base): + /* %rax contains now our new 'base'. */ + mov RAX, RSI + + add $(LOCAL(cont0) - LOCAL(base)), RAX + jmp *RAX +LOCAL(cont0): + .endm + + .macro RELOAD_GDT + lea (LOCAL(cont1) - LOCAL(base)) (RSI, 1), RAX + movl %eax, (LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) + + lea (LOCAL(gdt) - LOCAL(base)) (RSI, 1), RAX + mov RAX, (LOCAL(gdt_addr) - LOCAL(base)) (RSI, 1) + + /* Switch to compatibility mode. */ + lgdt (LOCAL(gdtdesc) - LOCAL(base)) (RSI, 1) + + /* Update %cs. */ + ljmp *(LOCAL(jump_vector) - LOCAL(base)) (RSI, 1) + + .p2align 4 +LOCAL(gdtdesc): + .word LOCAL(gdt_end) - LOCAL(gdt) +LOCAL(gdt_addr): +#ifdef __x86_64__ + /* Filled by the code. */ + .quad 0 +#else + /* Filled by the code. */ + .long 0 +#endif + + .p2align 4 +LOCAL(jump_vector): + /* Jump location. Is filled by the code */ + .long 0 + .long CODE_SEGMENT + +LOCAL(cont1): + .endm diff --git a/grub-core/kern/i386/ieee1275/init.c b/grub-core/lib/ieee1275/halt.c similarity index 62% rename from grub-core/kern/i386/ieee1275/init.c rename to grub-core/lib/ieee1275/halt.c index 9fb98739b..7ede29de9 100644 --- a/grub-core/kern/i386/ieee1275/init.c +++ b/grub-core/lib/ieee1275/halt.c @@ -1,7 +1,7 @@ -/* init.c -- Initialize GRUB on Open Firmware. */ +/* openfw.c -- Open firmware support functions. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,12 +17,17 @@ * along with GRUB. If not, see . */ -#include -#include - -void grub_stop_floppy (void); +#include +#include void -grub_stop_floppy (void) +grub_halt (void) { + /* Not standardized. We try three known commands. */ + + grub_ieee1275_interpret ("shut-down", 0); + grub_ieee1275_interpret ("power-off", 0); + grub_ieee1275_interpret ("poweroff", 0); + + while (1); } diff --git a/grub-core/lib/ieee1275/relocator.c b/grub-core/lib/ieee1275/relocator.c new file mode 100644 index 000000000..947346d46 --- /dev/null +++ b/grub-core/lib/ieee1275/relocator.c @@ -0,0 +1,95 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include + +unsigned +grub_relocator_firmware_get_max_events (void) +{ + int counter = 0; + auto int NESTED_FUNC_ATTR count (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t len __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))); + int NESTED_FUNC_ATTR count (grub_uint64_t addr __attribute__ ((unused)), + grub_uint64_t len __attribute__ ((unused)), + grub_uint32_t type __attribute__ ((unused))) + { + counter++; + return 0; + } + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET)) + return 0; + grub_machine_mmap_iterate (count); + return 2 * counter; +} + +unsigned +grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events) +{ + int counter = 0; + auto int NESTED_FUNC_ATTR fill (grub_uint64_t addr, grub_uint64_t len, + grub_uint32_t type); + int NESTED_FUNC_ATTR fill (grub_uint64_t addr, grub_uint64_t len, + grub_uint32_t type) + { + if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + return 0; + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM)) + { + if (addr + len <= 0x180000) + return 0; + + if (addr < 0x180000) + { + len = addr + len - 0x180000; + addr = 0x180000; + } + } + + events[counter].type = REG_FIRMWARE_START; + events[counter].pos = addr; + counter++; + events[counter].type = REG_FIRMWARE_END; + events[counter].pos = addr + len; + counter++; + + return 0; + } + + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET)) + return 0; + grub_machine_mmap_iterate (fill); + return counter; +} + +int +grub_relocator_firmware_alloc_region (grub_addr_t start, grub_size_t size) +{ + return (grub_claimmap (start, size) >= 0); +} + +void +grub_relocator_firmware_free_region (grub_addr_t start, grub_size_t size) +{ + grub_ieee1275_release (start, size); +} diff --git a/grub-core/lib/mips/relocator.c b/grub-core/lib/mips/relocator.c index 118ddbd6f..537b0af2c 100644 --- a/grub-core/lib/mips/relocator.c +++ b/grub-core/lib/mips/relocator.c @@ -25,26 +25,33 @@ #include #include +#include -/* Remark: doesn't work with source outside of 4G. - Use relocator64 in this case. - */ +/* Do we need mips64? */ -extern grub_uint8_t grub_relocator32_forward_start; -extern grub_uint8_t grub_relocator32_forward_end; -extern grub_uint8_t grub_relocator32_backward_start; -extern grub_uint8_t grub_relocator32_backward_end; +extern grub_uint8_t grub_relocator_forward_start; +extern grub_uint8_t grub_relocator_forward_end; +extern grub_uint8_t grub_relocator_backward_start; +extern grub_uint8_t grub_relocator_backward_end; #define REGW_SIZEOF (2 * sizeof (grub_uint32_t)) #define JUMP_SIZEOF (2 * sizeof (grub_uint32_t)) -#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator32_##x##_end \ - - &grub_relocator32_##x##_start) +#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \ + - &grub_relocator_##x##_start) #define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ - + REGW_SIZEOF * (31 + 3) + JUMP_SIZEOF) -#define RELOCATOR_ALIGN 16 + + REGW_SIZEOF * 3) +grub_size_t grub_relocator_align = sizeof (grub_uint32_t); +grub_size_t grub_relocator_forward_size; +grub_size_t grub_relocator_backward_size; +grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; -#define PREFIX(x) grub_relocator32_ ## x +void +grub_cpu_relocator_init (void) +{ + grub_relocator_forward_size = RELOCATOR_SIZEOF(forward); + grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); +} static void write_reg (int regn, grub_uint32_t val, void **target) @@ -69,44 +76,74 @@ write_jump (int regn, void **target) *target = ((grub_uint32_t *) *target) + 1; } -static void -write_call_relocator_bw (void *ptr0, void *src, grub_uint32_t dest, - grub_size_t size, struct grub_relocator32_state state) +void +grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) +{ + write_reg (1, addr, &rels); + write_jump (1, &rels); +} + +void +grub_cpu_relocator_backward (void *ptr0, void *src, void *dest, + grub_size_t size) { void *ptr = ptr0; - int i; write_reg (8, (grub_uint32_t) src, &ptr); - write_reg (9, dest, &ptr); - write_reg (10, size, &ptr); - grub_memcpy (ptr, &grub_relocator32_backward_start, + write_reg (9, (grub_uint32_t) dest, &ptr); + write_reg (10, (grub_uint32_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_backward_start, RELOCATOR_SRC_SIZEOF (backward)); - ptr = (grub_uint8_t *) ptr + RELOCATOR_SRC_SIZEOF (backward); - for (i = 1; i < 32; i++) - write_reg (i, state.gpr[i], &ptr); - write_jump (state.jumpreg, &ptr); - grub_arch_sync_caches (ptr0, (grub_uint8_t *) ptr - (grub_uint8_t *) ptr0); - grub_dprintf ("relocator", "Backward relocator: about to jump to %p\n", ptr0); - ((void (*) (void)) ptr0) (); } -static void -write_call_relocator_fw (void *ptr0, void *src, grub_uint32_t dest, - grub_size_t size, struct grub_relocator32_state state) +void +grub_cpu_relocator_forward (void *ptr0, void *src, void *dest, + grub_size_t size) { void *ptr = ptr0; - int i; write_reg (8, (grub_uint32_t) src, &ptr); - write_reg (9, dest, &ptr); - write_reg (10, size, &ptr); - grub_memcpy (ptr, &grub_relocator32_forward_start, + write_reg (9, (grub_uint32_t) dest, &ptr); + write_reg (10, (grub_uint32_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_forward_start, RELOCATOR_SRC_SIZEOF (forward)); - ptr = (grub_uint8_t *) ptr + RELOCATOR_SRC_SIZEOF (forward); +} + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state) +{ + grub_relocator_chunk_t ch; + void *ptr; + grub_err_t err; + void *relst; + grub_size_t relsize; + grub_size_t stateset_size = 31 * REGW_SIZEOF + JUMP_SIZEOF; + unsigned i; + grub_addr_t vtarget; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + (0xffffffff - stateset_size) + + 1, stateset_size, + sizeof (grub_uint32_t), + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + ptr = get_virtual_current_address (ch); for (i = 1; i < 32; i++) write_reg (i, state.gpr[i], &ptr); write_jump (state.jumpreg, &ptr); - grub_arch_sync_caches (ptr0, (grub_uint8_t *) ptr - (grub_uint8_t *) ptr0); - grub_dprintf ("relocator", "Forward relocator: about to jump to %p\n", ptr0); - ((void (*) (void)) ptr0) (); -} -#include "../relocator.c" + vtarget = (grub_addr_t) grub_map_memory (get_physical_target_address (ch), + stateset_size); + + err = grub_relocator_prepare_relocs (rel, vtarget, &relst, &relsize); + if (err) + return err; + + grub_arch_sync_caches ((void *) relst, relsize); + + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} diff --git a/grub-core/lib/mips/relocator_asm.S b/grub-core/lib/mips/relocator_asm.S index ff4fa31e0..3408b59e1 100644 --- a/grub-core/lib/mips/relocator_asm.S +++ b/grub-core/lib/mips/relocator_asm.S @@ -20,39 +20,39 @@ .p2align 4 /* force 16-byte alignment */ -VARIABLE (grub_relocator32_forward_start) +VARIABLE (grub_relocator_forward_start) move $a0, $9 move $a1, $10 copycont1: lb $11,0($8) sb $11,0($9) - addiu $8, $8, 0x1 - addiu $9, $9, 0x1 - addiu $10, $10, 0xffff + addiu $8, $8, 1 + addiu $9, $9, 1 + addiu $10, $10, -1 bne $10, $0, copycont1 #include "../../kern/mips/cache_flush.S" -VARIABLE (grub_relocator32_forward_end) +VARIABLE (grub_relocator_forward_end) -VARIABLE (grub_relocator32_backward_start) +VARIABLE (grub_relocator_backward_start) move $a0, $9 move $a1, $10 addu $9, $9, $10 addu $8, $8, $10 /* Backward movsl is implicitly off-by-one. compensate that. */ - addiu $9, $9, 0xffff - addiu $8, $8, 0xffff + addiu $9, $9, -1 + addiu $8, $8, -1 copycont2: lb $11,0($8) sb $11,0($9) - addiu $8, $8, 0xffff - addiu $9, $9, 0xffff - addiu $10, 0xffff + addiu $8, $8, -1 + addiu $9, $9, -1 + addiu $10, $10, -1 bne $10, $0, copycont2 #include "../../kern/mips/cache_flush.S" -VARIABLE (grub_relocator32_backward_end) +VARIABLE (grub_relocator_backward_end) diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h index ce3794087..28e354759 100644 --- a/grub-core/lib/posix_wrap/sys/types.h +++ b/grub-core/lib/posix_wrap/sys/types.h @@ -22,11 +22,14 @@ #include typedef grub_size_t size_t; -typedef int bool; -static const bool true = 1; -static const bool false = 0; +typedef enum { false = 0, true = 1 } bool; #define ULONG_MAX GRUB_ULONG_MAX #define UCHAR_MAX 0xff +typedef grub_uint8_t uint8_t; +typedef grub_uint16_t uint16_t; +typedef grub_uint32_t uint32_t; +typedef grub_uint64_t uint64_t; + #endif diff --git a/grub-core/lib/powerpc/relocator.c b/grub-core/lib/powerpc/relocator.c new file mode 100644 index 000000000..85dfbeaf3 --- /dev/null +++ b/grub-core/lib/powerpc/relocator.c @@ -0,0 +1,142 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern grub_uint8_t grub_relocator_forward_start; +extern grub_uint8_t grub_relocator_forward_end; +extern grub_uint8_t grub_relocator_backward_start; +extern grub_uint8_t grub_relocator_backward_end; + +#define REGW_SIZEOF (2 * sizeof (grub_uint32_t)) +#define JUMP_SIZEOF (sizeof (grub_uint32_t)) + +#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \ + - &grub_relocator_##x##_start) +#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ + + REGW_SIZEOF * 3) +grub_size_t grub_relocator_align = sizeof (grub_uint32_t); +grub_size_t grub_relocator_forward_size; +grub_size_t grub_relocator_backward_size; +grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; + +void +grub_cpu_relocator_init (void) +{ + grub_relocator_forward_size = RELOCATOR_SIZEOF(forward); + grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); +} + +static void +write_reg (int regn, grub_uint32_t val, void **target) +{ + /* lis r, val >> 16 */ + *(grub_uint32_t *) *target = + ((0x3c00 | (regn << 5)) << 16) | (val >> 16); + *target = ((grub_uint32_t *) *target) + 1; + /* ori r, r, val & 0xffff. */ + *(grub_uint32_t *) *target = (((0x6000 | regn << 5 | regn) << 16) + | (val & 0xffff)); + *target = ((grub_uint32_t *) *target) + 1; +} + +static void +write_jump (void **target) +{ + /* blr. */ + *(grub_uint32_t *) *target = 0x4e800020; + *target = ((grub_uint32_t *) *target) + 1; +} + +void +grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) +{ + write_reg (GRUB_PPC_JUMP_REGISTER, addr, &rels); + write_jump (&rels); +} + +void +grub_cpu_relocator_backward (void *ptr0, void *src, void *dest, + grub_size_t size) +{ + void *ptr = ptr0; + write_reg (8, (grub_uint32_t) src, &ptr); + write_reg (9, (grub_uint32_t) dest, &ptr); + write_reg (10, (grub_uint32_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_backward_start, + RELOCATOR_SRC_SIZEOF (backward)); +} + +void +grub_cpu_relocator_forward (void *ptr0, void *src, void *dest, + grub_size_t size) +{ + void *ptr = ptr0; + write_reg (8, (grub_uint32_t) src, &ptr); + write_reg (9, (grub_uint32_t) dest, &ptr); + write_reg (10, (grub_uint32_t) size, &ptr); + grub_memcpy (ptr, &grub_relocator_forward_start, + RELOCATOR_SRC_SIZEOF (forward)); +} + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state) +{ + void *ptr; + grub_err_t err; + void *relst; + grub_size_t relsize; + grub_size_t stateset_size = 32 * REGW_SIZEOF + JUMP_SIZEOF; + unsigned i; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + (0xffffffff - stateset_size) + + 1, stateset_size, + sizeof (grub_uint32_t), + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + ptr = get_virtual_current_address (ch); + for (i = 0; i < 32; i++) + write_reg (i, state.gpr[i], &ptr); + write_jump (&ptr); + + err = grub_relocator_prepare_relocs (rel, get_physical_target_address (ch), + &relst, &relsize); + if (err) + return err; + + grub_arch_sync_caches ((void *) relst, relsize); + + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; +} diff --git a/grub-core/lib/powerpc/relocator_asm.S b/grub-core/lib/powerpc/relocator_asm.S new file mode 100644 index 000000000..355e9c8b4 --- /dev/null +++ b/grub-core/lib/powerpc/relocator_asm.S @@ -0,0 +1,60 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 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 + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE (grub_relocator_forward_start) + mr 3, 9 + mr 4, 10 + +copycont1: + lbz 11,0(8) + stb 11,0(9) + addi 8, 8, 0x1 + addi 9, 9, 0x1 + addi 10, 10, -1 + cmpwi 10, 0 + bne copycont1 + +#include "../../kern/powerpc/cache_flush.S" + +VARIABLE (grub_relocator_forward_end) + +VARIABLE (grub_relocator_backward_start) + mr 3, 9 + mr 4, 10 + + add 9, 9, 10 + add 8, 8, 10 + /* Backward movsl is implicitly off-by-one. compensate that. */ + addi 9, 9, -1 + addi 8, 8, -1 +copycont2: + lbz 11,0(8) + stb 11,0(9) + addi 8, 8, -1 + addi 9, 9, -1 + addi 10, 10, -1 + cmpwi 10, 0 + bne copycont2 + +#include "../../kern/powerpc/cache_flush.S" + +VARIABLE (grub_relocator_backward_end) diff --git a/grub-core/lib/relocator.c b/grub-core/lib/relocator.c index 6a5acc548..53acda52f 100644 --- a/grub-core/lib/relocator.c +++ b/grub-core/lib/relocator.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -16,122 +16,1607 @@ * along with GRUB. If not, see . */ -#define MAX_OVERHEAD ((RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) \ - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) \ - + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) \ - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN)) -#define PRE_REGION_SIZE (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) +#include +#include +#include +#include +#include +#include -void * -PREFIX (alloc) (grub_size_t size) +struct grub_relocator { - char *playground; + struct grub_relocator_chunk *chunks; + grub_phys_addr_t postchunks; + grub_phys_addr_t highestaddr; + grub_phys_addr_t highestnonpostaddr; + grub_size_t relocators_size; +}; - playground = grub_malloc (size + MAX_OVERHEAD); - if (!playground) - return 0; - - *(grub_size_t *) playground = size; - - return playground + PRE_REGION_SIZE; -} - -void * -PREFIX (realloc) (void *relocator, grub_size_t size) -{ - char *playground; - - if (!relocator) - return PREFIX (alloc) (size); - - playground = (char *) relocator - PRE_REGION_SIZE; - - playground = grub_realloc (playground, size + MAX_OVERHEAD); - if (!playground) - return 0; - - *(grub_size_t *) playground = size; - - return playground + PRE_REGION_SIZE; -} - -void -PREFIX(free) (void *relocator) -{ - if (relocator) - grub_free ((char *) relocator - PRE_REGION_SIZE); -} - -grub_err_t -PREFIX (boot) (void *relocator, grub_uint32_t dest, - struct grub_relocator32_state state) +struct grub_relocator_subchunk { + enum {CHUNK_TYPE_IN_REGION, CHUNK_TYPE_REGION_START, +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + CHUNK_TYPE_FIRMWARE, CHUNK_TYPE_LEFTOVER +#endif + } type; + grub_mm_region_t reg; + grub_mm_header_t head; + grub_phys_addr_t start; grub_size_t size; - char *playground; + grub_size_t pre_size; + struct grub_relocator_extra_block *extra; +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + struct grub_relocator_fw_leftover *pre, *post; +#endif +}; - playground = (char *) relocator - PRE_REGION_SIZE; - size = *(grub_size_t *) playground; +struct grub_relocator_chunk +{ + struct grub_relocator_chunk *next; + grub_phys_addr_t src; + void *srcv; + grub_phys_addr_t target; + grub_size_t size; + struct grub_relocator_subchunk *subchunks; + unsigned nsubchunks; +}; - grub_dprintf ("relocator", - "Relocator: source: %p, destination: 0x%x, size: 0x%lx\n", - relocator, (unsigned) dest, (unsigned long) size); +struct grub_relocator_extra_block +{ + struct grub_relocator_extra_block *next; + struct grub_relocator_extra_block **prev; + grub_phys_addr_t start; + grub_phys_addr_t end; +}; - /* Very unlikely condition: Relocator may risk overwrite itself. - Just move it a bit up. */ - if ((grub_addr_t) dest < (grub_addr_t) relocator - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN) - && (grub_addr_t) dest + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) - > (grub_addr_t) relocator) +#if GRUB_RELOCATOR_HAVE_LEFTOVERS +struct grub_relocator_fw_leftover +{ + struct grub_relocator_fw_leftover *next; + struct grub_relocator_fw_leftover **prev; + grub_phys_addr_t quantstart; + grub_uint8_t freebytes[GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT / 8]; +}; + +struct grub_relocator_fw_leftover *leftovers; +#endif + +struct grub_relocator_extra_block *extra_blocks; + +void * +get_virtual_current_address (grub_relocator_chunk_t in) +{ + return in->srcv; +} + +grub_phys_addr_t +get_physical_target_address (grub_relocator_chunk_t in) +{ + return in->target; +} + +struct grub_relocator * +grub_relocator_new (void) +{ + struct grub_relocator *ret; + + grub_cpu_relocator_init (); + + ret = grub_zalloc (sizeof (struct grub_relocator)); + if (!ret) + return NULL; + + ret->postchunks = ~(grub_phys_addr_t) 0; + ret->relocators_size = grub_relocator_jumper_size; + grub_dprintf ("relocator", "relocators_size=%lu\n", + (unsigned long) ret->relocators_size); + return ret; +} + +#define DIGITSORT_BITS 8 +#define DIGITSORT_MASK ((1 << DIGITSORT_BITS) - 1) +#define BITS_IN_BYTE 8 + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) + +static inline int +is_start (int type) +{ + return !(type & 1) && (type != COLLISION_START); +} + +static void +allocate_regstart (grub_phys_addr_t addr, grub_size_t size, grub_mm_region_t rb, + grub_mm_region_t *regancestor, grub_mm_header_t hancestor) +{ + grub_addr_t newreg_start, newreg_raw_start + = (grub_addr_t) rb + (addr - grub_vtop (rb)) + size; + grub_addr_t newreg_size, newreg_presize; + grub_mm_header_t new_header; + grub_mm_header_t hb = (grub_mm_header_t) (rb + 1); + + grub_dprintf ("relocator", "ra = %p, rb = %p\n", regancestor, rb); + + newreg_start = ALIGN_UP (newreg_raw_start, GRUB_MM_ALIGN); + newreg_presize = newreg_start - newreg_raw_start; + newreg_size = rb->size - (newreg_start - (grub_addr_t) rb); + if ((hb->size << GRUB_MM_ALIGN_LOG2) >= newreg_start + - (grub_addr_t) rb) { - void *relocator_new = ((grub_uint8_t *) relocator) - + (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN); - grub_dprintf ("relocator", "Overwrite condition detected moving " - "relocator from %p to %p\n", relocator, relocator_new); - grub_memmove (relocator_new, relocator, - (RELOCATOR_SIZEOF (forward) + RELOCATOR_ALIGN) - + size - + (RELOCATOR_SIZEOF (backward) + RELOCATOR_ALIGN)); - relocator = relocator_new; - } - - if ((grub_addr_t) dest >= (grub_addr_t) relocator) - { - int overhead; - overhead = dest - - ALIGN_UP (dest - RELOCATOR_SIZEOF (backward) - RELOCATOR_ALIGN, - RELOCATOR_ALIGN); - grub_dprintf ("relocator", - "Backward relocator: code %p, source: %p, " - "destination: 0x%x, size: 0x%lx\n", - (char *) relocator - overhead, - (char *) relocator - overhead, - (unsigned) dest - overhead, - (unsigned long) size + overhead); - - write_call_relocator_bw ((char *) relocator - overhead, - (char *) relocator - overhead, - dest - overhead, size + overhead, state); + grub_mm_header_t newhnext = hb->next; + grub_size_t newhsize = ((hb->size << GRUB_MM_ALIGN_LOG2) + - (newreg_start + - (grub_addr_t) rb)) >> GRUB_MM_ALIGN_LOG2; + new_header = (void *) (newreg_start + sizeof (*rb)); + if (newhnext == hb) + newhnext = new_header; + new_header->next = newhnext; + new_header->size = newhsize; + new_header->magic = GRUB_MM_FREE_MAGIC; } else { - int overhead; + new_header = hb->next; + if (new_header == hb) + new_header = (void *) (newreg_start + sizeof (*rb)); + } + { + struct grub_mm_header *newregfirst = rb->first; + struct grub_mm_region *newregnext = rb->next; + struct grub_mm_region *newreg = (void *) newreg_start; + hancestor->next = new_header; + if (newregfirst == hb) + newregfirst = new_header; + newreg->first = newregfirst; + newreg->next = newregnext; + newreg->pre_size = newreg_presize; + newreg->size = newreg_size; + *regancestor = newreg; + { + grub_mm_header_t h = newreg->first, hp = NULL; + do + { + if ((void *) h < (void *) (newreg + 1)) + grub_fatal ("Failed to adjust memory region: %p, %p, %p, %p, %p", + newreg, newreg->first, h, hp, hb); + if ((void *) h == (void *) (newreg + 1)) + grub_dprintf ("relocator", + "Free start memory region: %p, %p, %p, %p, %p", + newreg, newreg->first, h, hp, hb); - overhead = ALIGN_UP (dest + size, RELOCATOR_ALIGN) - + RELOCATOR_SIZEOF (forward) - (dest + size); - grub_dprintf ("relocator", - "Forward relocator: code %p, source: %p, " - "destination: 0x%x, size: 0x%lx\n", - (char *) relocator + size + overhead - - RELOCATOR_SIZEOF (forward), - relocator, (unsigned) dest, - (unsigned long) size + overhead); + hp = h; + h = h->next; + } + while (h != newreg->first); + } + } +} - write_call_relocator_fw ((char *) relocator + size + overhead - - RELOCATOR_SIZEOF (forward), - relocator, dest, size + overhead, state); +static void +allocate_inreg (grub_phys_addr_t paddr, grub_size_t size, + grub_mm_header_t hb, grub_mm_header_t hbp, + grub_mm_region_t rb) +{ + struct grub_mm_header *foll = NULL; + grub_addr_t vaddr = (grub_addr_t) hb + (paddr - grub_vtop (hb)); + + grub_dprintf ("relocator", "inreg paddr = 0x%lx, size = %lu," + " hb = %p, hbp = %p, rb = %p, vaddr = 0x%lx\n", + (unsigned long) paddr, (unsigned long) size, hb, hbp, + rb, (unsigned long) vaddr); + + if (ALIGN_UP (vaddr + size, GRUB_MM_ALIGN) + GRUB_MM_ALIGN + <= (grub_addr_t) (hb + hb->size)) + { + foll = (void *) ALIGN_UP (vaddr + size, GRUB_MM_ALIGN); + foll->magic = GRUB_MM_FREE_MAGIC; + foll->size = hb + hb->size - foll; + grub_dprintf ("relocator", "foll = %p, foll->size = %lu\n", foll, + (unsigned long) foll->size); } - /* Not reached. */ + if (vaddr - (grub_addr_t) hb >= sizeof (*hb)) + { + hb->size = ((vaddr - (grub_addr_t) hb) >> GRUB_MM_ALIGN_LOG2); + if (foll) + { + foll->next = hb; + hbp->next = foll; + if (rb->first == hb) + { + rb->first = foll; + } + } + } + else + { + if (foll) + { + foll->next = hb->next; + } + else + foll = hb->next; + + hbp->next = foll; + if (rb->first == hb) + { + rb->first = foll; + } + if (rb->first == hb) + { + rb->first = (void *) (rb + 1); + } + } +} + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS +static void +check_leftover (struct grub_relocator_fw_leftover *lo) +{ + unsigned i; + for (i = 0; i < sizeof (lo->freebytes); i++) + if (lo->freebytes[i] != 0xff) + return; + grub_relocator_firmware_free_region (lo->quantstart, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + *lo->prev = lo->next; + if (lo->next) + lo->next->prev = lo->prev; +} +#endif + +static void +free_subchunk (const struct grub_relocator_subchunk *subchu) +{ + switch (subchu->type) + { + case CHUNK_TYPE_REGION_START: + { + grub_mm_region_t r1, r2, *rp; + grub_mm_header_t h; + grub_size_t pre_size; + r1 = subchu->reg; + r2 = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) subchu->reg + + (grub_vtop (subchu->reg) + - subchu->start) + subchu->size, + GRUB_MM_ALIGN); + for (rp = &grub_mm_base; *rp && *rp != r2; rp = &((*rp)->next)); + pre_size = subchu->pre_size; + + if (*rp) + { + grub_mm_header_t h2, *hp; + r1->first = r2->first; + r1->next = r2->next; + r1->pre_size = pre_size; + r1->size = r2->size + (r2 - r1) * sizeof (*r2); + *rp = r1; + h = (grub_mm_header_t) (r1 + 1); + h->next = r2->first; + h->magic = GRUB_MM_FREE_MAGIC; + h->size = (r2 - r1 - 1); + for (hp = &r2->first, h2 = *hp; h2->next != r2->first; + hp = &(h2->next), h2 = *hp) + if (h2 == (grub_mm_header_t) (r2 + 1)) + break; + if (h2 == (grub_mm_header_t) (r2 + 1)) + { + h->size = h2->size + (h2 - h); + h->next = h2->next; + *hp = h; + if (hp == &r2->first) + { + for (h2 = r2->first; h2->next != r2->first; h2 = h2->next); + h2->next = h; + } + } + else + { + h2->next = h; + } + } + else + { + r1->pre_size = pre_size; + r1->size = (r2 - r1) * sizeof (*r2); + /* Find where to insert this region. + Put a smaller one before bigger ones, + to prevent fragmentation. */ + for (rp = &grub_mm_base; *rp; rp = &((*rp)->next)) + if ((*rp)->size > r1->size) + break; + r1->next = *rp; + *rp = r1->next; + h = (grub_mm_header_t) (r1 + 1); + r1->first = h; + h->next = h; + h->magic = GRUB_MM_FREE_MAGIC; + h->size = (r2 - r1 - 1); + } + for (r2 = grub_mm_base; r2; r2 = r2->next) + if ((grub_addr_t) r2 + r2->size == (grub_addr_t) r1) + break; + if (r2) + { + grub_mm_header_t hl2, hl, g; + g = (grub_mm_header_t) ((grub_addr_t) r2 + r2->size); + g->size = (grub_mm_header_t) r1 - g; + r2->size += r1->size; + for (hl = r2->first; hl->next != r2->first; hl = hl->next); + for (hl2 = r1->first; hl2->next != r1->first; hl2 = hl2->next); + hl2->next = r2->first; + r2->first = r1->first; + hl->next = r2->first; + *rp = (*rp)->next; + grub_free (g + 1); + } + break; + } + case CHUNK_TYPE_IN_REGION: + { + grub_mm_header_t h = (grub_mm_header_t) ALIGN_DOWN ((grub_addr_t) subchu->head, + GRUB_MM_ALIGN); + h->size + = ((subchu->start + subchu->size + GRUB_MM_ALIGN - 1) / GRUB_MM_ALIGN) + - (subchu->start / GRUB_MM_ALIGN); + h->next = h; + h->magic = GRUB_MM_ALLOC_MAGIC; + grub_free (h + 1); + break; + } +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case CHUNK_TYPE_FIRMWARE: + case CHUNK_TYPE_LEFTOVER: + { + grub_addr_t fstart, fend; + fstart = ALIGN_UP (subchu->start, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + fend = ALIGN_DOWN (subchu->start + subchu->size, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + if (fstart < fend) + grub_relocator_firmware_free_region (fstart, fend - fstart); +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + if (subchu->pre) + { + int off = subchu->start - fstart + - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + grub_memset (subchu->pre->freebytes + off / 8 + 1, + 0xff, sizeof (subchu->pre->freebytes) - off / 8 - 1); + subchu->pre->freebytes[off / 8] |= ~((1 << (off % 8)) - 1); + check_leftover (subchu->pre); + } + if (subchu->post) + { + int off = subchu->start + subchu->size - fend; + grub_memset (subchu->pre->freebytes, + 0xff, sizeof (subchu->pre->freebytes) - off / 8); + subchu->pre->freebytes[off / 8] |= ((1 << (8 - (off % 8))) - 1); + check_leftover (subchu->post); + } +#endif + *subchu->extra->prev = subchu->extra->next; + grub_free (subchu->extra); + } + break; +#endif + } +} + +static int +malloc_in_range (struct grub_relocator *rel, + grub_addr_t start, grub_addr_t end, grub_addr_t align, + grub_size_t size, struct grub_relocator_chunk *res, + int from_low_priv, int collisioncheck) +{ + grub_mm_region_t r, *ra, base_saved; + struct grub_relocator_mmap_event *events = NULL, *eventt = NULL, *t; + /* 128 is just in case of additional malloc (shouldn't happen). */ + unsigned maxevents = 2 + 128; + grub_mm_header_t p, pa; + unsigned *counter; + int nallocs = 0; + unsigned j, N = 0; + grub_addr_t target = 0; + + grub_dprintf ("relocator", + "trying to allocate in 0x%lx-0x%lx aligned 0x%lx size 0x%lx\n", + (unsigned long) start, (unsigned long) end, + (unsigned long) align, (unsigned long) size); + + start = ALIGN_UP (start, align); + end = ALIGN_DOWN (end - size, align) + size; + + if (end < start + size) + return 0; + + /* We have to avoid any allocations when filling scanline events. + Hence 2-stages. + */ + for (r = grub_mm_base; r; r = r->next) + { + p = r->first; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal ("%d: out of range pointer: %p\n", __LINE__, p); + maxevents += 2; + p = p->next; + } + while (p != r->first); + maxevents += 4; + } + + if (collisioncheck && rel) + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + maxevents += 2; + } + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + { + struct grub_relocator_extra_block *cur; + for (cur = extra_blocks; cur; cur = cur->next) + maxevents += 2; + } + for (r = grub_mm_base; r; r = r->next) + maxevents += 2; + + maxevents += grub_relocator_firmware_get_max_events (); +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + { + struct grub_relocator_fw_leftover *cur; + for (cur = leftovers; cur; cur = cur->next) + { + int l = 0; + unsigned i; + for (i = 0; i < GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; i++) + { + if (l != ((cur->freebytes[i / 8] >> (i % 8)) & 1)) + maxevents++; + l = ((cur->freebytes[i / 8] >> (i % 8)) & 1); + } + if (l) + maxevents++; + } + } +#endif + + events = grub_malloc (maxevents * sizeof (events[0])); + eventt = grub_malloc (maxevents * sizeof (events[0])); + counter = grub_malloc ((DIGITSORT_MASK + 2) * sizeof (counter[0])); + if (!events || !eventt || !counter) + { + grub_dprintf ("relocator", "events or counter allocation failed %d\n", + maxevents); + grub_free (events); + grub_free (eventt); + grub_free (counter); + return 0; + } + + if (collisioncheck && rel) + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + { + events[N].type = COLLISION_START; + events[N].pos = chunk->target; + N++; + events[N].type = COLLISION_END; + events[N].pos = chunk->target + chunk->size; + N++; + } + } + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + for (r = grub_mm_base; r; r = r->next) + { + grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n", + (unsigned long) r - r->pre_size, + (unsigned long) (r + 1) + r->size); + events[N].type = FIRMWARE_BLOCK_START; + events[N].pos = (grub_addr_t) r - r->pre_size; + N++; + events[N].type = FIRMWARE_BLOCK_END; + events[N].pos = (grub_addr_t) (r + 1) + r->size; + N++; + } + { + struct grub_relocator_extra_block *cur; + for (cur = extra_blocks; cur; cur = cur->next) + { + grub_dprintf ("relocator", "Blocking at 0x%lx-0x%lx\n", + (unsigned long) cur->start, (unsigned long) cur->end); + events[N].type = FIRMWARE_BLOCK_START; + events[N].pos = cur->start; + N++; + events[N].type = FIRMWARE_BLOCK_END; + events[N].pos = cur->end; + N++; + } + } + + N += grub_relocator_firmware_fill_events (events + N); + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + { + struct grub_relocator_fw_leftover *cur; + for (cur = leftovers; cur; cur = cur->next) + { + unsigned i; + int l = 0; + for (i = 0; i < GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; i++) + { + if (l != ((cur->freebytes[i / 8] >> (i % 8)) & 1)) + { + events[N].type = l ? REG_LEFTOVER_END : REG_LEFTOVER_START; + events[N].pos = cur->quantstart + i; + events[N].leftover = cur; + N++; + } + l = ((cur->freebytes[i / 8] >> (i % 8)) & 1); + } + if (l) + { + events[N].type = REG_LEFTOVER_END; + events[N].pos = cur->quantstart + i; + events[N].leftover = cur; + N++; + } + } + } +#endif +#endif + + /* No malloc from this point. */ + base_saved = grub_mm_base; + grub_mm_base = NULL; + + for (ra = &base_saved, r = *ra; r; ra = &(r->next), r = *ra) + { + int pre_added = 0; + pa = r->first; + p = pa->next; + if (p->magic == GRUB_MM_ALLOC_MAGIC) + continue; + do + { + grub_dprintf ("relocator", "free block %p+0x%lx\n", + p, (unsigned long) p->size); + if (p->magic != GRUB_MM_FREE_MAGIC) + grub_fatal (__FILE__":%d free magic broken at %p (0x%x)\n", + __LINE__, p, p->magic); + if (p == (grub_mm_header_t) (r + 1)) + { + pre_added = 1; + events[N].type = REG_BEG_START; + events[N].pos = grub_vtop (r) - r->pre_size; + events[N].reg = r; + events[N].regancestor = ra; + events[N].head = p; + events[N].hancestor = pa; + N++; + events[N].type = REG_BEG_END; + events[N].pos = grub_vtop (p + p->size) - sizeof (*r); + N++; + } + else + { + events[N].type = IN_REG_START; + events[N].pos = grub_vtop (p); + events[N].head = p; + events[N].hancestor = pa; + events[N].reg = r; + N++; + events[N].type = IN_REG_END; + events[N].pos = grub_vtop (p + p->size); + N++; + } + pa = p; + p = pa->next; + } + while (pa != r->first); + } + + /* Put ending events after starting events. */ + { + int st = 0, e = N / 2; + for (j = 0; j < N; j++) + if (is_start (events[j].type) || events[j].type == COLLISION_START) + eventt[st++] = events[j]; + else + eventt[e++] = events[j]; + t = eventt; + eventt = events; + events = t; + } + + { + unsigned i; + for (i = 0; i < (BITS_IN_BYTE * sizeof (grub_addr_t) / DIGITSORT_BITS); + i++) + { + memset (counter, 0, (1 + (1 << DIGITSORT_BITS)) * sizeof (counter[0])); + for (j = 0; j < N; j++) + counter[((events[j].pos >> (DIGITSORT_BITS * i)) + & DIGITSORT_MASK) + 1]++; + for (j = 0; j <= DIGITSORT_MASK; j++) + counter[j+1] += counter[j]; + for (j = 0; j < N; j++) + eventt[counter[((events[j].pos >> (DIGITSORT_BITS * i)) + & DIGITSORT_MASK)]++] = events[j]; + t = eventt; + eventt = events; + events = t; + } + } + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + retry: +#endif + + /* Now events are nicely sorted. */ + { + int nstarted = 0, ncollisions = 0, nstartedfw = 0, nblockfw = 0; +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + int nlefto = 0; +#else + const int nlefto = 0; +#endif + grub_addr_t starta = 0; + int numstarted; + for (j = from_low_priv ? 0 : N - 1; from_low_priv ? j < N : (j + 1); + from_low_priv ? j++ : j--) + { + int isinsidebefore, isinsideafter; + isinsidebefore = (!ncollisions && (nstarted || (((nlefto || nstartedfw) + && !nblockfw)))); + switch (events[j].type) + { +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case REG_FIRMWARE_START: + nstartedfw++; + break; + + case REG_FIRMWARE_END: + nstartedfw--; + break; + + case FIRMWARE_BLOCK_START: + nblockfw++; + break; + + case FIRMWARE_BLOCK_END: + nblockfw--; + break; +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case REG_LEFTOVER_START: + nlefto++; + break; + + case REG_LEFTOVER_END: + nlefto--; + break; +#endif + + case COLLISION_START: + ncollisions++; + break; + + case COLLISION_END: + ncollisions--; + break; + + case IN_REG_START: + case REG_BEG_START: + nstarted++; + break; + + case IN_REG_END: + case REG_BEG_END: + nstarted--; + break; + } + isinsideafter = (!ncollisions && (nstarted || ((nlefto || nstartedfw) + && !nblockfw))); + if (!isinsidebefore && isinsideafter) + { + starta = from_low_priv ? ALIGN_UP (events[j].pos, align) + : ALIGN_DOWN (events[j].pos - size, align) + size; + numstarted = j; + } + if (isinsidebefore && !isinsideafter && from_low_priv) + { + target = starta; + if (target < start) + target = start; + if (target + size <= end && target + size <= events[j].pos) + /* Found an usable address. */ + goto found; + } + if (isinsidebefore && !isinsideafter && !from_low_priv) + { + target = starta - size; + if (target > end - size) + target = end - size; + if (target >= start && target >= events[j].pos) + goto found; + } + } + } + + grub_mm_base = base_saved; + grub_free (events); + grub_free (eventt); + grub_free (counter); + return 0; + + found: + { + int inreg = 0, regbeg = 0, ncol = 0; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + int fwin = 0, fwb = 0, fwlefto = 0; +#endif + int last_start = 0; + for (j = 0; j < N; j++) + { + int typepre; + if (ncol) + typepre = -1; + else if (regbeg) + typepre = CHUNK_TYPE_REGION_START; + else if (inreg) + typepre = CHUNK_TYPE_IN_REGION; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + else if (fwin && !fwb) + typepre = CHUNK_TYPE_FIRMWARE; + else if (fwlefto && !fwb) + typepre = CHUNK_TYPE_LEFTOVER; +#endif + else + typepre = -1; + + if (j != 0 && events[j - 1].pos != events[j].pos) + { + grub_addr_t alloc_start, alloc_end; + alloc_start = max (events[j - 1].pos, target); + alloc_end = min (events[j].pos, target + size); + if (alloc_end > alloc_start) + { + switch (typepre) + { + case CHUNK_TYPE_REGION_START: + allocate_regstart (alloc_start, alloc_end - alloc_start, + events[last_start].reg, + events[last_start].regancestor, + events[last_start].hancestor); + /* TODO: maintain a reverse lookup tree for hancestor. */ + { + unsigned k; + for (k = 0; k < N; k++) + if (events[k].hancestor == events[last_start].head) + events[k].hancestor = events[last_start].hancestor; + } + break; + case CHUNK_TYPE_IN_REGION: + allocate_inreg (alloc_start, alloc_end - alloc_start, + events[last_start].head, + events[last_start].hancestor, + events[last_start].reg); + { + unsigned k; + for (k = 0; k < N; k++) + if (events[k].hancestor == events[last_start].head) + events[k].hancestor = events[last_start].hancestor; + } + break; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case CHUNK_TYPE_FIRMWARE: + { + grub_addr_t fstart, fend; + fstart + = ALIGN_DOWN (alloc_start, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + fend + = ALIGN_UP (alloc_end, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + grub_dprintf ("relocator", "requesting %lx-%lx\n", + (unsigned long) fstart, + (unsigned long) fend); + /* The failure here can be very expensive. */ + if (!grub_relocator_firmware_alloc_region (fstart, + fend - fstart)) + { + if (from_low_priv) + start = fend; + else + end = fstart; + goto retry; + } + break; + } +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case CHUNK_TYPE_LEFTOVER: + { + unsigned offstart = alloc_start + % GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + unsigned offend = alloc_end + % GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + struct grub_relocator_fw_leftover *lo + = events[last_start].leftover; + lo->freebytes[offstart / 8] + &= ((1 << (8 - (start % 8))) - 1); + grub_memset (lo->freebytes + (offstart + 7) / 8, 0, + offend / 8 - (offstart + 7) / 8); + lo->freebytes[offend / 8] &= ~((1 << (offend % 8)) - 1); + } + break; +#endif + } + nallocs++; + } + } + + switch (events[j].type) + { + case REG_BEG_START: + case IN_REG_START: + if (events[j].type == REG_BEG_START && + (grub_addr_t) (events[j].reg + 1) > target) + regbeg++; + else + inreg++; + last_start = j; + break; + + case REG_BEG_END: + case IN_REG_END: + if (regbeg) + regbeg--; + else + inreg--; + break; + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case REG_FIRMWARE_START: + fwin++; + break; + + case REG_FIRMWARE_END: + fwin--; + break; + + case FIRMWARE_BLOCK_START: + fwb++; + break; + + case FIRMWARE_BLOCK_END: + fwb--; + break; +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case REG_LEFTOVER_START: + fwlefto++; + break; + + case REG_LEFTOVER_END: + fwlefto--; + break; +#endif + case COLLISION_START: + ncol++; + break; + case COLLISION_END: + ncol--; + break; + } + + } + } + + /* Malloc is available again. */ + grub_mm_base = base_saved; + + { + int last_start = 0; + int inreg = 0, regbeg = 0, ncol = 0; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + int fwin = 0, fwlefto = 0, fwb = 0; +#endif + unsigned cural = 0; + int oom = 0; + res->subchunks = grub_malloc (sizeof (res->subchunks[0]) * nallocs); + if (!res->subchunks) + oom = 1; + res->nsubchunks = nallocs; + + for (j = 0; j < N; j++) + { + int typepre; + if (ncol) + typepre = -1; + else if (regbeg) + typepre = CHUNK_TYPE_REGION_START; + else if (inreg) + typepre = CHUNK_TYPE_IN_REGION; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + else if (fwin && !fwb) + typepre = CHUNK_TYPE_FIRMWARE; + else if (fwlefto && !fwb) + typepre = CHUNK_TYPE_LEFTOVER; +#endif + else + typepre = -1; + + if (j != 0 && events[j - 1].pos != events[j].pos) + { + grub_addr_t alloc_start, alloc_end; + struct grub_relocator_subchunk tofree; + struct grub_relocator_subchunk *curschu = &tofree; + if (!oom) + curschu = &res->subchunks[cural]; + alloc_start = max (events[j - 1].pos, target); + alloc_end = min (events[j].pos, target + size); + if (alloc_end > alloc_start) + { + grub_dprintf ("relocator", "subchunk 0x%lx-0x%lx, %d\n", + (unsigned long) alloc_start, + (unsigned long) alloc_end, typepre); + curschu->type = typepre; + curschu->start = alloc_start; + curschu->size = alloc_end - alloc_start; + if (typepre == CHUNK_TYPE_REGION_START + || typepre == CHUNK_TYPE_IN_REGION) + { + curschu->reg = events[last_start].reg; + curschu->head = events[last_start].head; + curschu->pre_size = alloc_start - events[j - 1].pos; + } + if (!oom && (typepre == CHUNK_TYPE_REGION_START +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + || typepre == CHUNK_TYPE_FIRMWARE +#endif + )) + { + struct grub_relocator_extra_block *ne; + ne = grub_malloc (sizeof (*ne)); + if (!ne) + { + oom = 1; + grub_memcpy (&tofree, curschu, sizeof (tofree)); + } + else + { + ne->start = alloc_start; + ne->end = alloc_end; + ne->next = extra_blocks; + ne->prev = &extra_blocks; + if (extra_blocks) + extra_blocks->prev = &(ne->next); + extra_blocks = ne; + curschu->extra = ne; + } + } +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + if (!oom && typepre == CHUNK_TYPE_FIRMWARE) + { + grub_addr_t fstart, fend; + + fstart + = ALIGN_DOWN (alloc_start, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + fend + = ALIGN_UP (alloc_end, + GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT); + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + { + struct grub_relocator_fw_leftover *lo1 = NULL; + struct grub_relocator_fw_leftover *lo2 = NULL; + if (fstart != alloc_start) + lo1 = grub_malloc (sizeof (*lo1)); + if (fend != alloc_end) + lo2 = grub_malloc (sizeof (*lo2)); + if ((!lo1 && fstart != alloc_start) + || (!lo2 && fend != alloc_end)) + { + struct grub_relocator_extra_block *ne; + grub_free (lo1); + grub_free (lo2); + lo1 = NULL; + lo2 = NULL; + oom = 1; + grub_memcpy (&tofree, curschu, sizeof (tofree)); + ne = extra_blocks; + extra_blocks = extra_blocks->next; + grub_free (ne); + } + if (lo1) + { + lo1->quantstart = fstart; + grub_memset (lo1->freebytes, 0xff, + (alloc_start - fstart) / 8); + lo1->freebytes[(alloc_start - fstart) / 8] + = (1 << ((alloc_start - fstart) % 8)) - 1; + grub_memset (lo1->freebytes + + ((alloc_start - fstart) / 8) + 1, 0, + sizeof (lo1->freebytes) + - (alloc_start - fstart) / 8 - 1); + lo1->next = leftovers; + lo1->prev = &leftovers; + if (leftovers) + leftovers->prev = &lo1->next; + leftovers = lo1; + } + if (lo2) + { + lo2->quantstart + = fend - GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT; + grub_memset (lo2->freebytes, 0, + (alloc_end - lo2->quantstart) / 8); + lo2->freebytes[(alloc_end - lo2->quantstart) / 8] + = ~((1 << ((alloc_end - lo2->quantstart) % 8)) - 1); + grub_memset (lo2->freebytes + + ((alloc_end - lo2->quantstart) / 8) + + 1, 0, sizeof (lo2->freebytes) + - (alloc_end - lo2->quantstart) / 8 - 1); + lo2->prev = &leftovers; + if (leftovers) + leftovers->prev = &lo2->next; + lo2->next = leftovers; + leftovers = lo2; + } + curschu->pre = lo1; + curschu->post = lo2; + } +#endif + } + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + if (typepre == CHUNK_TYPE_LEFTOVER) + { + curschu->pre = events[last_start].leftover; + curschu->post = events[last_start].leftover; + } +#endif + +#endif + if (!oom) + cural++; + else + free_subchunk (&tofree); + } + } + + switch (events[j].type) + { + case REG_BEG_START: + case IN_REG_START: + if (events[j].type == REG_BEG_START && + (grub_addr_t) (events[j].reg + 1) > target) + regbeg++; + else + inreg++; + last_start = j; + break; + + case REG_BEG_END: + case IN_REG_END: + inreg = regbeg = 0; + break; + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + case REG_FIRMWARE_START: + fwin++; + break; + + case REG_FIRMWARE_END: + fwin--; + break; + + case FIRMWARE_BLOCK_START: + fwb++; + break; + + case FIRMWARE_BLOCK_END: + fwb--; + break; +#endif + +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + case REG_LEFTOVER_START: + fwlefto++; + break; + + case REG_LEFTOVER_END: + fwlefto--; + break; +#endif + case COLLISION_START: + ncol++; + break; + case COLLISION_END: + ncol--; + break; + } + } + if (oom) + { + unsigned i; + for (i = 0; i < cural; i++) + free_subchunk (&res->subchunks[i]); + grub_free (res->subchunks); + grub_dprintf ("relocator", "allocation failed with out-of-memory\n"); + return 0; + } + } + + res->src = target; + res->size = size; + grub_dprintf ("relocator", "allocated: 0x%lx+0x%lx\n", (unsigned long) target, + (unsigned long) size); + + return 1; +} + +static void +adjust_limits (struct grub_relocator *rel, + grub_phys_addr_t *min_addr, grub_phys_addr_t *max_addr, + grub_phys_addr_t in_min, grub_phys_addr_t in_max) +{ + struct grub_relocator_chunk *chunk; + + *min_addr = 0; + *max_addr = rel->postchunks; + + /* Keep chunks in memory in the same order as they'll be after relocation. */ + for (chunk = rel->chunks; chunk; chunk = chunk->next) + { + if (chunk->target > in_max && chunk->src < *max_addr + && chunk->src < rel->postchunks) + *max_addr = chunk->src; + if (chunk->target + chunk->size <= in_min + && chunk->src + chunk->size > *min_addr + && chunk->src < rel->postchunks) + *min_addr = chunk->src + chunk->size; + } +} + +grub_err_t +grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t target, grub_size_t size) +{ + struct grub_relocator_chunk *chunk; + grub_phys_addr_t min_addr = 0, max_addr; + + if (target > ~size) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "address is out of range"); + + adjust_limits (rel, &min_addr, &max_addr, target, target); + + for (chunk = rel->chunks; chunk; chunk = chunk->next) + if ((chunk->target <= target && target < chunk->target + chunk->size) + || (target <= chunk->target && chunk->target < target + size)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "overlap detected"); + + chunk = grub_malloc (sizeof (struct grub_relocator_chunk)); + if (!chunk) + return grub_errno; + + grub_dprintf ("relocator", + "min_addr = 0x%llx, max_addr = 0x%llx, target = 0x%llx\n", + (unsigned long long) min_addr, (unsigned long long) max_addr, + (unsigned long long) target); + + do + { + /* A trick to improve Linux allocation. */ +#if defined (__i386__) || defined (__x86_64__) + if (target < 0x100000) + if (malloc_in_range (rel, rel->highestnonpostaddr, ~(grub_addr_t)0, 1, + size, chunk, 0, 1)) + { + if (rel->postchunks > chunk->src) + rel->postchunks = chunk->src; + break; + } +#endif + if (malloc_in_range (rel, target, max_addr, 1, size, chunk, 1, 0)) + break; + + if (malloc_in_range (rel, min_addr, target, 1, size, chunk, 0, 0)) + break; + + if (malloc_in_range (rel, rel->highestnonpostaddr, ~(grub_addr_t)0, 1, + size, chunk, 0, 1)) + { + if (rel->postchunks > chunk->src) + rel->postchunks = chunk->src; + break; + } + + grub_dprintf ("relocator", "not allocated\n"); + grub_free (chunk); + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + } + while (0); + + grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n", + (unsigned long long) chunk->src, (unsigned long long) target); + + if (rel->highestaddr < target + size) + rel->highestaddr = target + size; + + if (rel->highestaddr < chunk->src + size) + rel->highestaddr = chunk->src + size; + + if (chunk->src < rel->postchunks) + { + if (rel->highestnonpostaddr < target + size) + rel->highestnonpostaddr = target + size; + + if (rel->highestnonpostaddr < chunk->src + size) + rel->highestnonpostaddr = chunk->src + size; + } + + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + + if (chunk->src < target) + rel->relocators_size += grub_relocator_backward_size; + if (chunk->src > target) + rel->relocators_size += grub_relocator_forward_size; + + grub_dprintf ("relocator", "relocators_size=%ld\n", + (unsigned long) rel->relocators_size); + + chunk->target = target; + chunk->size = size; + chunk->next = rel->chunks; + rel->chunks = chunk; + grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks, + rel->chunks->next); + + chunk->srcv = grub_map_memory (chunk->src, chunk->size); + *out = chunk; +#ifdef DEBUG_RELOCATOR + { + grub_mm_region_t r; + grub_mm_header_t p; + grub_memset (chunk->srcv, 0xfa, chunk->size); + for (r = grub_mm_base; r; r = r->next) + { + p = r->first; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal (__FILE__ ":%d: out of range pointer: %p\n", __LINE__, p); + p = p->next; + } + while (p != r->first); + } + } +#endif return GRUB_ERR_NONE; } + +grub_err_t +grub_relocator_alloc_chunk_align (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t min_addr, + grub_phys_addr_t max_addr, + grub_size_t size, grub_size_t align, + int preference) +{ + grub_addr_t min_addr2 = 0, max_addr2; + struct grub_relocator_chunk *chunk; + + if (max_addr > ~size) + max_addr = ~size; + +#ifdef GRUB_MACHINE_PCBIOS + if (min_addr < 0x1000) + min_addr = 0x1000; +#endif + + grub_dprintf ("relocator", "chunks = %p\n", rel->chunks); + + chunk = grub_malloc (sizeof (struct grub_relocator_chunk)); + if (!chunk) + return grub_errno; + + if (malloc_in_range (rel, min_addr, max_addr, align, + size, chunk, + preference != GRUB_RELOCATOR_PREFERENCE_HIGH, 1)) + { + grub_dprintf ("relocator", "allocated 0x%llx/0x%llx\n", + (unsigned long long) chunk->src, + (unsigned long long) chunk->src); + grub_dprintf ("relocator", "chunks = %p\n", rel->chunks); + chunk->target = chunk->src; + chunk->size = size; + chunk->next = rel->chunks; + rel->chunks = chunk; + chunk->srcv = grub_map_memory (chunk->src, chunk->size); + *out = chunk; + return GRUB_ERR_NONE; + } + + adjust_limits (rel, &min_addr2, &max_addr2, min_addr, max_addr); + grub_dprintf ("relocator", "Adjusted limits from %lx-%lx to %lx-%lx\n", + (unsigned long) min_addr, (unsigned long) max_addr, + (unsigned long) min_addr2, (unsigned long) max_addr2); + + do + { + if (malloc_in_range (rel, min_addr2, max_addr2, align, + size, chunk, 1, 1)) + break; + + if (malloc_in_range (rel, rel->highestnonpostaddr, ~(grub_addr_t)0, 1, + size, chunk, 0, 1)) + { + if (rel->postchunks > chunk->src) + rel->postchunks = chunk->src; + break; + } + + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + } + while (0); + + { + int found = 0; + auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); + int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t sz, grub_uint32_t type) + { + grub_uint64_t candidate; + if (type != GRUB_MACHINE_MEMORY_AVAILABLE) + return 0; + candidate = ALIGN_UP (addr, align); + if (candidate < min_addr) + candidate = ALIGN_UP (min_addr, align); + if (candidate + size > addr + sz + || candidate > ALIGN_DOWN (max_addr, align)) + return 0; + if (preference == GRUB_RELOCATOR_PREFERENCE_HIGH) + candidate = ALIGN_DOWN (min (addr + sz - size, max_addr), align); + if (!found || (preference == GRUB_RELOCATOR_PREFERENCE_HIGH + && candidate > chunk->target)) + chunk->target = candidate; + if (!found || (preference == GRUB_RELOCATOR_PREFERENCE_LOW + && candidate < chunk->target)) + chunk->target = candidate; + found = 1; + return 0; + } + + grub_machine_mmap_iterate (hook); + if (!found) + return grub_error (GRUB_ERR_BAD_OS, "couldn't find suitable memory target"); + } + while (1) + { + struct grub_relocator_chunk *chunk2; + for (chunk2 = rel->chunks; chunk2; chunk2 = chunk2->next) + if ((chunk2->target <= chunk->target + && chunk->target < chunk2->target + chunk2->size) + || (chunk2->target <= chunk->target + size + && chunk->target + size < chunk2->target + chunk2->size) + || (chunk->target <= chunk2->target && chunk2->target + < chunk->target + size) + || (chunk->target <= chunk2->target + chunk2->size + && chunk2->target + chunk2->size < chunk->target + size)) + { + if (preference == GRUB_RELOCATOR_PREFERENCE_HIGH) + chunk->target = ALIGN_DOWN (chunk2->target, align); + else + chunk->target = ALIGN_UP (chunk2->target + chunk2->size, align); + break; + } + if (!chunk2) + break; + } + + if (chunk->src < chunk->target) + rel->relocators_size += grub_relocator_backward_size; + if (chunk->src > chunk->target) + rel->relocators_size += grub_relocator_forward_size; + + chunk->size = size; + chunk->next = rel->chunks; + rel->chunks = chunk; + grub_dprintf ("relocator", "cur = %p, next = %p\n", rel->chunks, + rel->chunks->next); + chunk->srcv = grub_map_memory (chunk->src, chunk->size); + *out = chunk; +#ifdef DEBUG_RELOCATOR + { + grub_mm_region_t r; + grub_mm_header_t p; + + grub_memset (chunk->srcv, 0xfa, chunk->size); + for (r = grub_mm_base; r; r = r->next) + { + p = r->first; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal (__FILE__ "%d: out of range pointer: %p\n", __LINE__, p); + p = p->next; + } + while (p != r->first); + } + } +#endif + return GRUB_ERR_NONE; +} + +void +grub_relocator_unload (struct grub_relocator *rel) +{ + struct grub_relocator_chunk *chunk, *next; + if (!rel) + return; + for (chunk = rel->chunks; chunk; chunk = next) + { + unsigned i; + for (i = 0; i < chunk->nsubchunks; i++) + free_subchunk (&chunk->subchunks[i]); + grub_unmap_memory (chunk->srcv, chunk->size); + next = chunk->next; + grub_free (chunk->subchunks); + grub_free (chunk); + } + grub_free (rel); +} + +grub_err_t +grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr, + void **relstart, grub_size_t *relsize) +{ + grub_uint8_t *rels; + grub_uint8_t *rels0; + struct grub_relocator_chunk *sorted; + grub_size_t nchunks = 0; + unsigned j; + struct grub_relocator_chunk movers_chunk; + + grub_dprintf ("relocator", "Preparing relocs (size=%ld)\n", + (unsigned long) rel->relocators_size); + + if (!malloc_in_range (rel, 0, ~(grub_addr_t)0 - rel->relocators_size + 1, + grub_relocator_align, + rel->relocators_size, &movers_chunk, 1, 1)) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + rels = rels0 = grub_map_memory (movers_chunk.src, movers_chunk.size); + + if (relsize) + *relsize = rel->relocators_size; + + grub_dprintf ("relocator", "Relocs allocated at %p\n", movers_chunk.srcv); + + { + unsigned i; + grub_size_t count[257]; + struct grub_relocator_chunk *from, *to, *tmp; + + grub_memset (count, 0, sizeof (count)); + + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + { + grub_dprintf ("relocator", "chunk %p->%p, 0x%lx\n", + (void *) chunk->src, (void *) chunk->target, + (unsigned long) chunk->size); + nchunks++; + count[(chunk->src & 0xff) + 1]++; + } + } + from = grub_malloc (nchunks * sizeof (sorted[0])); + to = grub_malloc (nchunks * sizeof (sorted[0])); + if (!from || !to) + { + grub_free (from); + grub_free (to); + return grub_errno; + } + + for (j = 0; j < 256; j++) + count[j+1] += count[j]; + + { + struct grub_relocator_chunk *chunk; + for (chunk = rel->chunks; chunk; chunk = chunk->next) + from[count[chunk->src & 0xff]++] = *chunk; + } + + for (i = 1; i < GRUB_CPU_SIZEOF_VOID_P; i++) + { + grub_memset (count, 0, sizeof (count)); + for (j = 0; j < nchunks; j++) + count[((from[j].src >> (8 * i)) & 0xff) + 1]++; + for (j = 0; j < 256; j++) + count[j+1] += count[j]; + for (j = 0; j < nchunks; j++) + to[count[(from[j].src >> (8 * i)) & 0xff]++] = from[j]; + tmp = to; + to = from; + from = tmp; + } + sorted = from; + grub_free (to); + } + + for (j = 0; j < nchunks; j++) + { + grub_dprintf ("relocator", "sorted chunk %p->%p, 0x%lx\n", + (void *) sorted[j].src, (void *) sorted[j].target, + (unsigned long) sorted[j].size); + if (sorted[j].src < sorted[j].target) + { + grub_cpu_relocator_backward ((void *) rels, + sorted[j].srcv, + grub_map_memory (sorted[j].target, + sorted[j].size), + sorted[j].size); + rels += grub_relocator_backward_size; + } + if (sorted[j].src > sorted[j].target) + { + grub_cpu_relocator_forward ((void *) rels, + sorted[j].srcv, + grub_map_memory (sorted[j].target, + sorted[j].size), + sorted[j].size); + rels += grub_relocator_forward_size; + } + if (sorted[j].src == sorted[j].target) + grub_arch_sync_caches (sorted[j].srcv, sorted[j].size); + } + grub_cpu_relocator_jumper ((void *) rels, (grub_addr_t) addr); + *relstart = rels0; + grub_free (sorted); + return GRUB_ERR_NONE; +} + +void +grub_mm_check_real (char *file, int line) +{ + grub_mm_region_t r; + grub_mm_header_t p, pa; + + for (r = grub_mm_base; r; r = r->next) + { + pa = r->first; + p = pa->next; + if (p->magic == GRUB_MM_ALLOC_MAGIC) + continue; + do + { + if ((grub_addr_t) p < (grub_addr_t) (r + 1) + || (grub_addr_t) p >= (grub_addr_t) (r + 1) + r->size) + grub_fatal ("%s:%d: out of range pointer: %p\n", file, line, p); + if (p->magic != GRUB_MM_FREE_MAGIC) + grub_fatal ("%s:%d free magic broken at %p (0x%x)\n", file, + line, p, p->magic); + pa = p; + p = pa->next; + } + while (pa != r->first); + } +} diff --git a/grub-core/lib/x86_64/relocator_asm.S b/grub-core/lib/x86_64/relocator_asm.S new file mode 100644 index 000000000..2ab6d8cb7 --- /dev/null +++ b/grub-core/lib/x86_64/relocator_asm.S @@ -0,0 +1,85 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + + .p2align 2 + +VARIABLE(grub_relocator_backward_start) + /* mov imm32, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator_backward_dest) + .long 0, 0 + movq %rax, %rdi + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator_backward_src) + .long 0, 0 + movq %rax, %rsi + + /* mov imm64, %rcx */ + .byte 0x48 + .byte 0xb9 +VARIABLE(grub_relocator_backward_chunk_size) + .long 0, 0 + + add %rcx, %rsi + add %rcx, %rdi + + /* Backward movsb is implicitly off-by-one. compensate that. */ + sub $1, %rsi + sub $1, %rdi + + /* Backward copy. */ + std + + rep + movsb +VARIABLE(grub_relocator_backward_end) + + +VARIABLE(grub_relocator_forward_start) + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator_forward_dest) + .long 0, 0 + movq %rax, %rdi + + /* mov imm64, %rax */ + .byte 0x48 + .byte 0xb8 +VARIABLE(grub_relocator_forward_src) + .long 0, 0 + movq %rax, %rsi + + /* mov imm64, %rcx */ + .byte 0x48 + .byte 0xb9 +VARIABLE(grub_relocator_forward_chunk_size) + .long 0, 0 + + /* Forward copy. */ + cld + rep + movsb +VARIABLE(grub_relocator_forward_end) diff --git a/grub-core/lib/xzembed/xz.h b/grub-core/lib/xzembed/xz.h new file mode 100644 index 000000000..f0a7dbbca --- /dev/null +++ b/grub-core/lib/xzembed/xz.h @@ -0,0 +1,180 @@ +/* xz.h - XZ decompressor */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#ifndef XZ_H +#define XZ_H + +#include + +/** + * enum xz_ret - Return codes + * @XZ_OK: Everything is OK so far. More input or more output + * space is required to continue. + * @XZ_STREAM_END: Operation finished successfully. + * @XZ_MEMLIMIT_ERROR: Not enough memory was preallocated at decoder + * initialization time. + * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic bytes). + * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested + * compression options. In the decoder this means that + * the header CRC32 matches, but the header itself + * specifies something that we don't support. + * @XZ_DATA_ERROR: Compressed data is corrupt. + * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly + * different between multi-call and single-call mode; + * more information below. + * + * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls + * to XZ code cannot consume any input and cannot produce any new output. + * This happens when there is no new input available, or the output buffer + * is full while at least one output byte is still pending. Assuming your + * code is not buggy, you can get this error only when decoding a compressed + * stream that is truncated or otherwise corrupt. + * + * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer + * is too small, or the compressed input is corrupt in a way that makes the + * decoder produce more output than the caller expected. When it is + * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR + * is used instead of XZ_BUF_ERROR. + */ +enum xz_ret { + XZ_OK, + XZ_STREAM_END, + XZ_MEMLIMIT_ERROR, + XZ_FORMAT_ERROR, + XZ_OPTIONS_ERROR, + XZ_DATA_ERROR, + XZ_BUF_ERROR +}; + +/** + * struct xz_buf - Passing input and output buffers to XZ code + * @in: Beginning of the input buffer. This may be NULL if and only + * if in_pos is equal to in_size. + * @in_pos: Current position in the input buffer. This must not exceed + * in_size. + * @in_size: Size of the input buffer + * @out: Beginning of the output buffer. This may be NULL if and only + * if out_pos is equal to out_size. + * @out_pos: Current position in the output buffer. This must not exceed + * out_size. + * @out_size: Size of the output buffer + * + * Only the contents of the output buffer from out[out_pos] onward, and + * the variables in_pos and out_pos are modified by the XZ code. + */ +struct xz_buf { + const uint8_t *in; + size_t in_pos; + size_t in_size; + + uint8_t *out; + size_t out_pos; + size_t out_size; +}; + +/** + * struct xz_dec - Opaque type to hold the XZ decoder state + */ +struct xz_dec; + +/** + * xz_dec_init() - Allocate and initialize a XZ decoder state + * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for + * multi-call decoding, or special value of zero to indicate + * single-call decoding mode. + * + * If dict_max > 0, the decoder is initialized to work in multi-call mode. + * dict_max number of bytes of memory is preallocated for the LZMA2 + * dictionary. This way there is no risk that xz_dec_run() could run out + * of memory, since xz_dec_run() will never allocate any memory. Instead, + * if the preallocated dictionary is too small for decoding the given input + * stream, xz_dec_run() will return XZ_MEMLIMIT_ERROR. Thus, it is important + * to know what kind of data will be decoded to avoid allocating excessive + * amount of memory for the dictionary. + * + * LZMA2 dictionary is always 2^n bytes or 2^n + 2^(n-1) bytes (the latter + * sizes are less common in practice). In the kernel, dictionary sizes of + * 64 KiB, 128 KiB, 256 KiB, 512 KiB, and 1 MiB are probably the only + * reasonable values. + * + * If dict_max == 0, the decoder is initialized to work in single-call mode. + * In single-call mode, xz_dec_run() decodes the whole stream at once. The + * caller must provide enough output space or the decoding will fail. The + * output space is used as the dictionary buffer, which is why there is + * no need to allocate the dictionary as part of the decoder's internal + * state. + * + * Because the output buffer is used as the workspace, streams encoded using + * a big dictionary are not a problem in single-call. It is enough that the + * output buffer is is big enough to hold the actual uncompressed data; it + * can be smaller than the dictionary size stored in the stream headers. + * + * On success, xz_dec_init() returns a pointer to struct xz_dec, which is + * ready to be used with xz_dec_run(). On error, xz_dec_init() returns NULL. + */ +struct xz_dec * xz_dec_init(uint32_t dict_max); + +/** + * xz_dec_run() - Run the XZ decoder + * @s: Decoder state allocated using xz_dec_init() + * @b: Input and output buffers + * + * In multi-call mode, this function may return any of the values listed in + * enum xz_ret. + * + * In single-call mode, this function never returns XZ_OK. If an error occurs + * in single-call mode (return value is not XZ_STREAM_END), b->in_pos and + * b->out_pos are not modified, and the contents of the output buffer from + * b->out[b->out_pos] onward are undefined. + * + * NOTE: In single-call mode, the contents of the output buffer are undefined + * also after XZ_BUF_ERROR. This is because with some filter chains, there + * may be a second pass over the output buffer, and this pass cannot be + * properly done if the output buffer is truncated. Thus, you cannot give + * the single-call decoder a too small buffer and then expect to get that + * amount valid data from the beginning of the stream. You must use the + * multi-call decoder if you don't want to uncompress the whole stream. + */ +enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b); + +/** + * xz_dec_reset() - Reset an already allocated decoder state + * @s: Decoder state allocated using xz_dec_init() + * + * This function can be used to reset the multi-call decoder state without + * freeing and reallocating memory with xz_dec_end() and xz_dec_init(). + * + * In single-call mode, xz_dec_reset() is always called in the beginning of + * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in + * multi-call mode. + */ +void xz_dec_reset(struct xz_dec *s); + +/** + * xz_dec_end() - Free the memory allocated for the decoder state + * @s: Decoder state allocated using xz_dec_init(). If s is NULL, + * this function does nothing. + */ +void xz_dec_end(struct xz_dec *s); + +#endif diff --git a/grub-core/lib/xzembed/xz_config.h b/grub-core/lib/xzembed/xz_config.h new file mode 100644 index 000000000..0af0d2b81 --- /dev/null +++ b/grub-core/lib/xzembed/xz_config.h @@ -0,0 +1,141 @@ +/* xz_config.h - Private includes and definitions for userspace use */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#ifndef XZ_CONFIG_H +#define XZ_CONFIG_H + +/* Enable BCJ filter decoders. */ + +#if defined(__i386__) || defined(__x86_64__) + #define XZ_DEC_X86 +#endif + +#ifdef __powerpc__ + #define XZ_DEC_POWERPC +#endif + +#ifdef __ia64__ + #define XZ_DEC_IA64 +#endif + +#ifdef __arm__ + #define XZ_DEC_ARM +#endif + +#ifdef __thumb__ + #define XZ_DEC_ARMTHUMB +#endif + +#ifdef __sparc__ + #define XZ_DEC_SPARC +#endif + + +#include "xz.h" +#include + +#define kmalloc(size, flags) malloc(size) +#define kfree(ptr) free(ptr) +#define vmalloc(size) malloc(size) +#define vfree(ptr) free(ptr) + +#define memeq(a, b, size) (memcmp(a, b, size) == 0) +#define memzero(buf, size) memset(buf, 0, size) + +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define min_t(type, x, y) min(x, y) + +/* + * Some functions have been marked with __always_inline to keep the + * performance reasonable even when the compiler is optimizing for + * small code size. You may be able to save a few bytes by #defining + * __always_inline to plain inline, but don't complain if the code + * becomes slow. + * + * NOTE: System headers on GNU/Linux may #define this macro already, + * so if you want to change it, it you need to #undef it first. + */ +#ifndef __always_inline +# ifdef __GNUC__ +# define __always_inline \ + inline __attribute__((__always_inline__)) +# else +# define __always_inline inline +# endif +#endif + +/* + * Some functions are marked to never be inlined to reduce stack usage. + * If you don't care about stack usage, you may want to modify this so + * that noinline_for_stack is #defined to be empty even when using GCC. + * Doing so may save a few bytes in binary size. + */ +#ifndef noinline_for_stack +# ifdef __GNUC__ +# define noinline_for_stack __attribute__((__noinline__)) +# else +# define noinline_for_stack +# endif +#endif + +/* Inline functions to access unaligned unsigned 32-bit integers */ +static inline uint32_t get_unaligned_le32(const uint8_t *buf) +{ + return (uint32_t)buf[0] + | ((uint32_t)buf[1] << 8) + | ((uint32_t)buf[2] << 16) + | ((uint32_t)buf[3] << 24); +} + +static inline uint32_t get_unaligned_be32(const uint8_t *buf) +{ + return (uint32_t)(buf[0] << 24) + | ((uint32_t)buf[1] << 16) + | ((uint32_t)buf[2] << 8) + | (uint32_t)buf[3]; +} + +static inline void put_unaligned_le32(uint32_t val, uint8_t *buf) +{ + buf[0] = (uint8_t)val; + buf[1] = (uint8_t)(val >> 8); + buf[2] = (uint8_t)(val >> 16); + buf[3] = (uint8_t)(val >> 24); +} + +static inline void put_unaligned_be32(uint32_t val, uint8_t *buf) +{ + buf[0] = (uint8_t)(val >> 24); + buf[1] = (uint8_t)(val >> 16); + buf[2] = (uint8_t)(val >> 8); + buf[3] = (uint8_t)val; +} + +/* + * Use get_unaligned_le32() also for aligned access for simplicity. On + * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr)) + * could save a few bytes in code size. + */ +#define get_le32 get_unaligned_le32 + +#endif diff --git a/grub-core/lib/xzembed/xz_dec_bcj.c b/grub-core/lib/xzembed/xz_dec_bcj.c new file mode 100644 index 000000000..7eec9de7d --- /dev/null +++ b/grub-core/lib/xzembed/xz_dec_bcj.c @@ -0,0 +1,569 @@ +/* xz_dec_bcj.c - Branch/Call/Jump (BCJ) filter decoders */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#include "xz_private.h" + +struct xz_dec_bcj { + /* Type of the BCJ filter being used */ + enum { + BCJ_X86 = 4, /* x86 or x86-64 */ + BCJ_POWERPC = 5, /* Big endian only */ + BCJ_IA64 = 6, /* Big or little endian */ + BCJ_ARM = 7, /* Little endian only */ + BCJ_ARMTHUMB = 8, /* Little endian only */ + BCJ_SPARC = 9 /* Big or little endian */ + } type; + + /* + * Return value of the next filter in the chain. We need to preserve + * this information across calls, because we must not call the next + * filter anymore once it has returned XZ_STREAM_END. + */ + enum xz_ret ret; + + /* True if we are operating in single-call mode. */ + bool single_call; + + /* + * Absolute position relative to the beginning of the uncompressed + * data (in a single .xz Block). We care only about the lowest 32 + * bits so this doesn't need to be uint64_t even with big files. + */ + uint32_t pos; + + /* x86 filter state */ + uint32_t x86_prev_mask; + + /* Temporary space to hold the variables from struct xz_buf */ + uint8_t *out; + size_t out_pos; + size_t out_size; + + struct { + /* Amount of already filtered data in the beginning of buf */ + size_t filtered; + + /* Total amount of data currently stored in buf */ + size_t size; + + /* + * Buffer to hold a mix of filtered and unfiltered data. This + * needs to be big enough to hold Alignment + 2 * Look-ahead: + * + * Type Alignment Look-ahead + * x86 1 4 + * PowerPC 4 0 + * IA-64 16 0 + * ARM 4 0 + * ARM-Thumb 2 2 + * SPARC 4 0 + */ + uint8_t buf[16]; + } temp; +}; + +#ifdef XZ_DEC_X86 +/* + * This is macro used to test the most significant byte of a memory address + * in an x86 instruction. + */ +#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF) + +static noinline_for_stack size_t bcj_x86( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + static const bool mask_to_allowed_status[8] + = { true, true, true, false, true, false, false, false }; + + static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 }; + + size_t i; + size_t prev_pos = (size_t)-1; + uint32_t prev_mask = s->x86_prev_mask; + uint32_t src; + uint32_t dest; + uint32_t j; + uint8_t b; + + if (size <= 4) + return 0; + + size -= 4; + for (i = 0; i < size; ++i) { + if ((buf[i] & 0xFE) != 0xE8) + continue; + + prev_pos = i - prev_pos; + if (prev_pos > 3) { + prev_mask = 0; + } else { + prev_mask = (prev_mask << (prev_pos - 1)) & 7; + if (prev_mask != 0) { + b = buf[i + 4 - mask_to_bit_num[prev_mask]]; + if (!mask_to_allowed_status[prev_mask] + || bcj_x86_test_msbyte(b)) { + prev_pos = i; + prev_mask = (prev_mask << 1) | 1; + continue; + } + } + } + + prev_pos = i; + + if (bcj_x86_test_msbyte(buf[i + 4])) { + src = get_unaligned_le32(buf + i + 1); + while (true) { + dest = src - (s->pos + (uint32_t)i + 5); + if (prev_mask == 0) + break; + + j = mask_to_bit_num[prev_mask] * 8; + b = (uint8_t)(dest >> (24 - j)); + if (!bcj_x86_test_msbyte(b)) + break; + + src = dest ^ (((uint32_t)1 << (32 - j)) - 1); + } + + dest &= 0x01FFFFFF; + dest |= (uint32_t)0 - (dest & 0x01000000); + put_unaligned_le32(dest, buf + i + 1); + i += 4; + } else { + prev_mask = (prev_mask << 1) | 1; + } + } + + prev_pos = i - prev_pos; + s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1); + return i; +} +#endif + +#ifdef XZ_DEC_POWERPC +static noinline_for_stack size_t bcj_powerpc( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = get_unaligned_be32(buf + i); + if ((instr & 0xFC000003) == 0x48000001) { + instr &= 0x03FFFFFC; + instr -= s->pos + (uint32_t)i; + instr &= 0x03FFFFFC; + instr |= 0x48000001; + put_unaligned_be32(instr, buf + i); + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_IA64 +static noinline_for_stack size_t bcj_ia64( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + static const uint8_t branch_table[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, + 4, 4, 0, 0, 4, 4, 0, 0 + }; + + /* + * The local variables take a little bit stack space, but it's less + * than what LZMA2 decoder takes, so it doesn't make sense to reduce + * stack usage here without doing that for the LZMA2 decoder too. + */ + + /* Loop counters */ + size_t i; + size_t j; + + /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */ + uint32_t slot; + + /* Bitwise offset of the instruction indicated by slot */ + uint32_t bit_pos; + + /* bit_pos split into byte and bit parts */ + uint32_t byte_pos; + uint32_t bit_res; + + /* Address part of an instruction */ + uint32_t addr; + + /* Mask used to detect which instructions to convert */ + uint32_t mask; + + /* 41-bit instruction stored somewhere in the lowest 48 bits */ + uint64_t instr; + + /* Instruction normalized with bit_res for easier manipulation */ + uint64_t norm; + + for (i = 0; i + 16 <= size; i += 16) { + mask = branch_table[buf[i] & 0x1F]; + for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) { + if (((mask >> slot) & 1) == 0) + continue; + + byte_pos = bit_pos >> 3; + bit_res = bit_pos & 7; + instr = 0; + for (j = 0; j < 6; ++j) + instr |= (uint64_t)(buf[i + j + byte_pos]) + << (8 * j); + + norm = instr >> bit_res; + + if (((norm >> 37) & 0x0F) == 0x05 + && ((norm >> 9) & 0x07) == 0) { + addr = (norm >> 13) & 0x0FFFFF; + addr |= ((uint32_t)(norm >> 36) & 1) << 20; + addr <<= 4; + addr -= s->pos + (uint32_t)i; + addr >>= 4; + + norm &= ~((uint64_t)0x8FFFFF << 13); + norm |= (uint64_t)(addr & 0x0FFFFF) << 13; + norm |= (uint64_t)(addr & 0x100000) + << (36 - 20); + + instr &= (1 << bit_res) - 1; + instr |= norm << bit_res; + + for (j = 0; j < 6; j++) + buf[i + j + byte_pos] + = (uint8_t)(instr >> (8 * j)); + } + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_ARM +static noinline_for_stack size_t bcj_arm( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 4) { + if (buf[i + 3] == 0xEB) { + addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) + | ((uint32_t)buf[i + 2] << 16); + addr <<= 2; + addr -= s->pos + (uint32_t)i + 8; + addr >>= 2; + buf[i] = (uint8_t)addr; + buf[i + 1] = (uint8_t)(addr >> 8); + buf[i + 2] = (uint8_t)(addr >> 16); + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_ARMTHUMB +static noinline_for_stack size_t bcj_armthumb( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 2) { + if ((buf[i + 1] & 0xF8) == 0xF0 + && (buf[i + 3] & 0xF8) == 0xF8) { + addr = (((uint32_t)buf[i + 1] & 0x07) << 19) + | ((uint32_t)buf[i] << 11) + | (((uint32_t)buf[i + 3] & 0x07) << 8) + | (uint32_t)buf[i + 2]; + addr <<= 1; + addr -= s->pos + (uint32_t)i + 4; + addr >>= 1; + buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07)); + buf[i] = (uint8_t)(addr >> 11); + buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07)); + buf[i + 2] = (uint8_t)addr; + i += 2; + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_SPARC +static noinline_for_stack size_t bcj_sparc( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = get_unaligned_be32(buf + i); + if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) { + instr <<= 2; + instr -= s->pos + (uint32_t)i; + instr >>= 2; + instr = ((uint32_t)0x40000000 - (instr & 0x400000)) + | 0x40000000 | (instr & 0x3FFFFF); + put_unaligned_be32(instr, buf + i); + } + } + + return i; +} +#endif + +/* + * Apply the selected BCJ filter. Update *pos and s->pos to match the amount + * of data that got filtered. + * + * NOTE: This is implemented as a switch statement to avoid using function + * pointers, which could be problematic in the kernel boot code, which must + * avoid pointers to static data (at least on x86). + */ +static void bcj_apply(struct xz_dec_bcj *s, + uint8_t *buf, size_t *pos, size_t size) +{ + size_t filtered; + + buf += *pos; + size -= *pos; + + switch (s->type) { +#ifdef XZ_DEC_X86 + case BCJ_X86: + filtered = bcj_x86(s, buf, size); + break; +#endif +#ifdef XZ_DEC_POWERPC + case BCJ_POWERPC: + filtered = bcj_powerpc(s, buf, size); + break; +#endif +#ifdef XZ_DEC_IA64 + case BCJ_IA64: + filtered = bcj_ia64(s, buf, size); + break; +#endif +#ifdef XZ_DEC_ARM + case BCJ_ARM: + filtered = bcj_arm(s, buf, size); + break; +#endif +#ifdef XZ_DEC_ARMTHUMB + case BCJ_ARMTHUMB: + filtered = bcj_armthumb(s, buf, size); + break; +#endif +#ifdef XZ_DEC_SPARC + case BCJ_SPARC: + filtered = bcj_sparc(s, buf, size); + break; +#endif + default: + /* Never reached but silence compiler warnings. */ + filtered = 0; + break; + } + + *pos += filtered; + s->pos += filtered; +} + +/* + * Flush pending filtered data from temp to the output buffer. + * Move the remaining mixture of possibly filtered and unfiltered + * data to the beginning of temp. + */ +static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b) +{ + size_t copy_size; + + copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos); + memcpy(b->out + b->out_pos, s->temp.buf, copy_size); + b->out_pos += copy_size; + + s->temp.filtered -= copy_size; + s->temp.size -= copy_size; + memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size); +} + +/* + * The BCJ filter functions are primitive in sense that they process the + * data in chunks of 1-16 bytes. To hide this issue, this function does + * some buffering. + */ +enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, + struct xz_dec_lzma2 *lzma2, struct xz_buf *b) +{ + size_t out_start; + + /* + * Flush pending already filtered data to the output buffer. Return + * immediatelly if we couldn't flush everything, or if the next + * filter in the chain had already returned XZ_STREAM_END. + */ + if (s->temp.filtered > 0) { + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + } + + /* + * If we have more output space than what is currently pending in + * temp, copy the unfiltered data from temp to the output buffer + * and try to fill the output buffer by decoding more data from the + * next filter in the chain. Apply the BCJ filter on the new data + * in the output buffer. If everything cannot be filtered, copy it + * to temp and rewind the output buffer position accordingly. + */ + if (s->temp.size < b->out_size - b->out_pos) { + out_start = b->out_pos; + memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); + b->out_pos += s->temp.size; + + s->ret = xz_dec_lzma2_run(lzma2, b); + if (s->ret != XZ_STREAM_END + && (s->ret != XZ_OK || s->single_call)) + return s->ret; + + bcj_apply(s, b->out, &out_start, b->out_pos); + + /* + * As an exception, if the next filter returned XZ_STREAM_END, + * we can do that too, since the last few bytes that remain + * unfiltered are meant to remain unfiltered. + */ + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + + s->temp.size = b->out_pos - out_start; + b->out_pos -= s->temp.size; + memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); + } + + /* + * If we have unfiltered data in temp, try to fill by decoding more + * data from the next filter. Apply the BCJ filter on temp. Then we + * hopefully can fill the actual output buffer by copying filtered + * data from temp. A mix of filtered and unfiltered data may be left + * in temp; it will be taken care on the next call to this function. + */ + if (s->temp.size > 0) { + /* Make b->out{,_pos,_size} temporarily point to s->temp. */ + s->out = b->out; + s->out_pos = b->out_pos; + s->out_size = b->out_size; + b->out = s->temp.buf; + b->out_pos = s->temp.size; + b->out_size = sizeof(s->temp.buf); + + s->ret = xz_dec_lzma2_run(lzma2, b); + + s->temp.size = b->out_pos; + b->out = s->out; + b->out_pos = s->out_pos; + b->out_size = s->out_size; + + if (s->ret != XZ_OK && s->ret != XZ_STREAM_END) + return s->ret; + + bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size); + + /* + * If the next filter returned XZ_STREAM_END, we mark that + * everything is filtered, since the last unfiltered bytes + * of the stream are meant to be left as is. + */ + if (s->ret == XZ_STREAM_END) + s->temp.filtered = s->temp.size; + + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + } + + return s->ret; +} + +struct xz_dec_bcj * xz_dec_bcj_create(bool single_call) +{ + struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s != NULL) + s->single_call = single_call; + + return s; +} + +enum xz_ret xz_dec_bcj_reset( + struct xz_dec_bcj *s, uint8_t id) +{ + switch (id) { +#ifdef XZ_DEC_X86 + case BCJ_X86: +#endif +#ifdef XZ_DEC_POWERPC + case BCJ_POWERPC: +#endif +#ifdef XZ_DEC_IA64 + case BCJ_IA64: +#endif +#ifdef XZ_DEC_ARM + case BCJ_ARM: +#endif +#ifdef XZ_DEC_ARMTHUMB + case BCJ_ARMTHUMB: +#endif +#ifdef XZ_DEC_SPARC + case BCJ_SPARC: +#endif + break; + + default: + /* Unsupported Filter ID */ + return XZ_OPTIONS_ERROR; + } + + s->type = id; + s->ret = XZ_OK; + s->pos = 0; + s->x86_prev_mask = 0; + s->temp.filtered = 0; + s->temp.size = 0; + + return XZ_OK; +} diff --git a/grub-core/lib/xzembed/xz_dec_lzma2.c b/grub-core/lib/xzembed/xz_dec_lzma2.c new file mode 100644 index 000000000..a0d422697 --- /dev/null +++ b/grub-core/lib/xzembed/xz_dec_lzma2.c @@ -0,0 +1,1168 @@ +/* xz_dec_lzma2.c - LZMA2 decoder */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#include "xz_private.h" +#include "xz_lzma2.h" + +/* + * Range decoder initialization eats the first five bytes of each LZMA chunk. + */ +#define RC_INIT_BYTES 5 + +/* + * Minimum number of usable input buffer to safely decode one LZMA symbol. + * The worst case is that we decode 22 bits using probabilities and 26 + * direct bits. This may decode at maximum of 20 bytes of input. However, + * lzma_main() does an extra normalization before returning, thus we + * need to put 21 here. + */ +#define LZMA_IN_REQUIRED 21 + +/* + * Dictionary (history buffer) + * + * These are always true: + * start <= pos <= full <= end + * pos <= limit <= end + * + * In multi-call mode, also these are true: + * end == size + * size <= allocated + * + * Most of these variables are size_t to support single-call mode, + * in which the dictionary variables address the actual output + * buffer directly. + */ +struct dictionary { + /* Beginning of the history buffer */ + uint8_t *buf; + + /* Old position in buf (before decoding more data) */ + size_t start; + + /* Position in buf */ + size_t pos; + + /* + * How full dictionary is. This is used to detect corrupt input that + * would read beyond the beginning of the uncompressed stream. + */ + size_t full; + + /* Write limit; we don't write to buf[limit] or later bytes. */ + size_t limit; + + /* + * End of the dictionary buffer. In multi-call mode, this is + * the same as the dictionary size. In single-call mode, this + * indicates the size of the output buffer. + */ + size_t end; + + /* + * Size of the dictionary as specified in Block Header. This is used + * together with "full" to detect corrupt input that would make us + * read beyond the beginning of the uncompressed stream. + */ + uint32_t size; + + /* + * Amount of memory allocated for the dictionary. A special + * value of zero indicates that we are in single-call mode, + * where the output buffer works as the dictionary. + */ + uint32_t allocated; +}; + +/* Range decoder */ +struct rc_dec { + uint32_t range; + uint32_t code; + + /* + * Number of initializing bytes remaining to be read + * by rc_read_init(). + */ + uint32_t init_bytes_left; + + /* + * Buffer from which we read our input. It can be either + * temp.buf or the caller-provided input buffer. + */ + const uint8_t *in; + size_t in_pos; + size_t in_limit; +}; + +/* Probabilities for a length decoder. */ +struct lzma_len_dec { + /* Probability of match length being at least 10 */ + uint16_t choice; + + /* Probability of match length being at least 18 */ + uint16_t choice2; + + /* Probabilities for match lengths 2-9 */ + uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS]; + + /* Probabilities for match lengths 10-17 */ + uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS]; + + /* Probabilities for match lengths 18-273 */ + uint16_t high[LEN_HIGH_SYMBOLS]; +}; + +struct lzma_dec { + /* + * LZMA properties or related bit masks (number of literal + * context bits, a mask dervied from the number of literal + * position bits, and a mask dervied from the number + * position bits) + */ + uint32_t lc; + uint32_t literal_pos_mask; /* (1 << lp) - 1 */ + uint32_t pos_mask; /* (1 << pb) - 1 */ + + /* Types of the most recently seen LZMA symbols */ + enum lzma_state state; + + /* Distances of latest four matches */ + uint32_t rep0; + uint32_t rep1; + uint32_t rep2; + uint32_t rep3; + + /* + * Length of a match. This is updated so that dict_repeat can + * be called again to finish repeating the whole match. + */ + uint32_t len; + + /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ + uint16_t is_match[STATES][POS_STATES_MAX]; + + /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ + uint16_t is_rep[STATES]; + + /* + * If 0, distance of a repeated match is rep0. + * Otherwise check is_rep1. + */ + uint16_t is_rep0[STATES]; + + /* + * If 0, distance of a repeated match is rep1. + * Otherwise check is_rep2. + */ + uint16_t is_rep1[STATES]; + + /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ + uint16_t is_rep2[STATES]; + + /* + * If 1, the repeated match has length of one byte. Otherwise + * the length is decoded from rep_len_decoder. + */ + uint16_t is_rep0_long[STATES][POS_STATES_MAX]; + + /* + * Probability tree for the highest two bits of the match + * distance. There is a separate probability tree for match + * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. + */ + uint16_t dist_slot[DIST_STATES][DIST_SLOTS]; + + /* + * Probility trees for additional bits for match distance + * when the distance is in the range [4, 127]. + */ + uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END]; + + /* + * Probability tree for the lowest four bits of a match + * distance that is equal to or greater than 128. + */ + uint16_t dist_align[ALIGN_SIZE]; + + /* Length of a normal match */ + struct lzma_len_dec match_len_dec; + + /* Length of a repeated match */ + struct lzma_len_dec rep_len_dec; + + /* Probabilities of literals */ + uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; +}; + +struct xz_dec_lzma2 { + /* LZMA2 */ + struct { + /* Position in xz_dec_lzma2_run(). */ + enum lzma2_seq { + SEQ_CONTROL, + SEQ_UNCOMPRESSED_1, + SEQ_UNCOMPRESSED_2, + SEQ_COMPRESSED_0, + SEQ_COMPRESSED_1, + SEQ_PROPERTIES, + SEQ_LZMA_PREPARE, + SEQ_LZMA_RUN, + SEQ_COPY + } sequence; + + /* + * Next position after decoding the compressed size of + * the chunk. + */ + enum lzma2_seq next_sequence; + + /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ + uint32_t uncompressed; + + /* + * Compressed size of LZMA chunk or compressed/uncompressed + * size of uncompressed chunk (64 KiB at maximum) + */ + uint32_t compressed; + + /* + * True if dictionary reset is needed. This is false before + * the first chunk (LZMA or uncompressed). + */ + bool need_dict_reset; + + /* + * True if new LZMA properties are needed. This is false + * before the first LZMA chunk. + */ + bool need_props; + } lzma2; + + /* + * Temporary buffer which holds small number of input bytes between + * decoder calls. See lzma2_lzma() for details. + */ + struct { + uint32_t size; + uint8_t buf[3 * LZMA_IN_REQUIRED]; + } temp; + + struct dictionary dict; + struct rc_dec rc; + struct lzma_dec lzma; +}; + +/************** + * Dictionary * + **************/ + +/* + * Reset the dictionary state. When in single-call mode, set up the beginning + * of the dictionary to point to the actual output buffer. + */ +static void dict_reset(struct dictionary *dict, struct xz_buf *b) +{ + if (dict->allocated == 0) { + dict->buf = b->out + b->out_pos; + dict->end = b->out_size - b->out_pos; + } + dict->start = 0; + dict->pos = 0; + dict->limit = 0; + dict->full = 0; +} + +/* Set dictionary write limit */ +static void dict_limit(struct dictionary *dict, size_t out_max) +{ + if (dict->end - dict->pos <= out_max) + dict->limit = dict->end; + else + dict->limit = dict->pos + out_max; +} + +/* Return true if at least one byte can be written into the dictionary. */ +static inline bool dict_has_space(const struct dictionary *dict) +{ + return dict->pos < dict->limit; +} + +/* + * Get a byte from the dictionary at the given distance. The distance is + * assumed to valid, or as a special case, zero when the dictionary is + * still empty. This special case is needed for single-call decoding to + * avoid writing a '\0' to the end of the destination buffer. + */ +static inline uint32_t dict_get( + const struct dictionary *dict, uint32_t dist) +{ + size_t offset = dict->pos - dist - 1; + + if (dist >= dict->pos) + offset += dict->end; + + return dict->full > 0 ? dict->buf[offset] : 0; +} + +/* + * Put one byte into the dictionary. It is assumed that there is space for it. + */ +static inline void dict_put(struct dictionary *dict, uint8_t byte) +{ + dict->buf[dict->pos++] = byte; + + if (dict->full < dict->pos) + dict->full = dict->pos; +} + +/* + * Repeat given number of bytes from the given distance. If the distance is + * invalid, false is returned. On success, true is returned and *len is + * updated to indicate how many bytes were left to be repeated. + */ +static bool dict_repeat( + struct dictionary *dict, uint32_t *len, uint32_t dist) +{ + size_t back; + uint32_t left; + + if (dist >= dict->full || dist >= dict->size) + return false; + + left = min_t(size_t, dict->limit - dict->pos, *len); + *len -= left; + + back = dict->pos - dist - 1; + if (dist >= dict->pos) + back += dict->end; + + do { + dict->buf[dict->pos++] = dict->buf[back++]; + if (back == dict->end) + back = 0; + } while (--left > 0); + + if (dict->full < dict->pos) + dict->full = dict->pos; + + return true; +} + +/* Copy uncompressed data as is from input to dictionary and output buffers. */ +static void dict_uncompressed( + struct dictionary *dict, struct xz_buf *b, uint32_t *left) +{ + size_t copy_size; + + while (*left > 0 && b->in_pos < b->in_size + && b->out_pos < b->out_size) { + copy_size = min(b->in_size - b->in_pos, + b->out_size - b->out_pos); + if (copy_size > dict->end - dict->pos) + copy_size = dict->end - dict->pos; + if (copy_size > *left) + copy_size = *left; + + *left -= copy_size; + + memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); + dict->pos += copy_size; + + if (dict->full < dict->pos) + dict->full = dict->pos; + + if (dict->allocated != 0) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, b->in + b->in_pos, + copy_size); + } + + dict->start = dict->pos; + + b->out_pos += copy_size; + b->in_pos += copy_size; + + } +} + +/* + * Flush pending data from dictionary to b->out. It is assumed that there is + * enough space in b->out. This is guaranteed because caller uses dict_limit() + * before decoding data into the dictionary. + */ +static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b) +{ + size_t copy_size = dict->pos - dict->start; + + if (dict->allocated != 0) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, dict->buf + dict->start, + copy_size); + } + + dict->start = dict->pos; + b->out_pos += copy_size; + return copy_size; +} + +/***************** + * Range decoder * + *****************/ + +/* Reset the range decoder. */ +static void rc_reset(struct rc_dec *rc) +{ + rc->range = (uint32_t)-1; + rc->code = 0; + rc->init_bytes_left = RC_INIT_BYTES; +} + +/* + * Read the first five initial bytes into rc->code if they haven't been + * read already. (Yes, the first byte gets completely ignored.) + */ +static bool rc_read_init(struct rc_dec *rc, struct xz_buf *b) +{ + while (rc->init_bytes_left > 0) { + if (b->in_pos == b->in_size) + return false; + + rc->code = (rc->code << 8) + b->in[b->in_pos++]; + --rc->init_bytes_left; + } + + return true; +} + +/* Return true if there may not be enough input for the next decoding loop. */ +static inline bool rc_limit_exceeded(const struct rc_dec *rc) +{ + return rc->in_pos > rc->in_limit; +} + +/* + * Return true if it is possible (from point of view of range decoder) that + * we have reached the end of the LZMA chunk. + */ +static inline bool rc_is_finished(const struct rc_dec *rc) +{ + return rc->code == 0; +} + +/* Read the next input byte if needed. */ +static __always_inline void rc_normalize(struct rc_dec *rc) +{ + if (rc->range < RC_TOP_VALUE) { + rc->range <<= RC_SHIFT_BITS; + rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++]; + } +} + +/* + * Decode one bit. In some versions, this function has been splitted in three + * functions so that the compiler is supposed to be able to more easily avoid + * an extra branch. In this particular version of the LZMA decoder, this + * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3 + * on x86). Using a non-splitted version results in nicer looking code too. + * + * NOTE: This must return an int. Do not make it return a bool or the speed + * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, + * and it generates 10-20 % faster code than GCC 3.x from this file anyway.) + */ +static __always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob) +{ + uint32_t bound; + int bit; + + rc_normalize(rc); + bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob; + if (rc->code < bound) { + rc->range = bound; + *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS; + bit = 0; + } else { + rc->range -= bound; + rc->code -= bound; + *prob -= *prob >> RC_MOVE_BITS; + bit = 1; + } + + return bit; +} + +/* Decode a bittree starting from the most significant bit. */ +static __always_inline uint32_t rc_bittree( + struct rc_dec *rc, uint16_t *probs, uint32_t limit) +{ + uint32_t symbol = 1; + + do { + if (rc_bit(rc, &probs[symbol])) + symbol = (symbol << 1) + 1; + else + symbol <<= 1; + } while (symbol < limit); + + return symbol; +} + +/* Decode a bittree starting from the least significant bit. */ +static __always_inline void rc_bittree_reverse(struct rc_dec *rc, + uint16_t *probs, uint32_t *dest, uint32_t limit) +{ + uint32_t symbol = 1; + uint32_t i = 0; + + do { + if (rc_bit(rc, &probs[symbol])) { + symbol = (symbol << 1) + 1; + *dest += 1 << i; + } else { + symbol <<= 1; + } + } while (++i < limit); +} + +/* Decode direct bits (fixed fifty-fifty probability) */ +static inline void rc_direct( + struct rc_dec *rc, uint32_t *dest, uint32_t limit) +{ + uint32_t mask; + + do { + rc_normalize(rc); + rc->range >>= 1; + rc->code -= rc->range; + mask = (uint32_t)0 - (rc->code >> 31); + rc->code += rc->range & mask; + *dest = (*dest << 1) + (mask + 1); + } while (--limit > 0); +} + +/******** + * LZMA * + ********/ + +/* Get pointer to literal coder probability array. */ +static uint16_t * lzma_literal_probs(struct xz_dec_lzma2 *s) +{ + uint32_t prev_byte = dict_get(&s->dict, 0); + uint32_t low = prev_byte >> (8 - s->lzma.lc); + uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc; + return s->lzma.literal[low + high]; +} + +/* Decode a literal (one 8-bit byte) */ +static void lzma_literal(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + uint32_t symbol; + uint32_t match_byte; + uint32_t match_bit; + uint32_t offset; + uint32_t i; + + probs = lzma_literal_probs(s); + + if (lzma_state_is_literal(s->lzma.state)) { + symbol = rc_bittree(&s->rc, probs, 0x100); + } else { + symbol = 1; + match_byte = dict_get(&s->dict, s->lzma.rep0) << 1; + offset = 0x100; + + do { + match_bit = match_byte & offset; + match_byte <<= 1; + i = offset + match_bit + symbol; + + if (rc_bit(&s->rc, &probs[i])) { + symbol = (symbol << 1) + 1; + offset &= match_bit; + } else { + symbol <<= 1; + offset &= ~match_bit; + } + } while (symbol < 0x100); + } + + dict_put(&s->dict, (uint8_t)symbol); + lzma_state_literal(&s->lzma.state); +} + +/* Decode the length of the match into s->lzma.len. */ +static void lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l, + uint32_t pos_state) +{ + uint16_t *probs; + uint32_t limit; + + if (!rc_bit(&s->rc, &l->choice)) { + probs = l->low[pos_state]; + limit = LEN_LOW_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN; + } else { + if (!rc_bit(&s->rc, &l->choice2)) { + probs = l->mid[pos_state]; + limit = LEN_MID_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; + } else { + probs = l->high; + limit = LEN_HIGH_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS + + LEN_MID_SYMBOLS; + } + } + + s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit; +} + +/* Decode a match. The distance will be stored in s->lzma.rep0. */ +static void lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint16_t *probs; + uint32_t dist_slot; + uint32_t limit; + + lzma_state_match(&s->lzma.state); + + s->lzma.rep3 = s->lzma.rep2; + s->lzma.rep2 = s->lzma.rep1; + s->lzma.rep1 = s->lzma.rep0; + + lzma_len(s, &s->lzma.match_len_dec, pos_state); + + probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)]; + dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS; + + if (dist_slot < DIST_MODEL_START) { + s->lzma.rep0 = dist_slot; + } else { + limit = (dist_slot >> 1) - 1; + s->lzma.rep0 = 2 + (dist_slot & 1); + + if (dist_slot < DIST_MODEL_END) { + s->lzma.rep0 <<= limit; + probs = s->lzma.dist_special + s->lzma.rep0 + - dist_slot - 1; + rc_bittree_reverse(&s->rc, probs, + &s->lzma.rep0, limit); + } else { + rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS); + s->lzma.rep0 <<= ALIGN_BITS; + rc_bittree_reverse(&s->rc, s->lzma.dist_align, + &s->lzma.rep0, ALIGN_BITS); + } + } +} + +/* + * Decode a repeated match. The distance is one of the four most recently + * seen matches. The distance will be stored in s->lzma.rep0. + */ +static void lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint32_t tmp; + + if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) { + if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[ + s->lzma.state][pos_state])) { + lzma_state_short_rep(&s->lzma.state); + s->lzma.len = 1; + return; + } + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) { + tmp = s->lzma.rep1; + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) { + tmp = s->lzma.rep2; + } else { + tmp = s->lzma.rep3; + s->lzma.rep3 = s->lzma.rep2; + } + + s->lzma.rep2 = s->lzma.rep1; + } + + s->lzma.rep1 = s->lzma.rep0; + s->lzma.rep0 = tmp; + } + + lzma_state_long_rep(&s->lzma.state); + lzma_len(s, &s->lzma.rep_len_dec, pos_state); +} + +/* LZMA decoder core */ +static bool lzma_main(struct xz_dec_lzma2 *s) +{ + uint32_t pos_state; + + /* + * If the dictionary was reached during the previous call, try to + * finish the possibly pending repeat in the dictionary. + */ + if (dict_has_space(&s->dict) && s->lzma.len > 0) + dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0); + + /* + * Decode more LZMA symbols. One iteration may consume up to + * LZMA_IN_REQUIRED - 1 bytes. + */ + while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) { + pos_state = s->dict.pos & s->lzma.pos_mask; + + if (!rc_bit(&s->rc, &s->lzma.is_match[ + s->lzma.state][pos_state])) { + lzma_literal(s); + } else { + if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state])) + lzma_rep_match(s, pos_state); + else + lzma_match(s, pos_state); + + if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0)) + return false; + } + } + + /* + * Having the range decoder always normalized when we are outside + * this function makes it easier to correctly handle end of the chunk. + */ + rc_normalize(&s->rc); + + return true; +} + +/* + * Reset the LZMA decoder and range decoder state. Dictionary is nore reset + * here, because LZMA state may be reset without resetting the dictionary. + */ +static void lzma_reset(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + size_t i; + + s->lzma.state = STATE_LIT_LIT; + s->lzma.rep0 = 0; + s->lzma.rep1 = 0; + s->lzma.rep2 = 0; + s->lzma.rep3 = 0; + + /* + * All probabilities are initialized to the same value. This hack + * makes the code smaller by avoiding a separate loop for each + * probability array. + * + * This could be optimized so that only that part of literal + * probabilities that are actually required. In the common case + * we would write 12 KiB less. + */ + probs = s->lzma.is_match[0]; + for (i = 0; i < PROBS_TOTAL; ++i) + probs[i] = RC_BIT_MODEL_TOTAL / 2; + + rc_reset(&s->rc); +} + +/* + * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks + * from the decoded lp and pb values. On success, the LZMA decoder state is + * reset and true is returned. + */ +static bool lzma_props(struct xz_dec_lzma2 *s, uint8_t props) +{ + if (props > (4 * 5 + 4) * 9 + 8) + return false; + + s->lzma.pos_mask = 0; + while (props >= 9 * 5) { + props -= 9 * 5; + ++s->lzma.pos_mask; + } + + s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1; + + s->lzma.literal_pos_mask = 0; + while (props >= 9) { + props -= 9; + ++s->lzma.literal_pos_mask; + } + + s->lzma.lc = props; + + if (s->lzma.lc + s->lzma.literal_pos_mask > 4) + return false; + + s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1; + + lzma_reset(s); + + return true; +} + +/********* + * LZMA2 * + *********/ + +/* + * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't + * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This + * wrapper function takes care of making the LZMA decoder's assumption safe. + * + * As long as there is plenty of input left to be decoded in the current LZMA + * chunk, we decode directly from the caller-supplied input buffer until + * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into + * s->temp.buf, which (hopefully) gets filled on the next call to this + * function. We decode a few bytes from the temporary buffer so that we can + * continue decoding from the caller-supplied input buffer again. + */ +static bool lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b) +{ + size_t in_avail; + uint32_t tmp; + + in_avail = b->in_size - b->in_pos; + if (s->temp.size > 0 || s->lzma2.compressed == 0) { + tmp = 2 * LZMA_IN_REQUIRED - s->temp.size; + if (tmp > s->lzma2.compressed - s->temp.size) + tmp = s->lzma2.compressed - s->temp.size; + if (tmp > in_avail) + tmp = in_avail; + + memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp); + + if (s->temp.size + tmp == s->lzma2.compressed) { + memzero(s->temp.buf + s->temp.size + tmp, + sizeof(s->temp.buf) + - s->temp.size - tmp); + s->rc.in_limit = s->temp.size + tmp; + } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) { + s->temp.size += tmp; + b->in_pos += tmp; + return true; + } else { + s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED; + } + + s->rc.in = s->temp.buf; + s->rc.in_pos = 0; + + if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp) + return false; + + s->lzma2.compressed -= s->rc.in_pos; + + if (s->rc.in_pos < s->temp.size) { + s->temp.size -= s->rc.in_pos; + memmove(s->temp.buf, s->temp.buf + s->rc.in_pos, + s->temp.size); + return true; + } + + b->in_pos += s->rc.in_pos - s->temp.size; + s->temp.size = 0; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail >= LZMA_IN_REQUIRED) { + s->rc.in = b->in; + s->rc.in_pos = b->in_pos; + + if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED) + s->rc.in_limit = b->in_pos + s->lzma2.compressed; + else + s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED; + + if (!lzma_main(s)) + return false; + + in_avail = s->rc.in_pos - b->in_pos; + if (in_avail > s->lzma2.compressed) + return false; + + s->lzma2.compressed -= in_avail; + b->in_pos = s->rc.in_pos; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail < LZMA_IN_REQUIRED) { + if (in_avail > s->lzma2.compressed) + in_avail = s->lzma2.compressed; + + memcpy(s->temp.buf, b->in + b->in_pos, in_avail); + s->temp.size = in_avail; + b->in_pos += in_avail; + } + + return true; +} + +/* + * Take care of the LZMA2 control layer, and forward the job of actual LZMA + * decoding or copying of uncompressed chunks to other functions. + */ +enum xz_ret xz_dec_lzma2_run( + struct xz_dec_lzma2 *s, struct xz_buf *b) +{ + uint32_t tmp; + + while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) { + switch (s->lzma2.sequence) { + case SEQ_CONTROL: + /* + * LZMA2 control byte + * + * Exact values: + * 0x00 End marker + * 0x01 Dictionary reset followed by + * an uncompressed chunk + * 0x02 Uncompressed chunk (no dictionary reset) + * + * Highest three bits (s->control & 0xE0): + * 0xE0 Dictionary reset, new properties and state + * reset, followed by LZMA compressed chunk + * 0xC0 New properties and state reset, followed + * by LZMA compressed chunk (no dictionary + * reset) + * 0xA0 State reset using old properties, + * followed by LZMA compressed chunk (no + * dictionary reset) + * 0x80 LZMA chunk (no dictionary or state reset) + * + * For LZMA compressed chunks, the lowest five bits + * (s->control & 1F) are the highest bits of the + * uncompressed size (bits 16-20). + * + * A new LZMA2 stream must begin with a dictionary + * reset. The first LZMA chunk must set new + * properties and reset the LZMA state. + * + * Values that don't match anything described above + * are invalid and we return XZ_DATA_ERROR. + */ + tmp = b->in[b->in_pos++]; + + if (tmp >= 0xE0 || tmp == 0x01) { + s->lzma2.need_props = true; + s->lzma2.need_dict_reset = false; + dict_reset(&s->dict, b); + } else if (s->lzma2.need_dict_reset) { + return XZ_DATA_ERROR; + } + + if (tmp >= 0x80) { + s->lzma2.uncompressed = (tmp & 0x1F) << 16; + s->lzma2.sequence = SEQ_UNCOMPRESSED_1; + + if (tmp >= 0xC0) { + /* + * When there are new properties, + * state reset is done at + * SEQ_PROPERTIES. + */ + s->lzma2.need_props = false; + s->lzma2.next_sequence + = SEQ_PROPERTIES; + + } else if (s->lzma2.need_props) { + return XZ_DATA_ERROR; + + } else { + s->lzma2.next_sequence + = SEQ_LZMA_PREPARE; + if (tmp >= 0xA0) + lzma_reset(s); + } + } else { + if (tmp == 0x00) + return XZ_STREAM_END; + + if (tmp > 0x02) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_COMPRESSED_0; + s->lzma2.next_sequence = SEQ_COPY; + } + + break; + + case SEQ_UNCOMPRESSED_1: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_UNCOMPRESSED_2; + break; + + case SEQ_UNCOMPRESSED_2: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = SEQ_COMPRESSED_0; + break; + + case SEQ_COMPRESSED_0: + s->lzma2.compressed + = (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_COMPRESSED_1; + break; + + case SEQ_COMPRESSED_1: + s->lzma2.compressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = s->lzma2.next_sequence; + break; + + case SEQ_PROPERTIES: + if (!lzma_props(s, b->in[b->in_pos++])) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_LZMA_PREPARE; + + case SEQ_LZMA_PREPARE: + if (s->lzma2.compressed < RC_INIT_BYTES) + return XZ_DATA_ERROR; + + if (!rc_read_init(&s->rc, b)) + return XZ_OK; + + s->lzma2.compressed -= RC_INIT_BYTES; + s->lzma2.sequence = SEQ_LZMA_RUN; + + case SEQ_LZMA_RUN: + /* + * Set dictionary limit to indicate how much we want + * to be encoded at maximum. Decode new data into the + * dictionary. Flush the new data from dictionary to + * b->out. Check if we finished decoding this chunk. + * In case the dictionary got full but we didn't fill + * the output buffer yet, we may run this loop + * multiple times without changing s->lzma2.sequence. + */ + dict_limit(&s->dict, min_t(size_t, + b->out_size - b->out_pos, + s->lzma2.uncompressed)); + if (!lzma2_lzma(s, b)) + return XZ_DATA_ERROR; + + s->lzma2.uncompressed -= dict_flush(&s->dict, b); + + if (s->lzma2.uncompressed == 0) { + if (s->lzma2.compressed > 0 || s->lzma.len > 0 + || !rc_is_finished(&s->rc)) + return XZ_DATA_ERROR; + + rc_reset(&s->rc); + s->lzma2.sequence = SEQ_CONTROL; + + } else if (b->out_pos == b->out_size + || (b->in_pos == b->in_size + && s->temp.size + < s->lzma2.compressed)) { + return XZ_OK; + } + + break; + + case SEQ_COPY: + dict_uncompressed(&s->dict, b, &s->lzma2.compressed); + if (s->lzma2.compressed > 0) + return XZ_OK; + + s->lzma2.sequence = SEQ_CONTROL; + break; + } + } + + return XZ_OK; +} + +struct xz_dec_lzma2 * xz_dec_lzma2_create(uint32_t dict_max) +{ + struct xz_dec_lzma2 *s; + + /* Maximum supported dictionary by this implementation is 3 GiB. */ + if (dict_max > ((uint32_t)3 << 30)) + return NULL; + + s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + if (dict_max > 0) { + s->dict.buf = vmalloc(dict_max); + if (s->dict.buf == NULL) { + kfree(s); + return NULL; + } + } + + s->dict.allocated = dict_max; + + return s; +} + +enum xz_ret xz_dec_lzma2_reset( + struct xz_dec_lzma2 *s, uint8_t props) +{ + /* This limits dictionary size to 3 GiB (39) to keep parsing simpler. */ + if (props > ( min (DICT_BIT_SIZE,39)) ) + return XZ_OPTIONS_ERROR; + + s->dict.size = 2 + (props & 1); + s->dict.size <<= (props >> 1) + 11; + + if (s->dict.allocated > 0 && s->dict.allocated < s->dict.size) + { + /* enlarge dictionary buffer */ + uint8_t * newdict = realloc(s->dict.buf,s->dict.size); + + if (! newdict) + return XZ_MEMLIMIT_ERROR; + + s->dict.buf = newdict; + s->dict.allocated = s->dict.size; + } + + s->dict.end = s->dict.size; + + s->lzma.len = 0; + + s->lzma2.sequence = SEQ_CONTROL; + s->lzma2.need_dict_reset = true; + + s->temp.size = 0; + + return XZ_OK; +} + +void xz_dec_lzma2_end(struct xz_dec_lzma2 *s) +{ + if (s->dict.allocated > 0) + vfree(s->dict.buf); + + kfree(s); +} diff --git a/grub-core/lib/xzembed/xz_dec_stream.c b/grub-core/lib/xzembed/xz_dec_stream.c new file mode 100644 index 000000000..642492483 --- /dev/null +++ b/grub-core/lib/xzembed/xz_dec_stream.c @@ -0,0 +1,854 @@ +/* xz_dec_stream.c - .xz Stream decoder */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#include "xz_config.h" +#include "xz_private.h" +#include "xz_stream.h" + +#include + +/* Hash used to validate the Index field */ +struct xz_dec_hash { + vli_type unpadded; + vli_type uncompressed; + uint8_t *crc32_context; +}; + +struct xz_dec { + /* Position in dec_main() */ + enum { + SEQ_STREAM_HEADER, + SEQ_BLOCK_START, + SEQ_BLOCK_HEADER, + SEQ_BLOCK_UNCOMPRESS, + SEQ_BLOCK_PADDING, + SEQ_BLOCK_CHECK, + SEQ_INDEX, + SEQ_INDEX_PADDING, + SEQ_INDEX_CRC32, + SEQ_STREAM_FOOTER + } sequence; + + /* Position in variable-length integers and Check fields */ + uint32_t pos; + + /* Variable-length integer decoded by dec_vli() */ + vli_type vli; + + /* Saved in_pos and out_pos */ + size_t in_start; + size_t out_start; + + /* CRC32 value in Block or Index */ + uint32_t crc32_temp; /* need for crc32_validate*/ + uint8_t *crc32_context; + + /* True if CRC32 is calculated from uncompressed data */ + bool has_crc32; + + /* True if we are operating in single-call mode. */ + bool single_call; + + /* + * True if the next call to xz_dec_run() is allowed to return + * XZ_BUF_ERROR. + */ + bool allow_buf_error; + + /* Information stored in Block Header */ + struct { + /* + * Value stored in the Compressed Size field, or + * VLI_UNKNOWN if Compressed Size is not present. + */ + vli_type compressed; + + /* + * Value stored in the Uncompressed Size field, or + * VLI_UNKNOWN if Uncompressed Size is not present. + */ + vli_type uncompressed; + + /* Size of the Block Header field */ + uint32_t size; + } block_header; + + /* Information collected when decoding Blocks */ + struct { + /* Observed compressed size of the current Block */ + vli_type compressed; + + /* Observed uncompressed size of the current Block */ + vli_type uncompressed; + + /* Number of Blocks decoded so far */ + vli_type count; + + /* + * Hash calculated from the Block sizes. This is used to + * validate the Index field. + */ + struct xz_dec_hash hash; + } block; + + /* Variables needed when verifying the Index field */ + struct { + /* Position in dec_index() */ + enum { + SEQ_INDEX_COUNT, + SEQ_INDEX_UNPADDED, + SEQ_INDEX_UNCOMPRESSED + } sequence; + + /* Size of the Index in bytes */ + vli_type size; + + /* Number of Records (matches block.count in valid files) */ + vli_type count; + + /* + * Hash calculated from the Records (matches block.hash in + * valid files). + */ + struct xz_dec_hash hash; + } index; + + /* + * Temporary buffer needed to hold Stream Header, Block Header, + * and Stream Footer. The Block Header is the biggest (1 KiB) + * so we reserve space according to that. buf[] has to be aligned + * to a multiple of four bytes; the size_t variables before it + * should guarantee this. + */ + struct { + size_t pos; + size_t size; + uint8_t buf[1024]; + } temp; + + struct xz_dec_lzma2 *lzma2; + +#ifdef XZ_DEC_BCJ + struct xz_dec_bcj *bcj; + bool bcj_active; +#endif +}; + +/* + * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller + * must have set s->temp.pos to indicate how much data we are supposed + * to copy into s->temp.buf. Return true once s->temp.pos has reached + * s->temp.size. + */ +static bool fill_temp(struct xz_dec *s, struct xz_buf *b) +{ + size_t copy_size = min_t(size_t, + b->in_size - b->in_pos, s->temp.size - s->temp.pos); + + memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size); + b->in_pos += copy_size; + s->temp.pos += copy_size; + + if (s->temp.pos == s->temp.size) { + s->temp.pos = 0; + return true; + } + + return false; +} + +/* Decode a variable-length integer (little-endian base-128 encoding) */ +static enum xz_ret dec_vli(struct xz_dec *s, + const uint8_t *in, size_t *in_pos, size_t in_size) +{ + uint8_t byte; + + if (s->pos == 0) + s->vli = 0; + + while (*in_pos < in_size) { + byte = in[*in_pos]; + ++*in_pos; + + s->vli |= (vli_type)(byte & 0x7F) << s->pos; + + if ((byte & 0x80) == 0) { + /* Don't allow non-minimal encodings. */ + if (byte == 0 && s->pos != 0) + return XZ_DATA_ERROR; + + s->pos = 0; + return XZ_STREAM_END; + } + + s->pos += 7; + if (s->pos == 7 * VLI_BYTES_MAX) + return XZ_DATA_ERROR; + } + + return XZ_OK; +} + +/* + * Decode the Compressed Data field from a Block. Update and validate + * the observed compressed and uncompressed sizes of the Block so that + * they don't exceed the values possibly stored in the Block Header + * (validation assumes that no integer overflow occurs, since vli_type + * is normally uint64_t). Update the CRC32 if presence of the CRC32 + * field was indicated in Stream Header. + * + * Once the decoding is finished, validate that the observed sizes match + * the sizes possibly stored in the Block Header. Update the hash and + * Block count, which are later used to validate the Index field. + */ +static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + s->in_start = b->in_pos; + s->out_start = b->out_pos; + +#ifdef XZ_DEC_BCJ + if (s->bcj_active) + ret = xz_dec_bcj_run(s->bcj, s->lzma2, b); + else +#endif + ret = xz_dec_lzma2_run(s->lzma2, b); + + s->block.compressed += b->in_pos - s->in_start; + s->block.uncompressed += b->out_pos - s->out_start; + + /* + * There is no need to separately check for VLI_UNKNOWN, since + * the observed sizes are always smaller than VLI_UNKNOWN. + */ + if (s->block.compressed > s->block_header.compressed + || s->block.uncompressed + > s->block_header.uncompressed) + return XZ_DATA_ERROR; + + if (s->has_crc32) + GRUB_MD_CRC32->write(s->crc32_context,b->out + s->out_start, + b->out_pos - s->out_start); + + if (ret == XZ_STREAM_END) { + if (s->block_header.compressed != VLI_UNKNOWN + && s->block_header.compressed + != s->block.compressed) + return XZ_DATA_ERROR; + + if (s->block_header.uncompressed != VLI_UNKNOWN + && s->block_header.uncompressed + != s->block.uncompressed) + return XZ_DATA_ERROR; + + s->block.hash.unpadded += s->block_header.size + + s->block.compressed; + if (s->has_crc32) + s->block.hash.unpadded += 4; + + s->block.hash.uncompressed += s->block.uncompressed; + + GRUB_MD_CRC32->write(s->block.hash.crc32_context, + (const uint8_t *)&s->block.hash, sizeof(s->block.hash)); + + ++s->block.count; + } + + return ret; +} + +/* Update the Index size and the CRC32 value. */ +static void index_update(struct xz_dec *s, const struct xz_buf *b) +{ + size_t in_used = b->in_pos - s->in_start; + s->index.size += in_used; + GRUB_MD_CRC32->write(s->crc32_context,b->in + s->in_start, in_used); +} + +/* + * Decode the Number of Records, Unpadded Size, and Uncompressed Size + * fields from the Index field. That is, Index Padding and CRC32 are not + * decoded by this function. + * + * This can return XZ_OK (more input needed), XZ_STREAM_END (everything + * successfully decoded), or XZ_DATA_ERROR (input is corrupt). + */ +static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + do { + ret = dec_vli(s, b->in, &b->in_pos, b->in_size); + if (ret != XZ_STREAM_END) { + index_update(s, b); + return ret; + } + + switch (s->index.sequence) { + case SEQ_INDEX_COUNT: + s->index.count = s->vli; + + /* + * Validate that the Number of Records field + * indicates the same number of Records as + * there were Blocks in the Stream. + */ + if (s->index.count != s->block.count) + return XZ_DATA_ERROR; + + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + + case SEQ_INDEX_UNPADDED: + s->index.hash.unpadded += s->vli; + s->index.sequence = SEQ_INDEX_UNCOMPRESSED; + break; + + case SEQ_INDEX_UNCOMPRESSED: + s->index.hash.uncompressed += s->vli; + + GRUB_MD_CRC32->write(s->index.hash.crc32_context, + (const uint8_t *)&s->index.hash, + sizeof(s->index.hash)); + + --s->index.count; + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + } + } while (s->index.count > 0); + + return XZ_STREAM_END; +} + +/* + * Validate that the next four input bytes match the value of s->crc32. + * s->pos must be zero when starting to validate the first byte. + */ +static enum xz_ret crc32_validate(struct xz_dec *s, struct xz_buf *b) +{ + if(s->crc32_temp == 0) + { + GRUB_MD_CRC32->final(s->crc32_context); + s->crc32_temp = get_unaligned_be32(GRUB_MD_CRC32->read(s->crc32_context)); + } + + do { + if (b->in_pos == b->in_size) + return XZ_OK; + + if (((s->crc32_temp >> s->pos) & 0xFF) != b->in[b->in_pos++]) + return XZ_DATA_ERROR; + + s->pos += 8; + + } while (s->pos < 32); + + GRUB_MD_CRC32->init(s->crc32_context); + s->crc32_temp = 0; + s->pos = 0; + + return XZ_STREAM_END; +} + +/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */ +static enum xz_ret dec_stream_header(struct xz_dec *s) +{ + if (! memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE)) + return XZ_FORMAT_ERROR; + + uint8_t crc32_context[GRUB_MD_CRC32->contextsize]; + + GRUB_MD_CRC32->init(crc32_context); + GRUB_MD_CRC32->write(crc32_context,s->temp.buf + HEADER_MAGIC_SIZE, 2); + GRUB_MD_CRC32->final(crc32_context); + + uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context)); + uint32_t readcrc = get_unaligned_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2); + + if(resultcrc != readcrc) + return XZ_DATA_ERROR; + + /* + * Decode the Stream Flags field. Of integrity checks, we support + * only none (Check ID = 0) and CRC32 (Check ID = 1). + */ + if (s->temp.buf[HEADER_MAGIC_SIZE] != 0 + || s->temp.buf[HEADER_MAGIC_SIZE + 1] > 1) + return XZ_OPTIONS_ERROR; + + s->has_crc32 = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + + return XZ_OK; +} + +/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */ +static enum xz_ret dec_stream_footer(struct xz_dec *s) +{ + if (! memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE)) + return XZ_DATA_ERROR; + + uint8_t crc32_context[GRUB_MD_CRC32->contextsize]; + + GRUB_MD_CRC32->init(crc32_context); + GRUB_MD_CRC32->write(crc32_context, s->temp.buf + 4, 6); + GRUB_MD_CRC32->final(crc32_context); + + uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context)); + uint32_t readcrc = get_unaligned_le32(s->temp.buf); + + if(resultcrc != readcrc) + return XZ_DATA_ERROR; + + /* + * Validate Backward Size. Note that we never added the size of the + * Index CRC32 field to s->index.size, thus we use s->index.size / 4 + * instead of s->index.size / 4 - 1. + */ + if ((s->index.size >> 2) != get_le32(s->temp.buf + 4)) + return XZ_DATA_ERROR; + + if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->has_crc32) + return XZ_DATA_ERROR; + + /* + * Use XZ_STREAM_END instead of XZ_OK to be more convenient + * for the caller. + */ + return XZ_STREAM_END; +} + +/* Decode the Block Header and initialize the filter chain. */ +static enum xz_ret dec_block_header(struct xz_dec *s) +{ + enum xz_ret ret; + + /* + * Validate the CRC32. We know that the temp buffer is at least + * eight bytes so this is safe. + */ + s->temp.size -= 4; + + uint8_t crc32_context[GRUB_MD_CRC32->contextsize]; + + GRUB_MD_CRC32->init(crc32_context); + GRUB_MD_CRC32->write(crc32_context, s->temp.buf, s->temp.size); + GRUB_MD_CRC32->final(crc32_context); + + uint32_t resultcrc = get_unaligned_be32(GRUB_MD_CRC32->read(crc32_context)); + uint32_t readcrc = get_unaligned_le32(s->temp.buf + s->temp.size); + + if (resultcrc != readcrc) + return XZ_DATA_ERROR; + + s->temp.pos = 2; + + /* + * Catch unsupported Block Flags. We support only one or two filters + * in the chain, so we catch that with the same test. + */ +#ifdef XZ_DEC_BCJ + if (s->temp.buf[1] & 0x3E) +#else + if (s->temp.buf[1] & 0x3F) +#endif + return XZ_OPTIONS_ERROR; + + /* Compressed Size */ + if (s->temp.buf[1] & 0x40) { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) + != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.compressed = s->vli; + } else { + s->block_header.compressed = VLI_UNKNOWN; + } + + /* Uncompressed Size */ + if (s->temp.buf[1] & 0x80) { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) + != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.uncompressed = s->vli; + } else { + s->block_header.uncompressed = VLI_UNKNOWN; + } + +#ifdef XZ_DEC_BCJ + /* If there are two filters, the first one must be a BCJ filter. */ + s->bcj_active = s->temp.buf[1] & 0x01; + if (s->bcj_active) { + if (s->temp.size - s->temp.pos < 2) + return XZ_OPTIONS_ERROR; + + ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; + + /* + * We don't support custom start offset, + * so Size of Properties must be zero. + */ + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; + } +#endif + + /* Valid Filter Flags always take at least two bytes. */ + if (s->temp.size - s->temp.pos < 2) + return XZ_DATA_ERROR; + + /* Filter ID = LZMA2 */ + if (s->temp.buf[s->temp.pos++] != 0x21) + return XZ_OPTIONS_ERROR; + + /* Size of Properties = 1-byte Filter Properties */ + if (s->temp.buf[s->temp.pos++] != 0x01) + return XZ_OPTIONS_ERROR; + + /* Filter Properties contains LZMA2 dictionary size. */ + if (s->temp.size - s->temp.pos < 1) + return XZ_DATA_ERROR; + + ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; + + /* The rest must be Header Padding. */ + while (s->temp.pos < s->temp.size) + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; + + s->temp.pos = 0; + s->block.compressed = 0; + s->block.uncompressed = 0; + + return XZ_OK; +} + +static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + /* + * Store the start position for the case when we are in the middle + * of the Index field. + */ + s->in_start = b->in_pos; + + while (true) { + switch (s->sequence) { + case SEQ_STREAM_HEADER: + /* + * Stream Header is copied to s->temp, and then + * decoded from there. This way if the caller + * gives us only little input at a time, we can + * still keep the Stream Header decoding code + * simple. Similar approach is used in many places + * in this file. + */ + if (!fill_temp(s, b)) + return XZ_OK; + + ret = dec_stream_header(s); + if (ret != XZ_OK) + return ret; + + s->sequence = SEQ_BLOCK_START; + + case SEQ_BLOCK_START: + /* We need one byte of input to continue. */ + if (b->in_pos == b->in_size) + return XZ_OK; + + /* See if this is the beginning of the Index field. */ + if (b->in[b->in_pos] == 0) { + s->in_start = b->in_pos++; + s->sequence = SEQ_INDEX; + break; + } + + /* + * Calculate the size of the Block Header and + * prepare to decode it. + */ + s->block_header.size + = ((uint32_t)b->in[b->in_pos] + 1) * 4; + + s->temp.size = s->block_header.size; + s->temp.pos = 0; + s->sequence = SEQ_BLOCK_HEADER; + + case SEQ_BLOCK_HEADER: + if (!fill_temp(s, b)) + return XZ_OK; + + ret = dec_block_header(s); + if (ret != XZ_OK) + return ret; + + s->sequence = SEQ_BLOCK_UNCOMPRESS; + + case SEQ_BLOCK_UNCOMPRESS: + ret = dec_block(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->sequence = SEQ_BLOCK_PADDING; + + case SEQ_BLOCK_PADDING: + /* + * Size of Compressed Data + Block Padding + * must be a multiple of four. We don't need + * s->block.compressed for anything else + * anymore, so we use it here to test the size + * of the Block Padding field. + */ + while (s->block.compressed & 3) { + if (b->in_pos == b->in_size) + return XZ_OK; + + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + + ++s->block.compressed; + } + + s->sequence = SEQ_BLOCK_CHECK; + + case SEQ_BLOCK_CHECK: + if (s->has_crc32) { + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + } + + s->sequence = SEQ_BLOCK_START; + break; + + case SEQ_INDEX: + ret = dec_index(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->sequence = SEQ_INDEX_PADDING; + + case SEQ_INDEX_PADDING: + while ((s->index.size + (b->in_pos - s->in_start)) + & 3) { + if (b->in_pos == b->in_size) { + index_update(s, b); + return XZ_OK; + } + + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + } + + /* Finish the CRC32 value and Index size. */ + index_update(s, b); + + /* Compare the hashes to validate the Index field. */ + if (! memeq(&s->block.hash, &s->index.hash, sizeof(s->block.hash))) + return XZ_DATA_ERROR; + + s->sequence = SEQ_INDEX_CRC32; + + case SEQ_INDEX_CRC32: + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->temp.size = STREAM_HEADER_SIZE; + s->sequence = SEQ_STREAM_FOOTER; + + case SEQ_STREAM_FOOTER: + if (!fill_temp(s, b)) + return XZ_OK; + + return dec_stream_footer(s); + } + } + + /* Never reached */ +} + +/* + * xz_dec_run() is a wrapper for dec_main() to handle some special cases in + * multi-call and single-call decoding. + * + * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we + * are not going to make any progress anymore. This is to prevent the caller + * from calling us infinitely when the input file is truncated or otherwise + * corrupt. Since zlib-style API allows that the caller fills the input buffer + * only when the decoder doesn't produce any new output, we have to be careful + * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only + * after the second consecutive call to xz_dec_run() that makes no progress. + * + * In single-call mode, if we couldn't decode everything and no error + * occurred, either the input is truncated or the output buffer is too small. + * Since we know that the last input byte never produces any output, we know + * that if all the input was consumed and decoding wasn't finished, the file + * must be corrupt. Otherwise the output buffer has to be too small or the + * file is corrupt in a way that decoding it produces too big output. + * + * If single-call decoding fails, we reset b->in_pos and b->out_pos back to + * their original values. This is because with some filter chains there won't + * be any valid uncompressed data in the output buffer unless the decoding + * actually succeeds (that's the price to pay of using the output buffer as + * the workspace). + */ +enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b) +{ + size_t in_start; + size_t out_start; + enum xz_ret ret; + + if (s->single_call) + xz_dec_reset(s); + + in_start = b->in_pos; + out_start = b->out_pos; + ret = dec_main(s, b); + + if (s->single_call) { + if (ret == XZ_OK) + ret = b->in_pos == b->in_size + ? XZ_DATA_ERROR : XZ_BUF_ERROR; + + if (ret != XZ_STREAM_END) { + b->in_pos = in_start; + b->out_pos = out_start; + } + + } else if (ret == XZ_OK && in_start == b->in_pos + && out_start == b->out_pos) { + if (s->allow_buf_error) + ret = XZ_BUF_ERROR; + + s->allow_buf_error = true; + } else { + s->allow_buf_error = false; + } + + return ret; +} + +struct xz_dec * xz_dec_init(uint32_t dict_max) +{ + struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + /* prepare CRC32 calculators */ + if(GRUB_MD_CRC32 == NULL) + { + kfree(s); + return NULL; + } + + s->crc32_context = kmalloc(GRUB_MD_CRC32->contextsize, GFP_KERNEL); + if (s->crc32_context == NULL) + { + kfree(s); + return NULL; + } + + s->index.hash.crc32_context = kmalloc(GRUB_MD_CRC32->contextsize, GFP_KERNEL); + if (s->index.hash.crc32_context == NULL) + { + kfree(s->crc32_context); + kfree(s); + return NULL; + } + + s->block.hash.crc32_context = kmalloc(GRUB_MD_CRC32->contextsize, GFP_KERNEL); + if (s->block.hash.crc32_context == NULL) + { + kfree(s->index.hash.crc32_context); + kfree(s->crc32_context); + kfree(s); + return NULL; + } + + + GRUB_MD_CRC32->init(s->crc32_context); + s->crc32_temp = 0; + GRUB_MD_CRC32->init(s->index.hash.crc32_context); + GRUB_MD_CRC32->init(s->block.hash.crc32_context); + + + s->single_call = dict_max == 0; + +#ifdef XZ_DEC_BCJ + s->bcj = xz_dec_bcj_create(s->single_call); + if (s->bcj == NULL) + goto error_bcj; +#endif + + s->lzma2 = xz_dec_lzma2_create(dict_max); + if (s->lzma2 == NULL) + goto error_lzma2; + + xz_dec_reset(s); + return s; + +error_lzma2: +#ifdef XZ_DEC_BCJ + xz_dec_bcj_end(s->bcj); +error_bcj: +#endif + kfree(s); + return NULL; +} + +void xz_dec_reset(struct xz_dec *s) +{ + s->sequence = SEQ_STREAM_HEADER; + s->allow_buf_error = false; + s->pos = 0; + + memzero(&s->block, sizeof(s->block)); + memzero(&s->index, sizeof(s->index)); + s->temp.pos = 0; + s->temp.size = STREAM_HEADER_SIZE; + + GRUB_MD_CRC32->init(s->crc32_context); + s->crc32_temp = 0; + GRUB_MD_CRC32->init(s->index.hash.crc32_context); + GRUB_MD_CRC32->init(s->block.hash.crc32_context); + +} + +void xz_dec_end(struct xz_dec *s) +{ + if (s != NULL) { + xz_dec_lzma2_end(s->lzma2); +#ifdef XZ_DEC_BCJ + xz_dec_bcj_end(s->bcj); +#endif + kfree(s); + } +} diff --git a/grub-core/lib/xzembed/xz_lzma2.h b/grub-core/lib/xzembed/xz_lzma2.h new file mode 100644 index 000000000..15e553dc0 --- /dev/null +++ b/grub-core/lib/xzembed/xz_lzma2.h @@ -0,0 +1,236 @@ +/* xz_lzma2.h - LZMA2 definitions */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#ifndef XZ_LZMA2_H +#define XZ_LZMA2_H + +/* dictionary size hard limit + * actual size limit is calculated as shown in 5.3.1 + * http://tukaani.org/xz/xz-file-format.txt + * + * if bits > 39 dictionary_size = UINT32_MAX + * else + * dictionary_size = 2 | (bits & 1); + * dictionary_size <<= bits / 2 + 11; + * + * i.e. + * 0 - 4 KiB + * 6 - 32 KiB + * 30 - 128MiB + * 39 - 3072 MiB + * 40 - 4096 MiB - 1 B + * note: implementation supports 39 at maximum + */ +#define DICT_BIT_SIZE 30 + +/* Range coder constants */ +#define RC_SHIFT_BITS 8 +#define RC_TOP_BITS 24 +#define RC_TOP_VALUE (1 << RC_TOP_BITS) +#define RC_BIT_MODEL_TOTAL_BITS 11 +#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS) +#define RC_MOVE_BITS 5 + +/* + * Maximum number of position states. A position state is the lowest pb + * number of bits of the current uncompressed offset. In some places there + * are different sets of probabilities for different position states. + */ +#define POS_STATES_MAX (1 << 4) + +/* + * This enum is used to track which LZMA symbols have occurred most recently + * and in which order. This information is used to predict the next symbol. + * + * Symbols: + * - Literal: One 8-bit byte + * - Match: Repeat a chunk of data at some distance + * - Long repeat: Multi-byte match at a recently seen distance + * - Short repeat: One-byte repeat at a recently seen distance + * + * The symbol names are in from STATE_oldest_older_previous. REP means + * either short or long repeated match, and NONLIT means any non-literal. + */ +enum lzma_state { + STATE_LIT_LIT, + STATE_MATCH_LIT_LIT, + STATE_REP_LIT_LIT, + STATE_SHORTREP_LIT_LIT, + STATE_MATCH_LIT, + STATE_REP_LIT, + STATE_SHORTREP_LIT, + STATE_LIT_MATCH, + STATE_LIT_LONGREP, + STATE_LIT_SHORTREP, + STATE_NONLIT_MATCH, + STATE_NONLIT_REP +}; + +/* Total number of states */ +#define STATES 12 + +/* The lowest 7 states indicate that the previous state was a literal. */ +#define LIT_STATES 7 + +/* Indicate that the latest symbol was a literal. */ +static inline void lzma_state_literal(enum lzma_state *state) +{ + if (*state <= STATE_SHORTREP_LIT_LIT) + *state = STATE_LIT_LIT; + else if (*state <= STATE_LIT_SHORTREP) + *state -= 3; + else + *state -= 6; +} + +/* Indicate that the latest symbol was a match. */ +static inline void lzma_state_match(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH; +} + +/* Indicate that the latest state was a long repeated match. */ +static inline void lzma_state_long_rep(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP; +} + +/* Indicate that the latest symbol was a short match. */ +static inline void lzma_state_short_rep(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP; +} + +/* Test if the previous symbol was a literal. */ +static inline bool lzma_state_is_literal(enum lzma_state state) +{ + return state < LIT_STATES; +} + +/* Each literal coder is divided in three sections: + * - 0x001-0x0FF: Without match byte + * - 0x101-0x1FF: With match byte; match bit is 0 + * - 0x201-0x2FF: With match byte; match bit is 1 + * + * Match byte is used when the previous LZMA symbol was something else than + * a literal (that is, it was some kind of match). + */ +#define LITERAL_CODER_SIZE 0x300 + +/* Maximum number of literal coders */ +#define LITERAL_CODERS_MAX (1 << 4) + +/* Minimum length of a match is two bytes. */ +#define MATCH_LEN_MIN 2 + +/* Match length is encoded with 4, 5, or 10 bits. + * + * Length Bits + * 2-9 4 = Choice=0 + 3 bits + * 10-17 5 = Choice=1 + Choice2=0 + 3 bits + * 18-273 10 = Choice=1 + Choice2=1 + 8 bits + */ +#define LEN_LOW_BITS 3 +#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS) +#define LEN_MID_BITS 3 +#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS) +#define LEN_HIGH_BITS 8 +#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS) +#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS) + +/* + * Maximum length of a match is 273 which is a result of the encoding + * described above. + */ +#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1) + +/* + * Different sets of probabilities are used for match distances that have + * very short match length: Lengths of 2, 3, and 4 bytes have a separate + * set of probabilities for each length. The matches with longer length + * use a shared set of probabilities. + */ +#define DIST_STATES 4 + +/* + * Get the index of the appropriate probability array for decoding + * the distance slot. + */ +static inline uint32_t lzma_get_dist_state(uint32_t len) +{ + return len < DIST_STATES + MATCH_LEN_MIN + ? len - MATCH_LEN_MIN : DIST_STATES - 1; +} + +/* + * The highest two bits of a 32-bit match distance are encoded using six bits. + * This six-bit value is called a distance slot. This way encoding a 32-bit + * value takes 6-36 bits, larger values taking more bits. + */ +#define DIST_SLOT_BITS 6 +#define DIST_SLOTS (1 << DIST_SLOT_BITS) + +/* Match distances up to 127 are fully encoded using probabilities. Since + * the highest two bits (distance slot) are always encoded using six bits, + * the distances 0-3 don't need any additional bits to encode, since the + * distance slot itself is the same as the actual distance. DIST_MODEL_START + * indicates the first distance slot where at least one additional bit is + * needed. + */ +#define DIST_MODEL_START 4 + +/* + * Match distances greater than 127 are encoded in three pieces: + * - distance slot: the highest two bits + * - direct bits: 2-26 bits below the highest two bits + * - alignment bits: four lowest bits + * + * Direct bits don't use any probabilities. + * + * The distance slot value of 14 is for distances 128-191. + */ +#define DIST_MODEL_END 14 + +/* Distance slots that indicate a distance <= 127. */ +#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2) +#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS) + +/* + * For match distances greater than 127, only the highest two bits and the + * lowest four bits (alignment) is encoded using probabilities. + */ +#define ALIGN_BITS 4 +#define ALIGN_SIZE (1 << ALIGN_BITS) +#define ALIGN_MASK (ALIGN_SIZE - 1) + +/* Total number of all probability variables */ +#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE) + +/* + * LZMA remembers the four most recent match distances. Reusing these + * distances tends to take less space than re-encoding the actual + * distance value. + */ +#define REPS 4 + +#endif diff --git a/grub-core/lib/xzembed/xz_private.h b/grub-core/lib/xzembed/xz_private.h new file mode 100644 index 000000000..fc845c92d --- /dev/null +++ b/grub-core/lib/xzembed/xz_private.h @@ -0,0 +1,96 @@ +/* xz_private.h - Private includes and definitions */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#ifndef XZ_PRIVATE_H +#define XZ_PRIVATE_H + +/* + * For userspace builds, use a separate header to define the required + * macros and functions. This makes it easier to adapt the code into + * different environments and avoids clutter in the Linux kernel tree. + */ +#include "xz_config.h" + +/* + * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. + * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. + */ +#ifndef XZ_DEC_BCJ +# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \ + || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \ + || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \ + || defined(XZ_DEC_SPARC) +# define XZ_DEC_BCJ +# endif +#endif + +/* + * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used + * before calling xz_dec_lzma2_run(). + */ +struct xz_dec_lzma2 * xz_dec_lzma2_create( + uint32_t dict_max); + +/* + * Decode the LZMA2 properties (one byte) and reset the decoder. Return + * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not + * big enough, and XZ_OPTIONS_ERROR if props indicates something that this + * decoder doesn't support. + */ +enum xz_ret xz_dec_lzma2_reset( + struct xz_dec_lzma2 *s, uint8_t props); + +/* Decode raw LZMA2 stream from b->in to b->out. */ +enum xz_ret xz_dec_lzma2_run( + struct xz_dec_lzma2 *s, struct xz_buf *b); + +/* Free the memory allocated for the LZMA2 decoder. */ +void xz_dec_lzma2_end(struct xz_dec_lzma2 *s); + +/* + * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before + * calling xz_dec_bcj_run(). + */ +struct xz_dec_bcj * xz_dec_bcj_create(bool single_call); + +/* + * Decode the Filter ID of a BCJ filter. This implementation doesn't + * support custom start offsets, so no decoding of Filter Properties + * is needed. Returns XZ_OK if the given Filter ID is supported. + * Otherwise XZ_OPTIONS_ERROR is returned. + */ +enum xz_ret xz_dec_bcj_reset( + struct xz_dec_bcj *s, uint8_t id); + +/* + * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is + * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run() + * must be called directly. + */ +enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s, + struct xz_dec_lzma2 *lzma2, struct xz_buf *b); + +/* Free the memory allocated for the BCJ filters. */ +#define xz_dec_bcj_end(s) kfree(s) + +#endif diff --git a/grub-core/lib/xzembed/xz_stream.h b/grub-core/lib/xzembed/xz_stream.h new file mode 100644 index 000000000..f58397a15 --- /dev/null +++ b/grub-core/lib/xzembed/xz_stream.h @@ -0,0 +1,53 @@ +/* xz_stream.h - Definitions for handling the .xz file format */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +/* + * This file is based on code from XZ embedded project + * http://tukaani.org/xz/embedded.html + */ + +#ifndef XZ_STREAM_H +#define XZ_STREAM_H + +/* + * See the .xz file format specification at + * http://tukaani.org/xz/xz-file-format.txt + * to understand the container format. + */ + +#define STREAM_HEADER_SIZE 12 + +#define HEADER_MAGIC "\3757zXZ\0" +#define HEADER_MAGIC_SIZE 6 + +#define FOOTER_MAGIC "YZ" +#define FOOTER_MAGIC_SIZE 2 + +/* + * Variable-length integer can hold a 63-bit unsigned integer, or a special + * value to indicate that the value is unknown. + */ +typedef uint64_t vli_type; + +#define VLI_MAX ((vli_type)-1 / 2) +#define VLI_UNKNOWN ((vli_type)-1) + +/* Maximum encoded size of a VLI */ +#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7) + +#endif diff --git a/grub-core/loader/aout.c b/grub-core/loader/aout.c index 0254b6ae0..611960f92 100644 --- a/grub-core/loader/aout.c +++ b/grub-core/loader/aout.c @@ -39,9 +39,8 @@ grub_aout_get_type (union grub_aout_header *header) grub_err_t grub_aout_load (grub_file_t file, int offset, - grub_addr_t load_addr, - int load_size, - grub_addr_t bss_end_addr) + void *load_addr, + int load_size, grub_size_t bss_size) { if ((grub_file_seek (file, offset)) == (grub_off_t) - 1) return grub_errno; @@ -49,14 +48,13 @@ grub_aout_load (grub_file_t file, int offset, if (!load_size) load_size = file->size - offset; - grub_file_read (file, (void *) load_addr, load_size); + grub_file_read (file, load_addr, load_size); if (grub_errno) return grub_errno; - if (bss_end_addr) - grub_memset ((char *) load_addr + load_size, 0, - bss_end_addr - load_addr - load_size); + if (bss_size) + grub_memset ((char *) load_addr + load_size, 0, bss_size); return GRUB_ERR_NONE; } diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 3c7fe2fee..2e92bc42f 100644 --- a/grub-core/loader/i386/bsd.c +++ b/grub-core/loader/i386/bsd.c @@ -17,10 +17,8 @@ */ #include -#include -#include +#include #include -#include #include #include #include @@ -30,35 +28,67 @@ #include #include #include -#include #include #include #include #include +#include + #include #ifdef GRUB_MACHINE_PCBIOS #include #endif +#ifdef GRUB_MACHINE_EFI +#include +#define NETBSD_DEFAULT_VIDEO_MODE "800x600" +#else +#define NETBSD_DEFAULT_VIDEO_MODE "text" +#include +#endif +#include + #include #include #include +#include +#include #define ALIGN_DWORD(a) ALIGN_UP (a, 4) #define ALIGN_QWORD(a) ALIGN_UP (a, 8) #define ALIGN_VAR(a) ((is_64bit) ? (ALIGN_QWORD(a)) : (ALIGN_DWORD(a))) #define ALIGN_PAGE(a) ALIGN_UP (a, 4096) -#define MOD_BUF_ALLOC_UNIT 4096 - static int kernel_type = KERNEL_TYPE_NONE; static grub_dl_t my_mod; static grub_addr_t entry, entry_hi, kern_start, kern_end; +static void *kern_chunk_src; static grub_uint32_t bootflags; -static char *mod_buf; -static grub_uint32_t mod_buf_len, mod_buf_max, kern_end_mdofs; static int is_elf_kernel, is_64bit; -static char *netbsd_root = NULL; static grub_uint32_t openbsd_root; +struct grub_relocator *relocator = NULL; +static struct grub_openbsd_ramdisk_descriptor openbsd_ramdisk; + +struct bsd_tag +{ + struct bsd_tag *next; + grub_size_t len; + grub_uint32_t type; + union { + grub_uint8_t a; + grub_uint16_t b; + grub_uint32_t c; + } data[0]; +}; + +static struct bsd_tag *tags, *tags_last; + +struct netbsd_module +{ + struct netbsd_module *next; + struct grub_netbsd_btinfo_module mod; +}; + +static struct netbsd_module *netbsd_mods, *netbsd_mods_last; static const struct grub_arg_option freebsd_opts[] = { @@ -96,6 +126,8 @@ static const struct grub_arg_option openbsd_opts[] = {"single", 's', 0, N_("Boot into single mode."), 0, 0}, {"kdb", 'd', 0, N_("Enter in KDB on boot."), 0, 0}, {"root", 'r', 0, N_("Set root device."), "wdXY", ARG_TYPE_STRING}, + {"serial", 'h', GRUB_ARG_OPTION_OPTIONAL, + N_("Use serial console."), N_("comUNIT[,SPEED]"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -106,6 +138,7 @@ static const grub_uint32_t openbsd_flags[] = }; #define OPENBSD_ROOT_ARG (ARRAY_SIZE (openbsd_flags) - 1) +#define OPENBSD_SERIAL_ARG (ARRAY_SIZE (openbsd_flags)) static const struct grub_arg_option netbsd_opts[] = { @@ -122,6 +155,8 @@ static const struct grub_arg_option netbsd_opts[] = {"debug", 'x', 0, N_("Boot with debug messages."), 0, 0}, {"silent", 'z', 0, N_("Supress normal output (warnings remain)."), 0, 0}, {"root", 'r', 0, N_("Set root device."), N_("DEVICE"), ARG_TYPE_STRING}, + {"serial", 'h', GRUB_ARG_OPTION_OPTIONAL, + N_("Use serial console."), N_("[ADDR|comUNIT][,SPEED]"), ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -134,6 +169,7 @@ static const grub_uint32_t netbsd_flags[] = }; #define NETBSD_ROOT_ARG (ARRAY_SIZE (netbsd_flags) - 1) +#define NETBSD_SERIAL_ARG (ARRAY_SIZE (netbsd_flags)) static void grub_bsd_get_device (grub_uint32_t * biosdev, @@ -166,36 +202,42 @@ grub_bsd_get_device (grub_uint32_t * biosdev, } grub_err_t -grub_freebsd_add_meta (grub_uint32_t type, void *data, grub_uint32_t len) +grub_bsd_add_meta (grub_uint32_t type, void *data, grub_uint32_t len) { - if (mod_buf_max < mod_buf_len + len + 8) + struct bsd_tag *newtag; + + newtag = grub_malloc (len + sizeof (struct bsd_tag)); + if (!newtag) + return grub_errno; + newtag->len = len; + newtag->type = type; + newtag->next = NULL; + if (len) + grub_memcpy (newtag->data, data, len); + + if (kernel_type == KERNEL_TYPE_FREEBSD + && type == (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_SMAP)) { - char *new_buf; + struct bsd_tag *p; + for (p = tags; + p->type != (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_KERNEND); + p = p->next); - do + if (p) { - mod_buf_max += MOD_BUF_ALLOC_UNIT; + newtag->next = p->next; + p->next = newtag; + if (newtag->next == NULL) + tags_last = newtag; + return GRUB_ERR_NONE; } - while (mod_buf_max < mod_buf_len + len + 8); - - new_buf = grub_malloc (mod_buf_max); - if (!new_buf) - return grub_errno; - - grub_memcpy (new_buf, mod_buf, mod_buf_len); - grub_free (mod_buf); - - mod_buf = new_buf; } - *((grub_uint32_t *) (mod_buf + mod_buf_len)) = type; - *((grub_uint32_t *) (mod_buf + mod_buf_len + 4)) = len; - mod_buf_len += 8; - - if (len) - grub_memcpy (mod_buf + mod_buf_len, data, len); - - mod_buf_len = ALIGN_VAR (mod_buf_len + len); + if (tags_last) + tags_last->next = newtag; + else + tags = newtag; + tags_last = newtag; return GRUB_ERR_NONE; } @@ -212,100 +254,133 @@ struct grub_e820_mmap #define GRUB_E820_NVS 4 #define GRUB_E820_EXEC_CODE 5 -static grub_err_t -grub_freebsd_add_mmap (void) +static void +generate_e820_mmap (grub_size_t *len, grub_size_t *cnt, void *buf) { - grub_size_t len = 0; - struct grub_e820_mmap *mmap_buf = 0; - struct grub_e820_mmap *mmap = 0; - int isfirstrun = 1; + int count = 0; + struct grub_e820_mmap *mmap = buf; + struct grub_e820_mmap prev, cur; auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) { - /* FreeBSD assumes that first 64KiB are available. - Not always true but try to prevent panic somehow. */ - if (isfirstrun && addr != 0) + cur.addr = addr; + cur.size = size; + switch (type) { - if (mmap) - { - mmap->addr = 0; - mmap->size = (addr < 0x10000) ? addr : 0x10000; - mmap->type = GRUB_E820_RAM; - mmap++; - } - else - len += sizeof (struct grub_e820_mmap); - } - isfirstrun = 0; - if (mmap) - { - mmap->addr = addr; - mmap->size = size; - switch (type) - { - case GRUB_MACHINE_MEMORY_AVAILABLE: - mmap->type = GRUB_E820_RAM; - break; + case GRUB_MACHINE_MEMORY_AVAILABLE: + cur.type = GRUB_E820_RAM; + break; #ifdef GRUB_MACHINE_MEMORY_ACPI - case GRUB_MACHINE_MEMORY_ACPI: - mmap->type = GRUB_E820_ACPI; - break; + case GRUB_MACHINE_MEMORY_ACPI: + cur.type = GRUB_E820_ACPI; + break; #endif #ifdef GRUB_MACHINE_MEMORY_NVS - case GRUB_MACHINE_MEMORY_NVS: - mmap->type = GRUB_E820_NVS; - break; + case GRUB_MACHINE_MEMORY_NVS: + cur.type = GRUB_E820_NVS; + break; #endif - default: + default: #ifdef GRUB_MACHINE_MEMORY_CODE - case GRUB_MACHINE_MEMORY_CODE: + case GRUB_MACHINE_MEMORY_CODE: #endif #ifdef GRUB_MACHINE_MEMORY_RESERVED - case GRUB_MACHINE_MEMORY_RESERVED: + case GRUB_MACHINE_MEMORY_RESERVED: #endif - mmap->type = GRUB_E820_RESERVED; - break; - } + cur.type = GRUB_E820_RESERVED; + break; + } - /* Merge regions if possible. */ - if (mmap != mmap_buf && mmap->type == mmap[-1].type && - mmap->addr == mmap[-1].addr + mmap[-1].size) - mmap[-1].size += mmap->size; - else - mmap++; + /* Merge regions if possible. */ + if (count && cur.type == prev.type && cur.addr == prev.addr + prev.size) + { + prev.size += cur.size; + if (mmap) + mmap[-1] = prev; } else - len += sizeof (struct grub_e820_mmap); + { + if (mmap) + *mmap++ = cur; + prev = cur; + count++; + } + + if (kernel_type == KERNEL_TYPE_OPENBSD && prev.addr < 0x100000 + && prev.addr + prev.size > 0x100000) + { + cur.addr = 0x100000; + cur.size = prev.addr + prev.size - 0x100000; + cur.type = prev.type; + prev.size = 0x100000 - prev.addr; + if (mmap) + { + mmap[-1] = prev; + mmap[0] = cur; + mmap++; + } + prev = cur; + count++; + } return 0; } grub_mmap_iterate (hook); - mmap_buf = mmap = grub_malloc (len); - if (! mmap) + + if (len) + *len = count * sizeof (struct grub_e820_mmap); + *cnt = count; + + return; +} + +static grub_err_t +grub_bsd_add_mmap (void) +{ + grub_size_t len, cnt; + void *buf = NULL, *buf0; + + generate_e820_mmap (&len, &cnt, buf); + + if (kernel_type == KERNEL_TYPE_NETBSD) + len += sizeof (grub_uint32_t); + + if (kernel_type == KERNEL_TYPE_OPENBSD) + len += sizeof (struct grub_e820_mmap); + + buf = grub_malloc (len); + if (!buf) return grub_errno; - isfirstrun = 1; - grub_mmap_iterate (hook); + buf0 = buf; + if (kernel_type == KERNEL_TYPE_NETBSD) + { + *(grub_uint32_t *) buf = cnt; + buf = ((grub_uint32_t *) buf + 1); + } - len = (mmap - mmap_buf) * sizeof (struct grub_e820_mmap); - int i; - for (i = 0; i < mmap - mmap_buf; i++) - grub_dprintf ("bsd", "smap %d, %d:%llx - %llx\n", i, - mmap_buf[i].type, - (unsigned long long) mmap_buf[i].addr, - (unsigned long long) mmap_buf[i].size); + generate_e820_mmap (NULL, &cnt, buf); - grub_dprintf ("bsd", "%d entries in smap\n", mmap - mmap_buf); - grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_SMAP, mmap_buf, len); + if (kernel_type == KERNEL_TYPE_OPENBSD) + grub_memset ((grub_uint8_t *) buf + len - sizeof (struct grub_e820_mmap), 0, + sizeof (struct grub_e820_mmap)); - grub_free (mmap_buf); + grub_dprintf ("bsd", "%u entries in smap\n", (unsigned) cnt); + if (kernel_type == KERNEL_TYPE_NETBSD) + grub_bsd_add_meta (NETBSD_BTINFO_MEMMAP, buf0, len); + else if (kernel_type == KERNEL_TYPE_OPENBSD) + grub_bsd_add_meta (OPENBSD_BOOTARG_MMAP, buf0, len); + else + grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_SMAP, buf0, len); + + grub_free (buf0); return grub_errno; } @@ -323,29 +398,22 @@ grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv, if (grub_strcmp (type, "/boot/zfs/zpool.cache") == 0) name = "/boot/zfs/zpool.cache"; - if (grub_freebsd_add_meta (FREEBSD_MODINFO_NAME, name, - grub_strlen (name) + 1)) + if (grub_bsd_add_meta (FREEBSD_MODINFO_NAME, name, grub_strlen (name) + 1)) return grub_errno; if (is_64bit) { grub_uint64_t addr64 = addr, size64 = size; - if ((grub_freebsd_add_meta (FREEBSD_MODINFO_TYPE, type, - grub_strlen (type) + 1)) || - (grub_freebsd_add_meta (FREEBSD_MODINFO_ADDR, &addr64, - sizeof (addr64))) || - (grub_freebsd_add_meta (FREEBSD_MODINFO_SIZE, &size64, - sizeof (size64)))) + if (grub_bsd_add_meta (FREEBSD_MODINFO_TYPE, type, grub_strlen (type) + 1) + || grub_bsd_add_meta (FREEBSD_MODINFO_ADDR, &addr64, sizeof (addr64)) + || grub_bsd_add_meta (FREEBSD_MODINFO_SIZE, &size64, sizeof (size64))) return grub_errno; } else { - if ((grub_freebsd_add_meta (FREEBSD_MODINFO_TYPE, type, - grub_strlen (type) + 1)) || - (grub_freebsd_add_meta (FREEBSD_MODINFO_ADDR, &addr, - sizeof (addr))) || - (grub_freebsd_add_meta (FREEBSD_MODINFO_SIZE, &size, - sizeof (size)))) + if (grub_bsd_add_meta (FREEBSD_MODINFO_TYPE, type, grub_strlen (type) + 1) + || grub_bsd_add_meta (FREEBSD_MODINFO_ADDR, &addr, sizeof (addr)) + || grub_bsd_add_meta (FREEBSD_MODINFO_SIZE, &size, sizeof (size))) return grub_errno; } @@ -372,7 +440,7 @@ grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv, } *p = 0; - if (grub_freebsd_add_meta (FREEBSD_MODINFO_ARGS, cmdline, n)) + if (grub_bsd_add_meta (FREEBSD_MODINFO_ARGS, cmdline, n)) return grub_errno; } } @@ -383,27 +451,23 @@ grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv, static void grub_freebsd_list_modules (void) { - grub_uint32_t pos = 0; + struct bsd_tag *tag; grub_printf (" %-18s %-18s%14s%14s\n", "name", "type", "addr", "size"); - while (pos < mod_buf_len) - { - grub_uint32_t type, size; - type = *((grub_uint32_t *) (mod_buf + pos)); - size = *((grub_uint32_t *) (mod_buf + pos + 4)); - pos += 8; - switch (type) + for (tag = tags; tag; tag = tag->next) + { + switch (tag->type) { case FREEBSD_MODINFO_NAME: case FREEBSD_MODINFO_TYPE: - grub_printf (" %-18s", mod_buf + pos); + grub_printf (" %-18s", (char *) tag->data); break; case FREEBSD_MODINFO_ADDR: { - grub_addr_t addr; + grub_uint32_t addr; - addr = *((grub_addr_t *) (mod_buf + pos)); + addr = *((grub_uint32_t *) tag->data); grub_printf (" 0x%08x", addr); break; } @@ -411,41 +475,93 @@ grub_freebsd_list_modules (void) { grub_uint32_t len; - len = *((grub_uint32_t *) (mod_buf + pos)); + len = *((grub_uint32_t *) tag->data); grub_printf (" 0x%08x\n", len); } } - - pos = ALIGN_VAR (pos + size); } } +static grub_err_t +grub_netbsd_add_meta_module (char *filename, grub_uint32_t type, + grub_addr_t addr, grub_uint32_t size) +{ + char *name; + struct netbsd_module *mod; + name = grub_strrchr (filename, '/'); + + if (name) + name++; + else + name = filename; + + mod = grub_zalloc (sizeof (*mod)); + if (!mod) + return grub_errno; + + grub_strncpy (mod->mod.name, name, sizeof (mod->mod.name) - 1); + mod->mod.addr = addr; + mod->mod.type = type; + mod->mod.size = size; + + if (netbsd_mods_last) + netbsd_mods_last->next = mod; + else + netbsd_mods = mod; + netbsd_mods_last = mod; + + return GRUB_ERR_NONE; +} + +static void +grub_netbsd_list_modules (void) +{ + struct netbsd_module *mod; + + grub_printf (" %-18s%14s%14s%14s\n", "name", "type", "addr", "size"); + + for (mod = netbsd_mods; mod; mod = mod->next) + grub_printf (" %-18s 0x%08x 0x%08x 0x%08x", mod->mod.name, + mod->mod.type, mod->mod.addr, mod->mod.size); +} + /* This function would be here but it's under different license. */ #include "bsd_pagetable.c" -struct gdt_descriptor -{ - grub_uint16_t limit; - void *base; -} __attribute__ ((packed)); - static grub_err_t grub_freebsd_boot (void) { struct grub_freebsd_bootinfo bi; - char *p; + grub_uint8_t *p, *p0; + grub_addr_t p_target; + grub_size_t p_size = 0; grub_uint32_t bootdev, biosdev, unit, slice, part; + grub_err_t err; + grub_size_t tag_buf_len = 0; auto int iterate_env (struct grub_env_var *var); int iterate_env (struct grub_env_var *var) { if ((!grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1)) && (var->name[sizeof("kFreeBSD.") - 1])) { - grub_strcpy (p, &var->name[sizeof("kFreeBSD.") - 1]); - p += grub_strlen (p); + grub_strcpy ((char *) p, &var->name[sizeof("kFreeBSD.") - 1]); + p += grub_strlen ((char *) p); *(p++) = '='; - grub_strcpy (p, var->value); - p += grub_strlen (p) + 1; + grub_strcpy ((char *) p, var->value); + p += grub_strlen ((char *) p) + 1; + } + + return 0; + } + + auto int iterate_env_count (struct grub_env_var *var); + int iterate_env_count (struct grub_env_var *var) + { + if ((!grub_memcmp (var->name, "kFreeBSD.", sizeof("kFreeBSD.") - 1)) && (var->name[sizeof("kFreeBSD.") - 1])) + { + p_size += grub_strlen (&var->name[sizeof("kFreeBSD.") - 1]); + p_size++; + p_size += grub_strlen (var->value) + 1; } return 0; @@ -461,41 +577,102 @@ grub_freebsd_boot (void) bi.boot_device = biosdev; - p = (char *) kern_end; + p_size = 0; + grub_env_iterate (iterate_env_count); + + if (p_size) + p_size = ALIGN_PAGE (kern_end + p_size + 1) - kern_end; + + if (is_elf_kernel) + { + struct bsd_tag *tag; + + err = grub_bsd_add_mmap (); + if (err) + return err; + + err = grub_bsd_add_meta (FREEBSD_MODINFO_END, 0, 0); + if (err) + return err; + + tag_buf_len = 0; + for (tag = tags; tag; tag = tag->next) + tag_buf_len = ALIGN_VAR (tag_buf_len + + sizeof (struct freebsd_tag_header) + + tag->len); + p_size = ALIGN_PAGE (kern_end + p_size + tag_buf_len) - kern_end; + } + + if (is_64bit) + p_size += 4096 * 3; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + kern_end, p_size); + if (err) + return err; + p = get_virtual_current_address (ch); + } + p_target = kern_end; + p0 = p; + kern_end += p_size; grub_env_iterate (iterate_env); - if (p != (char *) kern_end) + if (p != p0) { *(p++) = 0; - bi.environment = kern_end; - kern_end = ALIGN_PAGE ((grub_uint32_t) p); + bi.environment = p_target; } if (is_elf_kernel) { - grub_addr_t md_ofs; - int ofs; + grub_uint8_t *p_tag = p; + struct bsd_tag *tag; + + for (tag = tags; tag; tag = tag->next) + { + struct freebsd_tag_header *head + = (struct freebsd_tag_header *) p_tag; + head->type = tag->type; + head->len = tag->len; + p_tag += sizeof (struct freebsd_tag_header); + switch (tag->type) + { + case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_HOWTO: + if (is_64bit) + *(grub_uint64_t *) p_tag = bootflags; + else + *(grub_uint32_t *) p_tag = bootflags; + break; - if (grub_freebsd_add_meta (FREEBSD_MODINFO_END, 0, 0)) - return grub_errno; + case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ENVP: + if (is_64bit) + *(grub_uint64_t *) p_tag = bi.environment; + else + *(grub_uint32_t *) p_tag = bi.environment; + break; - grub_memcpy ((char *) kern_end, mod_buf, mod_buf_len); - bi.tags = kern_end; + case FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_KERNEND: + if (is_64bit) + *(grub_uint64_t *) p_tag = kern_end; + else + *(grub_uint32_t *) p_tag = kern_end; + break; - kern_end = ALIGN_PAGE (kern_end + mod_buf_len); + default: + grub_memcpy (p_tag, tag->data, tag->len); + break; + } + p_tag += tag->len; + p_tag = ALIGN_VAR (p_tag - p) + p; + } - if (is_64bit) - kern_end += 4096 * 4; + bi.tags = (p - p0) + p_target; - md_ofs = bi.tags + kern_end_mdofs; - ofs = (is_64bit) ? 16 : 12; - *((grub_uint32_t *) md_ofs) = kern_end; - md_ofs -= ofs; - *((grub_uint32_t *) md_ofs) = bi.environment; - md_ofs -= ofs; - *((grub_uint32_t *) md_ofs) = bootflags; + p = (ALIGN_PAGE ((p_tag - p0) + p_target) - p_target) + p0; } bi.kern_end = kern_end; @@ -504,53 +681,82 @@ grub_freebsd_boot (void) if (is_64bit) { - grub_uint32_t *gdt; - grub_uint8_t *trampoline; - void (*launch_trampoline) (grub_addr_t entry_lo, ...) - __attribute__ ((cdecl, regparm (0))); + struct grub_relocator64_state state; grub_uint8_t *pagetable; + grub_uint32_t *stack; + grub_addr_t stack_target; - struct gdt_descriptor *gdtdesc; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + 0x10000, 0x90000, + 3 * sizeof (grub_uint32_t) + + sizeof (bi), 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + stack = get_virtual_current_address (ch); + stack_target = get_physical_target_address (ch); + } - pagetable = (grub_uint8_t *) (kern_end - 16384); - fill_bsd64_pagetable (pagetable); +#ifdef GRUB_MACHINE_EFI + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; +#endif - /* Create GDT. */ - gdt = (grub_uint32_t *) (kern_end - 4096); - gdt[0] = 0; - gdt[1] = 0; - gdt[2] = 0; - gdt[3] = 0x00209800; - gdt[4] = 0; - gdt[5] = 0x00008000; + pagetable = p; + fill_bsd64_pagetable (pagetable, (pagetable - p0) + p_target); - /* Create GDT descriptor. */ - gdtdesc = (struct gdt_descriptor *) (kern_end - 4096 + 24); - gdtdesc->limit = 24; - gdtdesc->base = gdt; + state.cr3 = (pagetable - p0) + p_target; + state.rsp = stack_target; + state.rip = (((grub_uint64_t) entry_hi) << 32) | entry; - /* Prepare trampoline. */ - trampoline = (grub_uint8_t *) (kern_end - 4096 + 24 - + sizeof (struct gdt_descriptor)); - launch_trampoline = (void __attribute__ ((cdecl, regparm (0))) - (*) (grub_addr_t entry_lo, ...)) trampoline; - grub_bsd64_trampoline_gdt = (grub_uint32_t) gdtdesc; - grub_bsd64_trampoline_selfjump - = (grub_uint32_t) (trampoline + 6 - + ((grub_uint8_t *) &grub_bsd64_trampoline_selfjump - - &grub_bsd64_trampoline_start)); - - /* Copy trampoline. */ - grub_memcpy (trampoline, &grub_bsd64_trampoline_start, - &grub_bsd64_trampoline_end - &grub_bsd64_trampoline_start); - - /* Launch trampoline. */ - launch_trampoline (entry, entry_hi, pagetable, bi.tags, - kern_end); + stack[0] = entry; + stack[1] = bi.tags; + stack[2] = kern_end; + return grub_relocator64_boot (relocator, state, 0, 0x40000000); } else - grub_unix_real_boot (entry, bootflags | FREEBSD_RB_BOOTINFO, bootdev, - 0, 0, 0, &bi, bi.tags, kern_end); + { + struct grub_relocator32_state state; + grub_uint32_t *stack; + grub_addr_t stack_target; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + 0x10000, 0x90000, + 9 * sizeof (grub_uint32_t) + + sizeof (bi), 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + stack = get_virtual_current_address (ch); + stack_target = get_physical_target_address (ch); + } + +#ifdef GRUB_MACHINE_EFI + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; +#endif + + grub_memcpy (&stack[9], &bi, sizeof (bi)); + state.eip = entry; + state.esp = stack_target; + state.ebp = stack_target; + stack[0] = entry; /* "Return" address. */ + stack[1] = bootflags | FREEBSD_RB_BOOTINFO; + stack[2] = bootdev; + stack[3] = 0; + stack[4] = 0; + stack[5] = 0; + stack[6] = stack_target + 9 * sizeof (grub_uint32_t); + stack[7] = bi.tags; + stack[8] = kern_end; + return grub_relocator32_boot (relocator, state); + } /* Not reached. */ return GRUB_ERR_NONE; @@ -559,180 +765,316 @@ grub_freebsd_boot (void) static grub_err_t grub_openbsd_boot (void) { - char *buf = (char *) GRUB_BSD_TEMP_BUFFER; - struct grub_openbsd_bios_mmap *pm; - struct grub_openbsd_bootargs *pa; + grub_uint32_t *stack; + struct grub_relocator32_state state; + void *curarg, *buf0, *arg0; + grub_addr_t buf_target; + grub_err_t err; + grub_size_t tag_buf_len; - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) - { - pm->addr = addr; - pm->len = size; + err = grub_bsd_add_mmap (); + if (err) + return err; - switch (type) - { - case GRUB_MACHINE_MEMORY_AVAILABLE: - pm->type = OPENBSD_MMAP_AVAILABLE; - break; + { + struct bsd_tag *tag; + tag_buf_len = 0; + for (tag = tags; tag; tag = tag->next) + tag_buf_len = ALIGN_VAR (tag_buf_len + + sizeof (struct grub_openbsd_bootargs) + + tag->len); + } - case GRUB_MACHINE_MEMORY_ACPI: - pm->type = OPENBSD_MMAP_ACPI; - break; + buf_target = GRUB_BSD_TEMP_BUFFER - 9 * sizeof (grub_uint32_t); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, buf_target, + tag_buf_len + + sizeof (struct grub_openbsd_bootargs) + + 9 * sizeof (grub_uint32_t)); + if (err) + return err; + buf0 = get_virtual_current_address (ch); + } - case GRUB_MACHINE_MEMORY_NVS: - pm->type = OPENBSD_MMAP_NVS; - break; + stack = (grub_uint32_t *) buf0; + arg0 = curarg = stack + 9; - default: - pm->type = OPENBSD_MMAP_RESERVED; - break; - } - pm++; + { + struct bsd_tag *tag; + struct grub_openbsd_bootargs *head; - return 0; - } - - pa = (struct grub_openbsd_bootargs *) buf; - - pa->ba_type = OPENBSD_BOOTARG_MMAP; - pm = (struct grub_openbsd_bios_mmap *) (pa + 1); - grub_mmap_iterate (hook); - - /* Memory map terminator. */ - pm->addr = 0; - pm->len = 0; - pm->type = 0; - pm++; - - pa->ba_size = (char *) pm - (char *) pa; - pa->ba_next = (struct grub_openbsd_bootargs *) pm; - pa = pa->ba_next; - pa->ba_type = OPENBSD_BOOTARG_END; - pa++; + for (tag = tags; tag; tag = tag->next) + { + head = curarg; + head->ba_type = tag->type; + head->ba_size = tag->len + sizeof (*head); + curarg = head + 1; + grub_memcpy (curarg, tag->data, tag->len); + curarg = (grub_uint8_t *) curarg + tag->len; + head->ba_next = (grub_uint8_t *) curarg - (grub_uint8_t *) buf0 + + buf_target; + } + head = curarg; + head->ba_type = OPENBSD_BOOTARG_END; + head->ba_size = 0; + head->ba_next = 0; + } grub_video_set_mode ("text", 0, 0); - grub_unix_real_boot (entry, bootflags, openbsd_root, OPENBSD_BOOTARG_APIVER, - 0, (grub_uint32_t) (grub_mmap_get_upper () >> 10), - (grub_uint32_t) (grub_mmap_get_lower () >> 10), - (char *) pa - buf, buf); +#ifdef GRUB_MACHINE_EFI + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; +#endif - /* Not reached. */ - return GRUB_ERR_NONE; + state.eip = entry; + state.ebp = state.esp + = ((grub_uint8_t *) stack - (grub_uint8_t *) buf0) + buf_target; + stack[0] = entry; + stack[1] = bootflags; + stack[2] = openbsd_root; + stack[3] = OPENBSD_BOOTARG_APIVER; + stack[4] = 0; + stack[5] = grub_mmap_get_upper () >> 10; + stack[6] = grub_mmap_get_lower () >> 10; + stack[7] = (grub_uint8_t *) curarg - (grub_uint8_t *) arg0; + stack[8] = ((grub_uint8_t *) arg0 - (grub_uint8_t *) buf0) + buf_target; + + return grub_relocator32_boot (relocator, state); +} + +static grub_err_t +grub_netbsd_setup_video (void) +{ + struct grub_video_mode_info mode_info; + void *framebuffer; + const char *modevar; + struct grub_netbsd_btinfo_framebuf params; + grub_err_t err; + grub_video_driver_id_t driv_id; + + modevar = grub_env_get ("gfxpayload"); + + /* Now all graphical modes are acceptable. + May change in future if we have modes without framebuffer. */ + if (modevar && *modevar != 0) + { + char *tmp; + tmp = grub_xasprintf ("%s;" NETBSD_DEFAULT_VIDEO_MODE, modevar); + if (! tmp) + return grub_errno; + err = grub_video_set_mode (tmp, 0, 0); + grub_free (tmp); + } + else + err = grub_video_set_mode (NETBSD_DEFAULT_VIDEO_MODE, 0, 0); + + if (err) + return err; + + driv_id = grub_video_get_driver_id (); + if (driv_id == GRUB_VIDEO_DRIVER_NONE) + return GRUB_ERR_NONE; + + err = grub_video_get_info_and_fini (&mode_info, &framebuffer); + + if (err) + return err; + + params.width = mode_info.width; + params.height = mode_info.height; + params.bpp = mode_info.bpp; + params.pitch = mode_info.pitch; + params.flags = 0; + + params.fbaddr = (grub_addr_t) framebuffer; + + params.red_mask_size = mode_info.red_mask_size; + params.red_field_pos = mode_info.red_field_pos; + params.green_mask_size = mode_info.green_mask_size; + params.green_field_pos = mode_info.green_field_pos; + params.blue_mask_size = mode_info.blue_mask_size; + params.blue_field_pos = mode_info.blue_field_pos; + +#ifdef GRUB_MACHINE_PCBIOS + /* VESA packed modes may come with zeroed mask sizes, which need + to be set here according to DAC Palette width. If we don't, + this results in Linux displaying a black screen. */ + if (mode_info.bpp <= 8 && driv_id == GRUB_VIDEO_DRIVER_VBE) + { + struct grub_vbe_info_block controller_info; + int status; + int width = 8; + + status = grub_vbe_bios_get_controller_info (&controller_info); + + if (status == GRUB_VBE_STATUS_OK && + (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH)) + status = grub_vbe_bios_set_dac_palette_width (&width); + + if (status != GRUB_VBE_STATUS_OK) + /* 6 is default after mode reset. */ + width = 6; + + params.red_mask_size = params.green_mask_size + = params.blue_mask_size = width; + } +#endif + + err = grub_bsd_add_meta (NETBSD_BTINFO_FRAMEBUF, ¶ms, sizeof (params)); + return err; +} + +static grub_err_t +grub_netbsd_add_modules (void) +{ + struct netbsd_module *mod; + unsigned modcnt = 0; + struct grub_netbsd_btinfo_modules *mods; + unsigned i; + grub_err_t err; + + for (mod = netbsd_mods; mod; mod = mod->next) + modcnt++; + + mods = grub_malloc (sizeof (*mods) + sizeof (mods->mods[0]) * modcnt); + if (!mods) + return grub_errno; + + mods->num = modcnt; + mods->last_addr = kern_end; + for (mod = netbsd_mods, i = 0; mod; i++, mod = mod->next) + mods->mods[i] = mod->mod; + + err = grub_bsd_add_meta (NETBSD_BTINFO_MODULES, mods, + sizeof (*mods) + sizeof (mods->mods[0]) * modcnt); + grub_free (mods); + return err; } static grub_err_t grub_netbsd_boot (void) { struct grub_netbsd_bootinfo *bootinfo; - int count = 0; - struct grub_netbsd_btinfo_mmap_header *mmap; - struct grub_netbsd_btinfo_mmap_entry *pm; - void *curarg; + void *curarg, *arg0; + grub_addr_t arg_target, stack_target; + grub_uint32_t *stack; + grub_err_t err; + struct grub_relocator32_state state; + grub_size_t tag_buf_len = 0; + int tag_count = 0; + + err = grub_bsd_add_mmap (); + if (err) + return err; + + err = grub_netbsd_setup_video (); + if (err) + { + grub_print_error (); + grub_printf ("Booting however\n"); + grub_errno = GRUB_ERR_NONE; + } + + err = grub_netbsd_add_modules (); + if (err) + return err; - auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)), - grub_uint64_t size __attribute__ ((unused)), - grub_uint32_t type __attribute__ ((unused))) { - count++; - return 0; - } - - auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) - { - pm->addr = addr; - pm->len = size; - - switch (type) + struct bsd_tag *tag; + tag_buf_len = 0; + for (tag = tags; tag; tag = tag->next) { - case GRUB_MACHINE_MEMORY_AVAILABLE: - pm->type = NETBSD_MMAP_AVAILABLE; - break; - - case GRUB_MACHINE_MEMORY_ACPI: - pm->type = NETBSD_MMAP_ACPI; - break; - - case GRUB_MACHINE_MEMORY_NVS: - pm->type = NETBSD_MMAP_NVS; - break; - - default: - pm->type = NETBSD_MMAP_RESERVED; - break; + tag_buf_len = ALIGN_VAR (tag_buf_len + + sizeof (struct grub_netbsd_btinfo_common) + + tag->len); + tag_count++; } - pm++; - - return 0; } - grub_mmap_iterate (count_hook); + arg_target = kern_end; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + arg_target, tag_buf_len + + sizeof (struct grub_netbsd_bootinfo) + + tag_count * sizeof (grub_uint32_t)); + if (err) + return err; + curarg = get_virtual_current_address (ch); + } - if (kern_end + sizeof (struct grub_netbsd_btinfo_rootdevice) - + sizeof (struct grub_netbsd_bootinfo) - + sizeof (struct grub_netbsd_btinfo_mmap_header) - + count * sizeof (struct grub_netbsd_btinfo_mmap_entry) - > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory"); + arg0 = curarg; + bootinfo = (void *) ((grub_uint8_t *) arg0 + tag_buf_len); - curarg = mmap = (struct grub_netbsd_btinfo_mmap_header *) kern_end; - pm = (struct grub_netbsd_btinfo_mmap_entry *) (mmap + 1); + { + struct bsd_tag *tag; + unsigned i; - grub_mmap_iterate (fill_hook); - mmap->common.type = NETBSD_BTINFO_MEMMAP; - mmap->common.len = (char *) pm - (char *) mmap; - mmap->count = count; - curarg = pm; + bootinfo->bi_count = tag_count; + for (tag = tags, i = 0; tag; i++, tag = tag->next) + { + struct grub_netbsd_btinfo_common *head = curarg; + bootinfo->bi_data[i] = ((grub_uint8_t *) curarg - (grub_uint8_t *) arg0) + + arg_target; + head->type = tag->type; + head->len = tag->len + sizeof (*head); + curarg = head + 1; + grub_memcpy (curarg, tag->data, tag->len); + curarg = (grub_uint8_t *) curarg + tag->len; + } + } - if (netbsd_root) - { - struct grub_netbsd_btinfo_rootdevice *rootdev; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, 0x10000, 0x90000, + 7 * sizeof (grub_uint32_t), 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + stack = get_virtual_current_address (ch); + stack_target = get_physical_target_address (ch); + } - rootdev = (struct grub_netbsd_btinfo_rootdevice *) curarg; +#ifdef GRUB_MACHINE_EFI + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; +#endif - rootdev->common.len = sizeof (struct grub_netbsd_btinfo_rootdevice); - rootdev->common.type = NETBSD_BTINFO_ROOTDEVICE; - grub_strncpy (rootdev->devname, netbsd_root, sizeof (rootdev->devname)); + state.eip = entry; + state.esp = stack_target; + state.ebp = stack_target; + stack[0] = entry; + stack[1] = bootflags; + stack[2] = 0; + stack[3] = ((grub_uint8_t *) bootinfo - (grub_uint8_t *) arg0) + arg_target; + stack[4] = 0; + stack[5] = grub_mmap_get_upper () >> 10; + stack[6] = grub_mmap_get_lower () >> 10; - bootinfo = (struct grub_netbsd_bootinfo *) (rootdev + 1); - bootinfo->bi_count = 2; - bootinfo->bi_data[0] = mmap; - bootinfo->bi_data[1] = rootdev; - } - else - { - bootinfo = (struct grub_netbsd_bootinfo *) curarg; - bootinfo->bi_count = 1; - bootinfo->bi_data[0] = mmap; - } - - grub_video_set_mode ("text", 0, 0); - - grub_unix_real_boot (entry, bootflags, 0, bootinfo, - 0, (grub_uint32_t) (grub_mmap_get_upper () >> 10), - (grub_uint32_t) (grub_mmap_get_lower () >> 10)); - - /* Not reached. */ - return GRUB_ERR_NONE; + return grub_relocator32_boot (relocator, state); } static grub_err_t grub_bsd_unload (void) { - if (mod_buf) + struct bsd_tag *tag, *next; + for (tag = tags; tag; tag = next) { - grub_free (mod_buf); - mod_buf = 0; - mod_buf_max = 0; + next = tag->next; + grub_free (tag); } + tags = NULL; + tags_last = NULL; kernel_type = KERNEL_TYPE_NONE; grub_dl_unref (my_mod); - grub_free (netbsd_root); - netbsd_root = NULL; + grub_relocator_unload (relocator); + relocator = NULL; return GRUB_ERR_NONE; } @@ -740,9 +1082,11 @@ grub_bsd_unload (void) static grub_err_t grub_bsd_load_aout (grub_file_t file) { - grub_addr_t load_addr, bss_end_addr; + grub_addr_t load_addr, load_end; int ofs, align_page; union grub_aout_header ah; + grub_err_t err; + grub_size_t bss_size; if ((grub_file_seek (file, 0)) == (grub_off_t) - 1) return grub_errno; @@ -772,7 +1116,7 @@ grub_bsd_load_aout (grub_file_t file) return grub_error (GRUB_ERR_BAD_OS, "load address below 1M"); kern_start = load_addr; - kern_end = load_addr + ah.aout32.a_text + ah.aout32.a_data; + load_end = kern_end = load_addr + ah.aout32.a_text + ah.aout32.a_data; if (align_page) kern_end = ALIGN_PAGE (kern_end); @@ -782,13 +1126,45 @@ grub_bsd_load_aout (grub_file_t file) if (align_page) kern_end = ALIGN_PAGE (kern_end); - bss_end_addr = kern_end; + bss_size = kern_end - load_end; } else - bss_end_addr = 0; + bss_size = 0; - return grub_aout_load (file, ofs, load_addr, - ah.aout32.a_text + ah.aout32.a_data, bss_end_addr); + { + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + kern_start, kern_end - kern_start); + if (err) + return err; + kern_chunk_src = get_virtual_current_address (ch); + } + + return grub_aout_load (file, ofs, kern_chunk_src, + ah.aout32.a_text + ah.aout32.a_data, + bss_size); +} + +static int NESTED_FUNC_ATTR +grub_bsd_elf32_size_hook (grub_elf_t elf __attribute__ ((unused)), + Elf32_Phdr *phdr, void *arg __attribute__ ((unused))) +{ + Elf32_Addr paddr; + + if (phdr->p_type != PT_LOAD + && phdr->p_type != PT_DYNAMIC) + return 0; + + paddr = phdr->p_paddr & 0xFFFFFF; + + if (paddr < kern_start) + kern_start = paddr; + + if (paddr + phdr->p_memsz > kern_end) + kern_end = paddr + phdr->p_memsz; + + return 0; } static grub_err_t @@ -807,20 +1183,30 @@ grub_bsd_elf32_hook (Elf32_Phdr * phdr, grub_addr_t * addr, int *do_load) phdr->p_paddr &= 0xFFFFFF; paddr = phdr->p_paddr; - if ((paddr < grub_os_area_addr) - || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "address 0x%x is out of range", - paddr); + *addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src); - if ((!kern_start) || (paddr < kern_start)) + return GRUB_ERR_NONE; +} + +static int NESTED_FUNC_ATTR +grub_bsd_elf64_size_hook (grub_elf_t elf __attribute__ ((unused)), + Elf64_Phdr *phdr, void *arg __attribute__ ((unused))) +{ + Elf64_Addr paddr; + + if (phdr->p_type != PT_LOAD + && phdr->p_type != PT_DYNAMIC) + return 0; + + paddr = phdr->p_paddr & 0xffffff; + + if (paddr < kern_start) kern_start = paddr; if (paddr + phdr->p_memsz > kern_end) kern_end = paddr + phdr->p_memsz; - *addr = paddr; - - return GRUB_ERR_NONE; + return 0; } static grub_err_t @@ -838,18 +1224,7 @@ grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr, int *do_load) *do_load = 1; paddr = phdr->p_paddr & 0xffffff; - if ((paddr < grub_os_area_addr) - || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) - return grub_error (GRUB_ERR_OUT_OF_RANGE, "address 0x%x is out of range", - paddr); - - if ((!kern_start) || (paddr < kern_start)) - kern_start = paddr; - - if (paddr + phdr->p_memsz > kern_end) - kern_end = paddr + phdr->p_memsz; - - *addr = paddr; + *addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src); return GRUB_ERR_NONE; } @@ -857,12 +1232,33 @@ grub_bsd_elf64_hook (Elf64_Phdr * phdr, grub_addr_t * addr, int *do_load) static grub_err_t grub_bsd_load_elf (grub_elf_t elf) { - kern_start = kern_end = 0; + grub_err_t err; + + kern_end = 0; + kern_start = ~0; if (grub_elf_is_elf32 (elf)) { + grub_relocator_chunk_t ch; + entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF; - return grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); + err = grub_elf32_phdr_iterate (elf, grub_bsd_elf32_size_hook, NULL); + if (err) + return err; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + kern_start, kern_end - kern_start); + if (err) + return err; + + kern_chunk_src = get_virtual_current_address (ch); + + err = grub_elf32_load (elf, grub_bsd_elf32_hook, 0, 0); + if (err) + return err; + if (kernel_type != KERNEL_TYPE_OPENBSD) + return GRUB_ERR_NONE; + return grub_openbsd_find_ramdisk32 (elf->file, kern_start, + kern_chunk_src, &openbsd_ramdisk); } else if (grub_elf_is_elf64 (elf)) { @@ -882,7 +1278,30 @@ grub_bsd_load_elf (grub_elf_t elf) entry = elf->ehdr.ehdr64.e_entry & 0x0fffffff; entry_hi = 0; } - return grub_elf64_load (elf, grub_bsd_elf64_hook, 0, 0); + + err = grub_elf64_phdr_iterate (elf, grub_bsd_elf64_size_hook, NULL); + if (err) + return err; + + grub_dprintf ("bsd", "kern_start = %lx, kern_end = %lx\n", + (unsigned long) kern_start, (unsigned long) kern_end); + { + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, + kern_end - kern_start); + if (err) + return err; + kern_chunk_src = get_virtual_current_address (ch); + } + + err = grub_elf64_load (elf, grub_bsd_elf64_hook, 0, 0); + if (err) + return err; + if (kernel_type != KERNEL_TYPE_OPENBSD) + return GRUB_ERR_NONE; + return grub_openbsd_find_ramdisk64 (elf->file, kern_start, + kern_chunk_src, &openbsd_ramdisk); } else return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); @@ -898,16 +1317,20 @@ grub_bsd_load (int argc, char *argv[]) grub_loader_unset (); + grub_memset (&openbsd_ramdisk, 0, sizeof (openbsd_ramdisk)); + if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); goto fail; } - file = grub_gzfile_open (argv[0], 1); + file = grub_file_open (argv[0]); if (!file) goto fail; + relocator = grub_relocator_new (); + elf = grub_elf_file (file); if (elf) { @@ -923,6 +1346,8 @@ grub_bsd_load (int argc, char *argv[]) grub_file_close (file); } + kern_end = ALIGN_PAGE (kern_end); + fail: if (grub_errno != GRUB_ERR_NONE) @@ -946,10 +1371,10 @@ grub_bsd_parse_flags (const struct grub_arg_list *state, } static grub_err_t -grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[]) +grub_cmd_freebsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) { kernel_type = KERNEL_TYPE_FREEBSD; - bootflags = grub_bsd_parse_flags (cmd->state, freebsd_flags); + bootflags = grub_bsd_parse_flags (ctxt->state, freebsd_flags); if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) { @@ -970,55 +1395,49 @@ grub_cmd_freebsd (grub_extcmd_t cmd, int argc, char *argv[]) if (err) return err; - file = grub_gzfile_open (argv[0], 1); + file = grub_file_open (argv[0]); if (! file) return grub_errno; if (is_64bit) - err = grub_freebsd_load_elf_meta64 (file, &kern_end); + err = grub_freebsd_load_elf_meta64 (relocator, file, &kern_end); else - err = grub_freebsd_load_elf_meta32 (file, &kern_end); + err = grub_freebsd_load_elf_meta32 (relocator, file, &kern_end); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_HOWTO, &data, 4); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_HOWTO, &data, 4); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | FREEBSD_MODINFOMD_ENVP, &data, len); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_KERNEND, &data, len); - if (err) - return err; - - kern_end_mdofs = mod_buf_len - len; - - err = grub_freebsd_add_mmap (); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_KERNEND, &data, len); if (err) return err; } - grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 1); + grub_loader_set (grub_freebsd_boot, grub_bsd_unload, 0); } return grub_errno; } static grub_err_t -grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[]) +grub_cmd_openbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) { grub_uint32_t bootdev; kernel_type = KERNEL_TYPE_OPENBSD; - bootflags = grub_bsd_parse_flags (cmd->state, openbsd_flags); + bootflags = grub_bsd_parse_flags (ctxt->state, openbsd_flags); - if (cmd->state[OPENBSD_ROOT_ARG].set) + if (ctxt->state[OPENBSD_ROOT_ARG].set) { - const char *arg = cmd->state[OPENBSD_ROOT_ARG].arg; + const char *arg = ctxt->state[OPENBSD_ROOT_ARG].arg; int unit, part; if (*(arg++) != 'w' || *(arg++) != 'd') return grub_error (GRUB_ERR_BAD_ARGUMENT, @@ -1039,9 +1458,54 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[]) else bootdev = 0; + if (ctxt->state[OPENBSD_SERIAL_ARG].set) + { + struct grub_openbsd_bootarg_console serial; + char *ptr; + unsigned port = 0; + unsigned speed = 9600; + + grub_memset (&serial, 0, sizeof (serial)); + + if (ctxt->state[OPENBSD_SERIAL_ARG].arg) + { + ptr = ctxt->state[OPENBSD_SERIAL_ARG].arg; + if (grub_memcmp (ptr, "com", sizeof ("com") - 1) != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "only com0-com3 are supported"); + ptr += sizeof ("com") - 1; + port = grub_strtoul (ptr, &ptr, 0); + if (port >= 4) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "only com0-com3 are supported"); + if (*ptr == ',') + { + ptr++; + speed = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + } + } + + serial.device = (GRUB_OPENBSD_COM_MAJOR << 8) | port; + serial.speed = speed; + + grub_bsd_add_meta (OPENBSD_BOOTARG_CONSOLE, &serial, sizeof (serial)); + bootflags |= OPENBSD_RB_SERCONS; + } + else + { + struct grub_openbsd_bootarg_console serial; + + grub_memset (&serial, 0, sizeof (serial)); + serial.device = (GRUB_OPENBSD_VGA_MAJOR << 8); + grub_bsd_add_meta (OPENBSD_BOOTARG_CONSOLE, &serial, sizeof (serial)); + bootflags &= ~OPENBSD_RB_SERCONS; + } + if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) { - grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 1); + grub_loader_set (grub_openbsd_boot, grub_bsd_unload, 0); openbsd_root = bootdev; } @@ -1049,16 +1513,95 @@ grub_cmd_openbsd (grub_extcmd_t cmd, int argc, char *argv[]) } static grub_err_t -grub_cmd_netbsd (grub_extcmd_t cmd, int argc, char *argv[]) +grub_cmd_netbsd (grub_extcmd_context_t ctxt, int argc, char *argv[]) { + grub_err_t err; kernel_type = KERNEL_TYPE_NETBSD; - bootflags = grub_bsd_parse_flags (cmd->state, netbsd_flags); + bootflags = grub_bsd_parse_flags (ctxt->state, netbsd_flags); if (grub_bsd_load (argc, argv) == GRUB_ERR_NONE) { - grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 1); - if (cmd->state[NETBSD_ROOT_ARG].set) - netbsd_root = grub_strdup (cmd->state[NETBSD_ROOT_ARG].arg); + if (is_elf_kernel) + { + grub_file_t file; + + file = grub_file_open (argv[0]); + if (! file) + return grub_errno; + + if (is_64bit) + err = grub_netbsd_load_elf_meta64 (relocator, file, &kern_end); + else + err = grub_netbsd_load_elf_meta32 (relocator, file, &kern_end); + if (err) + return err; + } + + { + char bootpath[GRUB_NETBSD_MAX_BOOTPATH_LEN]; + char *name; + name = grub_strrchr (argv[0], '/'); + if (name) + name++; + else + name = argv[0]; + grub_memset (bootpath, 0, sizeof (bootpath)); + grub_strncpy (bootpath, name, sizeof (bootpath) - 1); + grub_bsd_add_meta (NETBSD_BTINFO_BOOTPATH, bootpath, sizeof (bootpath)); + } + + if (ctxt->state[NETBSD_ROOT_ARG].set) + { + char root[GRUB_NETBSD_MAX_ROOTDEVICE_LEN]; + grub_memset (root, 0, sizeof (root)); + grub_strncpy (root, ctxt->state[NETBSD_ROOT_ARG].arg, + sizeof (root) - 1); + grub_bsd_add_meta (NETBSD_BTINFO_ROOTDEVICE, root, sizeof (root)); + } + if (ctxt->state[NETBSD_SERIAL_ARG].set) + { + struct grub_netbsd_btinfo_serial serial; + char *ptr; + + grub_memset (&serial, 0, sizeof (serial)); + grub_strcpy (serial.devname, "com"); + + if (ctxt->state[NETBSD_SERIAL_ARG].arg) + { + ptr = ctxt->state[NETBSD_SERIAL_ARG].arg; + if (grub_memcmp (ptr, "com", sizeof ("com") - 1) == 0) + { + ptr += sizeof ("com") - 1; + serial.addr + = grub_ns8250_hw_get_port (grub_strtoul (ptr, &ptr, 0)); + } + else + serial.addr = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + + if (*ptr == ',') + { + ptr++; + serial.speed = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + return grub_errno; + } + } + + grub_bsd_add_meta (NETBSD_BTINFO_CONSOLE, &serial, sizeof (serial)); + } + else + { + struct grub_netbsd_btinfo_serial cons; + + grub_memset (&cons, 0, sizeof (cons)); + grub_strcpy (cons.devname, "pc"); + + grub_bsd_add_meta (NETBSD_BTINFO_CONSOLE, &cons, sizeof (cons)); + } + + grub_loader_set (grub_netbsd_boot, grub_bsd_unload, 0); } return grub_errno; @@ -1086,7 +1629,7 @@ grub_cmd_freebsd_loadenv (grub_command_t cmd __attribute__ ((unused)), goto fail; } - file = grub_gzfile_open (argv[0], 1); + file = grub_file_open (argv[0]); if ((!file) || (!file->size)) goto fail; @@ -1167,18 +1710,14 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; - grub_err_t err; int modargc; char **modargv; char *type; - - if (kernel_type == KERNEL_TYPE_NONE) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "you need to load the kernel first"); + grub_err_t err; + void *src; if (kernel_type != KERNEL_TYPE_FREEBSD) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "only FreeBSD supports module"); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no FreeBSD loaded"); if (!is_elf_kernel) return grub_error (GRUB_ERR_BAD_ARGUMENT, @@ -1191,17 +1730,21 @@ grub_cmd_freebsd_module (grub_command_t cmd __attribute__ ((unused)), return 0; } - file = grub_gzfile_open (argv[0], 1); + file = grub_file_open (argv[0]); if ((!file) || (!file->size)) goto fail; - if (kern_end + file->size > grub_os_area_addr + grub_os_area_size) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "not enough memory for the module"); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_end, + file->size); + if (err) goto fail; - } + src = get_virtual_current_address (ch); + } - grub_file_read (file, (void *) kern_end, file->size); + + grub_file_read (file, src, file->size); if (grub_errno) goto fail; @@ -1231,6 +1774,73 @@ fail: return grub_errno; } +static grub_err_t +grub_netbsd_module_load (char *filename, grub_uint32_t type) +{ + grub_file_t file = 0; + void *src; + grub_err_t err; + + file = grub_file_open (filename); + if ((!file) || (!file->size)) + goto fail; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_end, + file->size); + if (err) + goto fail; + + src = get_virtual_current_address (ch); + } + + grub_file_read (file, src, file->size); + if (grub_errno) + goto fail; + + err = grub_netbsd_add_meta_module (filename, type, kern_end, file->size); + + if (err) + goto fail; + + kern_end = ALIGN_PAGE (kern_end + file->size); + +fail: + if (file) + grub_file_close (file); + + return grub_errno; +} + +static grub_err_t +grub_cmd_netbsd_module (grub_command_t cmd, + int argc, char *argv[]) +{ + grub_uint32_t type; + + if (kernel_type != KERNEL_TYPE_NETBSD) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no NetBSD loaded"); + + if (!is_elf_kernel) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "only ELF kernel supports module"); + + /* List the current modules if no parameter. */ + if (!argc) + { + grub_netbsd_list_modules (); + return 0; + } + + if (grub_strcmp (cmd->name, "knetbsd_module_elf") == 0) + type = GRUB_NETBSD_MODULE_ELF; + else + type = GRUB_NETBSD_MODULE_RAW; + + return grub_netbsd_module_load (argv[0], type); +} + static grub_err_t grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) @@ -1257,7 +1867,7 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)), return 0; } - file = grub_gzfile_open (argv[0], 1); + file = grub_file_open (argv[0]); if (!file) return grub_errno; if (!file->size) @@ -1267,21 +1877,71 @@ grub_cmd_freebsd_module_elf (grub_command_t cmd __attribute__ ((unused)), } if (is_64bit) - err = grub_freebsd_load_elfmodule_obj64 (file, argc, argv, &kern_end); + err = grub_freebsd_load_elfmodule_obj64 (relocator, file, + argc, argv, &kern_end); else - err = grub_freebsd_load_elfmodule32 (file, argc, argv, &kern_end); + err = grub_freebsd_load_elfmodule32 (relocator, file, + argc, argv, &kern_end); grub_file_close (file); return err; } +static grub_err_t +grub_cmd_openbsd_ramdisk (grub_command_t cmd __attribute__ ((unused)), + int argc, char *args[]) +{ + grub_file_t file; + grub_size_t size; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + if (kernel_type != KERNEL_TYPE_OPENBSD) + return grub_error (GRUB_ERR_BAD_OS, "no kOpenBSD loaded"); + + if (!openbsd_ramdisk.max_size) + return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD doesn't support ramdisk"); + + file = grub_file_open (args[0]); + if (! file) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + "couldn't load ramdisk"); + + size = grub_file_size (file); + + if (size > openbsd_ramdisk.max_size) + { + grub_file_close (file); + return grub_error (GRUB_ERR_BAD_OS, "your kOpenBSD supports ramdisk only" + " up to %u bytes, however you supplied a %u bytes one", + openbsd_ramdisk.max_size, size); + } + + if (grub_file_read (file, openbsd_ramdisk.target, size) + != (grub_ssize_t) (size)) + { + grub_file_close (file); + grub_error_push (); + return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); + } + grub_memset (openbsd_ramdisk.target + size, 0, + openbsd_ramdisk.max_size - size); + *openbsd_ramdisk.size = ALIGN_UP (size, 512); + + return GRUB_ERR_NONE; +} static grub_extcmd_t cmd_freebsd, cmd_openbsd, cmd_netbsd; static grub_command_t cmd_freebsd_loadenv, cmd_freebsd_module; -static grub_command_t cmd_freebsd_module_elf; +static grub_command_t cmd_netbsd_module, cmd_freebsd_module_elf; +static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk; GRUB_MOD_INIT (bsd) { + /* Net and OpenBSD kernels are often compressed. */ + grub_dl_load ("gzio"); + cmd_freebsd = grub_register_extcmd ("kfreebsd", grub_cmd_freebsd, GRUB_COMMAND_FLAG_BOTH, N_("FILE"), N_("Load kernel of FreeBSD."), @@ -1300,10 +1960,20 @@ GRUB_MOD_INIT (bsd) cmd_freebsd_module = grub_register_command ("kfreebsd_module", grub_cmd_freebsd_module, 0, N_("Load FreeBSD kernel module.")); + cmd_netbsd_module = + grub_register_command ("knetbsd_module", grub_cmd_netbsd_module, + 0, N_("Load NetBSD kernel module.")); + cmd_netbsd_module_elf = + grub_register_command ("knetbsd_module_elf", grub_cmd_netbsd_module, + 0, N_("Load NetBSD kernel module (ELF).")); cmd_freebsd_module_elf = grub_register_command ("kfreebsd_module_elf", grub_cmd_freebsd_module_elf, 0, N_("Load FreeBSD kernel module (ELF).")); + cmd_openbsd_ramdisk = grub_register_command ("kopenbsd_ramdisk", + grub_cmd_openbsd_ramdisk, 0, + "Load kOpenBSD ramdisk. "); + my_mod = mod; } @@ -1315,12 +1985,10 @@ GRUB_MOD_FINI (bsd) grub_unregister_command (cmd_freebsd_loadenv); grub_unregister_command (cmd_freebsd_module); + grub_unregister_command (cmd_netbsd_module); grub_unregister_command (cmd_freebsd_module_elf); + grub_unregister_command (cmd_netbsd_module_elf); + grub_unregister_command (cmd_openbsd_ramdisk); - if (mod_buf) - { - grub_free (mod_buf); - mod_buf = 0; - mod_buf_max = 0; - } + grub_bsd_unload (); } diff --git a/grub-core/loader/i386/bsdXX.c b/grub-core/loader/i386/bsdXX.c index cd5ba85dc..073f01da2 100644 --- a/grub-core/loader/i386/bsdXX.c +++ b/grub-core/loader/i386/bsdXX.c @@ -1,22 +1,18 @@ #include -#include +#include #include #include #include -#include +#include #define ALIGN_PAGE(a) ALIGN_UP (a, 4096) static inline grub_err_t load (grub_file_t file, void *where, grub_off_t off, grub_size_t size) { - if (PTR_TO_UINT32 (where) + size > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_RANGE, - "not enough memory for the module"); if (grub_file_seek (file, off) == (grub_off_t) -1) return grub_errno; - if (grub_file_read (file, where, size) - != (grub_ssize_t) size) + if (grub_file_read (file, where, size) != (grub_ssize_t) size) { if (grub_errno) return grub_errno; @@ -75,7 +71,8 @@ read_headers (grub_file_t file, Elf_Ehdr *e, char **shdr) platforms. So I keep both versions. */ #if OBJSYM grub_err_t -SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, +SUFFIX (grub_freebsd_load_elfmodule_obj) (struct grub_relocator *relocator, + grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end) { Elf_Ehdr e; @@ -83,6 +80,8 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, char *shdr = 0; grub_addr_t curload, module; grub_err_t err; + grub_size_t chunk_size = 0; + void *chunk_src; err = read_headers (file, &e, &shdr); if (err) @@ -90,6 +89,29 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, curload = module = ALIGN_PAGE (*kern_end); + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + { + if (s->sh_size == 0) + continue; + + if (s->sh_addralign) + chunk_size = ALIGN_UP (chunk_size + *kern_end, s->sh_addralign) + - *kern_end; + + chunk_size += s->sh_size; + } + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + module, chunk_size); + if (err) + return err; + chunk_src = get_virtual_current_address (ch); + } + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) @@ -109,15 +131,14 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, { default: case SHT_PROGBITS: - err = load (file, UINT_TO_PTR (curload), s->sh_offset, s->sh_size); + err = load (file, (grub_uint8_t *) chunk_src + curload - *kern_end, + s->sh_offset, s->sh_size); if (err) return err; break; case SHT_NOBITS: - if (curload + s->sh_size > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_RANGE, - "not enough memory for the module"); - grub_memset (UINT_TO_PTR (curload), 0, s->sh_size); + grub_memset ((grub_uint8_t *) chunk_src + curload - *kern_end, 0, + s->sh_size); break; } curload += s->sh_size; @@ -129,13 +150,13 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, argc - 1, argv + 1, module, curload - module); if (! err) - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA - | FREEBSD_MODINFOMD_ELFHDR, - &e, sizeof (e)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA + | FREEBSD_MODINFOMD_ELFHDR, + &e, sizeof (e)); if (! err) - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA - | FREEBSD_MODINFOMD_SHDR, - shdr, e.e_shnum * e.e_shentsize); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA + | FREEBSD_MODINFOMD_SHDR, + shdr, e.e_shnum * e.e_shentsize); return err; } @@ -143,7 +164,8 @@ SUFFIX (grub_freebsd_load_elfmodule_obj) (grub_file_t file, int argc, #else grub_err_t -SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], +SUFFIX (grub_freebsd_load_elfmodule) (struct grub_relocator *relocator, + grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end) { Elf_Ehdr e; @@ -151,6 +173,8 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], char *shdr = 0; grub_addr_t curload, module; grub_err_t err; + grub_size_t chunk_size = 0; + void *chunk_src; err = read_headers (file, &e, &shdr); if (err) @@ -158,6 +182,30 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], curload = module = ALIGN_PAGE (*kern_end); + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + { + if (s->sh_size == 0) + continue; + + if (! (s->sh_flags & SHF_ALLOC)) + continue; + if (chunk_size < s->sh_addr + s->sh_size) + chunk_size = s->sh_addr + s->sh_size; + } + + { + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + module, chunk_size); + if (err) + return err; + + chunk_src = get_virtual_current_address (ch); + } + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize); s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) @@ -176,17 +224,15 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], { default: case SHT_PROGBITS: - err = load (file, UINT_TO_PTR (module + s->sh_addr), + err = load (file, (grub_uint8_t *) chunk_src + module + + s->sh_addr - *kern_end, s->sh_offset, s->sh_size); if (err) return err; break; case SHT_NOBITS: - if (module + s->sh_addr + s->sh_size - > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_RANGE, - "not enough memory for the module"); - grub_memset (UINT_TO_PTR (module + s->sh_addr), 0, s->sh_size); + grub_memset ((grub_uint8_t *) chunk_src + module + + s->sh_addr - *kern_end, 0, s->sh_size); break; } if (curload < module + s->sh_addr + s->sh_size) @@ -212,32 +258,36 @@ SUFFIX (grub_freebsd_load_elfmodule) (grub_file_t file, int argc, char *argv[], grub_freebsd_add_meta_module (argv[0], FREEBSD_MODTYPE_ELF_MODULE, argc - 1, argv + 1, module, curload - module); - return SUFFIX (grub_freebsd_load_elf_meta) (file, kern_end); + return SUFFIX (grub_freebsd_load_elf_meta) (relocator, file, kern_end); } #endif grub_err_t -SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) +SUFFIX (grub_freebsd_load_elf_meta) (struct grub_relocator *relocator, + grub_file_t file, grub_addr_t *kern_end) { grub_err_t err; Elf_Ehdr e; Elf_Shdr *s; char *shdr = 0; unsigned symoff, stroff, symsize, strsize; - grub_addr_t curload; grub_freebsd_addr_t symstart, symend, symentsize, dynamic; Elf_Sym *sym; + void *sym_chunk; + grub_uint8_t *curload; + grub_freebsd_addr_t symtarget; const char *str; unsigned i; + grub_size_t chunk_size; err = read_headers (file, &e, &shdr); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_ELFHDR, &e, - sizeof (e)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_ELFHDR, &e, + sizeof (e)); if (err) return err; @@ -256,19 +306,31 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) stroff = s->sh_offset; strsize = s->sh_size; - if (*kern_end + 4 * sizeof (grub_freebsd_addr_t) + symsize + strsize - > grub_os_area_addr + grub_os_area_size) - return grub_error (GRUB_ERR_OUT_OF_RANGE, - "not enough memory for kernel symbols"); + chunk_size = ALIGN_UP (symsize + strsize, sizeof (grub_freebsd_addr_t)) + + 2 * sizeof (grub_freebsd_addr_t); - symstart = curload = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t)); - *((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = symsize; + symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t)); + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + symtarget, chunk_size); + if (err) + return err; + sym_chunk = get_virtual_current_address (ch); + } + + symstart = symtarget; + symend = symstart + chunk_size; + + curload = sym_chunk; + *((grub_freebsd_addr_t *) curload) = symsize; curload += sizeof (grub_freebsd_addr_t); + if (grub_file_seek (file, symoff) == (grub_off_t) -1) return grub_errno; - sym = (Elf_Sym *) UINT_TO_PTR (curload); - if (grub_file_read (file, UINT_TO_PTR (curload), symsize) != - (grub_ssize_t) symsize) + sym = (Elf_Sym *) curload; + if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize) { if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); @@ -276,21 +338,17 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) } curload += symsize; - *((grub_freebsd_addr_t *) UINT_TO_PTR (curload)) = strsize; + *((grub_freebsd_addr_t *) curload) = strsize; curload += sizeof (grub_freebsd_addr_t); if (grub_file_seek (file, stroff) == (grub_off_t) -1) return grub_errno; - str = (char *) UINT_TO_PTR (curload); - if (grub_file_read (file, UINT_TO_PTR (curload), strsize) - != (grub_ssize_t) strsize) + str = (char *) curload; + if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize) { if (! grub_errno) return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); return grub_errno; } - curload += strsize; - curload = ALIGN_UP (curload, sizeof (grub_freebsd_addr_t)); - symend = curload; for (i = 0; i * symentsize < symsize; @@ -305,25 +363,258 @@ SUFFIX (grub_freebsd_load_elf_meta) (grub_file_t file, grub_addr_t *kern_end) { dynamic = sym->st_value; grub_dprintf ("bsd", "dynamic = %llx\n", (unsigned long long) dynamic); - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_DYNAMIC, &dynamic, - sizeof (dynamic)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_DYNAMIC, &dynamic, + sizeof (dynamic)); if (err) return err; } - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_SSYM, &symstart, - sizeof (symstart)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_SSYM, &symstart, + sizeof (symstart)); if (err) return err; - err = grub_freebsd_add_meta (FREEBSD_MODINFO_METADATA | - FREEBSD_MODINFOMD_ESYM, &symend, - sizeof (symend)); + err = grub_bsd_add_meta (FREEBSD_MODINFO_METADATA | + FREEBSD_MODINFOMD_ESYM, &symend, + sizeof (symend)); if (err) return err; - *kern_end = ALIGN_PAGE (curload); + + *kern_end = ALIGN_PAGE (symend); return GRUB_ERR_NONE; } + +grub_err_t +SUFFIX (grub_netbsd_load_elf_meta) (struct grub_relocator *relocator, + grub_file_t file, grub_addr_t *kern_end) +{ + grub_err_t err; + Elf_Ehdr e; + Elf_Shdr *s, *symsh, *strsh; + char *shdr; + unsigned symsize, strsize; + Elf_Sym *sym; + void *sym_chunk; + grub_uint8_t *curload; + const char *str; + grub_size_t chunk_size; + Elf_Ehdr *e2; + struct grub_netbsd_btinfo_symtab symtab; + grub_addr_t symtarget; + + err = read_headers (file, &e, &shdr); + if (err) + return err; + + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + if (s->sh_type == SHT_SYMTAB) + break; + if (s >= (Elf_Shdr *) ((char *) shdr + + e.e_shnum * e.e_shentsize)) + return GRUB_ERR_NONE; + symsize = s->sh_size; + symsh = s; + s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link); + strsize = s->sh_size; + strsh = s; + + chunk_size = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t)) + + ALIGN_UP (strsize, sizeof (grub_freebsd_addr_t)) + + sizeof (e) + e.e_shnum * e.e_shentsize; + + symtarget = ALIGN_UP (*kern_end, sizeof (grub_freebsd_addr_t)); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + symtarget, chunk_size); + if (err) + return err; + sym_chunk = get_virtual_current_address (ch); + } + + symtab.nsyms = 1; + symtab.ssyms = symtarget; + symtab.esyms = symtarget + chunk_size; + + curload = sym_chunk; + + e2 = (Elf_Ehdr *) curload; + grub_memcpy (curload, &e, sizeof (e)); + e2->e_phoff = 0; + e2->e_phnum = 0; + e2->e_phentsize = 0; + e2->e_shstrndx = 0; + e2->e_shoff = sizeof (e); + + curload += sizeof (e); + + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + { + Elf_Shdr *s2; + s2 = (Elf_Shdr *) curload; + grub_memcpy (curload, s, e.e_shentsize); + if (s == symsh) + s2->sh_offset = sizeof (e) + e.e_shnum * e.e_shentsize; + else if (s == strsh) + s2->sh_offset = ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t)) + + sizeof (e) + e.e_shnum * e.e_shentsize; + else + s2->sh_offset = 0; + s2->sh_addr = s2->sh_offset; + curload += e.e_shentsize; + } + + if (grub_file_seek (file, symsh->sh_offset) == (grub_off_t) -1) + return grub_errno; + sym = (Elf_Sym *) curload; + if (grub_file_read (file, curload, symsize) != (grub_ssize_t) symsize) + { + if (! grub_errno) + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); + return grub_errno; + } + curload += ALIGN_UP (symsize, sizeof (grub_freebsd_addr_t)); + + if (grub_file_seek (file, strsh->sh_offset) == (grub_off_t) -1) + return grub_errno; + str = (char *) curload; + if (grub_file_read (file, curload, strsize) != (grub_ssize_t) strsize) + { + if (! grub_errno) + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); + return grub_errno; + } + + err = grub_bsd_add_meta (NETBSD_BTINFO_SYMTAB, + &symtab, + sizeof (symtab)); + if (err) + return err; + + *kern_end = ALIGN_PAGE (symtarget + chunk_size); + + return GRUB_ERR_NONE; +} + +grub_err_t +SUFFIX(grub_openbsd_find_ramdisk) (grub_file_t file, + grub_addr_t kern_start, + void *kern_chunk_src, + struct grub_openbsd_ramdisk_descriptor *desc) +{ + unsigned symoff, stroff, symsize, strsize, symentsize; + + { + grub_err_t err; + Elf_Ehdr e; + Elf_Shdr *s; + char *shdr; + + err = read_headers (file, &e, &shdr); + if (err) + return err; + + for (s = (Elf_Shdr *) shdr; s < (Elf_Shdr *) (shdr + + e.e_shnum * e.e_shentsize); + s = (Elf_Shdr *) ((char *) s + e.e_shentsize)) + if (s->sh_type == SHT_SYMTAB) + break; + if (s >= (Elf_Shdr *) ((char *) shdr + e.e_shnum * e.e_shentsize)) + { + grub_free (shdr); + return GRUB_ERR_NONE; + } + + symsize = s->sh_size; + symentsize = s->sh_entsize; + symoff = s->sh_offset; + + s = (Elf_Shdr *) (shdr + e.e_shentsize * s->sh_link); + stroff = s->sh_offset; + strsize = s->sh_size; + grub_free (shdr); + } + { + Elf_Sym *syms, *sym, *imagesym = NULL, *sizesym = NULL; + unsigned i; + char *strs; + + syms = grub_malloc (symsize); + if (!syms) + return grub_errno; + + if (grub_file_seek (file, symoff) == (grub_off_t) -1) + { + grub_free (syms); + return grub_errno; + } + if (grub_file_read (file, syms, symsize) != (grub_ssize_t) symsize) + { + grub_free (syms); + if (! grub_errno) + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); + return grub_errno; + } + + strs = grub_malloc (strsize); + if (!strs) + { + grub_free (syms); + return grub_errno; + } + + if (grub_file_seek (file, stroff) == (grub_off_t) -1) + return grub_errno; + if (grub_file_read (file, strs, strsize) != (grub_ssize_t) strsize) + { + grub_free (syms); + grub_free (strs); + if (! grub_errno) + return grub_error (GRUB_ERR_BAD_OS, "invalid ELF"); + return grub_errno; + } + + for (i = 0, sym = syms; i < symsize / symentsize; + i++, sym = (Elf_Sym *) ((char *) sym + symentsize)) + { + if (ELF_ST_TYPE (sym->st_info) != STT_OBJECT) + continue; + if (!sym->st_name) + continue; + if (grub_strcmp (strs + sym->st_name, "rd_root_image") == 0) + imagesym = sym; + if (grub_strcmp (strs + sym->st_name, "rd_root_size") == 0) + sizesym = sym; + if (imagesym && sizesym) + break; + } + if (!imagesym || !sizesym) + { + grub_free (syms); + grub_free (strs); + return GRUB_ERR_NONE; + } + if (sizeof (*desc->size) != sizesym->st_size) + { + grub_free (syms); + grub_free (strs); + return grub_error (GRUB_ERR_BAD_OS, "unexpected size of rd_root_size"); + } + desc->max_size = imagesym->st_size; + desc->target = (imagesym->st_value & 0xFFFFFF) - kern_start + + (grub_uint8_t *) kern_chunk_src; + desc->size = (grub_uint32_t *) ((sizesym->st_value & 0xFFFFFF) - kern_start + + (grub_uint8_t *) kern_chunk_src); + grub_free (syms); + grub_free (strs); + + return GRUB_ERR_NONE; + } +} diff --git a/grub-core/loader/i386/bsd_pagetable.c b/grub-core/loader/i386/bsd_pagetable.c index 0fd393707..13348cc83 100644 --- a/grub-core/loader/i386/bsd_pagetable.c +++ b/grub-core/loader/i386/bsd_pagetable.c @@ -50,9 +50,10 @@ static void -fill_bsd64_pagetable (grub_uint8_t *target) +fill_bsd64_pagetable (grub_uint8_t *src, grub_addr_t target) { grub_uint64_t *pt2, *pt3, *pt4; + grub_addr_t pt2t, pt3t, pt4t; int i; #define PG_V 0x001 @@ -60,11 +61,15 @@ fill_bsd64_pagetable (grub_uint8_t *target) #define PG_U 0x004 #define PG_PS 0x080 - pt4 = (grub_uint64_t *) target; - pt3 = (grub_uint64_t *) (target + 4096); - pt2 = (grub_uint64_t *) (target + 8192); + pt4 = (grub_uint64_t *) src; + pt3 = (grub_uint64_t *) (src + 4096); + pt2 = (grub_uint64_t *) (src + 8192); - grub_memset ((char *) target, 0, 4096 * 3); + pt4t = target; + pt3t = target + 4096; + pt2t = target + 8192; + + grub_memset (src, 0, 4096 * 3); /* * This is kinda brutal, but every single 1GB VM memory segment points to @@ -74,11 +79,11 @@ fill_bsd64_pagetable (grub_uint8_t *target) for (i = 0; i < 512; i++) { /* Each slot of the level 4 pages points to the same level 3 page */ - pt4[i] = (grub_addr_t) &pt3[0]; + pt4[i] = (grub_addr_t) pt3t; pt4[i] |= PG_V | PG_RW | PG_U; /* Each slot of the level 3 pages points to the same level 2 page */ - pt3[i] = (grub_addr_t) &pt2[0]; + pt3[i] = (grub_addr_t) pt2t; pt3[i] |= PG_V | PG_RW | PG_U; /* The level 2 page slots are mapped with 2MB pages for 1GB. */ diff --git a/grub-core/loader/i386/bsd_trampoline.S b/grub-core/loader/i386/bsd_trampoline.S deleted file mode 100644 index a568fff4d..000000000 --- a/grub-core/loader/i386/bsd_trampoline.S +++ /dev/null @@ -1,124 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (c) 2003 Peter Wemm - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -/* Based on the code from FreeBSD originally distributed under the - following terms: */ - -/*- - * Copyright (c) 2003 Peter Wemm - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - - -#define MSR_EFER 0xc0000080 -#define EFER_LME 0x00000100 -#define CR4_PAE 0x00000020 -#define CR4_PSE 0x00000010 -#define CR0_PG 0x80000000 - -#include - - .p2align 2 - - .code32 - - -VARIABLE(grub_bsd64_trampoline_start) - - /* Discard `grub_unix_real_boot' return address. */ - popl %eax - - /* entry */ - popl %edi - - /* entry_hi */ - popl %esi - - cli - - /* Turn on EFER.LME. */ - movl $MSR_EFER, %ecx - rdmsr - orl $EFER_LME, %eax - wrmsr - - /* Turn on PAE. */ - movl %cr4, %eax - orl $(CR4_PAE | CR4_PSE), %eax - movl %eax, %cr4 - - /* Set %cr3 for PT4. */ - popl %eax - movl %eax, %cr3 - - /* Push a dummy return address. */ - pushl %eax - - /* Turn on paging (implicitly sets EFER.LMA). */ - movl %cr0, %eax - orl $CR0_PG, %eax - movl %eax, %cr0 - - /* Now we're in compatibility mode. set %cs for long mode. */ - /* lgdt */ - .byte 0x0f - .byte 0x01 - .byte 0x15 -VARIABLE (grub_bsd64_trampoline_gdt) - .long 0x0 - - /* ljmp */ - .byte 0xea -VARIABLE (grub_bsd64_trampoline_selfjump) - .long 0x0 - .word 0x08 - - .code64 - -bsd64_longmode: - /* We're still running V=P, jump to entry point. */ - movl %esi, %eax - salq $32, %rax - orq %rdi, %rax - pushq %rax - ret -VARIABLE(grub_bsd64_trampoline_end) diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c deleted file mode 100644 index d37feb983..000000000 --- a/grub-core/loader/i386/efi/linux.c +++ /dev/null @@ -1,945 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * 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 - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define GRUB_LINUX_CL_OFFSET 0x1000 -#define GRUB_LINUX_CL_END_OFFSET 0x2000 - -#define NEXT_MEMORY_DESCRIPTOR(desc, size) \ - ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) - -static grub_dl_t my_mod; - -static grub_size_t linux_mem_size; -static int loaded; -static void *real_mode_mem; -static void *prot_mode_mem; -static void *initrd_mem; -static grub_efi_uintn_t real_mode_pages; -static grub_efi_uintn_t prot_mode_pages; -static grub_efi_uintn_t initrd_pages; -static void *mmap_buf; - -static grub_uint8_t gdt[] __attribute__ ((aligned(16))) = - { - /* NULL. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Reserved. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Code segment. */ - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00, - /* Data segment. */ - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 - }; - -struct gdt_descriptor -{ - grub_uint16_t limit; - void *base; -} __attribute__ ((packed)); - -static struct gdt_descriptor gdt_desc = - { - sizeof (gdt) - 1, - gdt - }; - -struct idt_descriptor -{ - grub_uint16_t limit; - void *base; -} __attribute__ ((packed)); - -static struct idt_descriptor idt_desc = - { - 0, - 0 - }; - -static inline grub_size_t -page_align (grub_size_t size) -{ - return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); -} - -/* Find the optimal number of pages for the memory map. Is it better to - move this code to efi/mm.c? */ -static grub_efi_uintn_t -find_mmap_size (void) -{ - static grub_efi_uintn_t mmap_size = 0; - - if (mmap_size != 0) - return mmap_size; - - mmap_size = (1 << 12); - while (1) - { - int ret; - grub_efi_memory_descriptor_t *mmap; - grub_efi_uintn_t desc_size; - - mmap = grub_malloc (mmap_size); - if (! mmap) - return 0; - - ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); - grub_free (mmap); - - if (ret < 0) - grub_fatal ("cannot get memory map"); - else if (ret > 0) - break; - - mmap_size += (1 << 12); - } - - /* Increase the size a bit for safety, because GRUB allocates more on - later, and EFI itself may allocate more. */ - mmap_size += (1 << 12); - - return page_align (mmap_size); -} - -static void -free_pages (void) -{ - if (real_mode_mem) - { - grub_efi_free_pages ((grub_addr_t) real_mode_mem, real_mode_pages); - real_mode_mem = 0; - } - - if (prot_mode_mem) - { - grub_efi_free_pages ((grub_addr_t) prot_mode_mem, prot_mode_pages); - prot_mode_mem = 0; - } - - if (initrd_mem) - { - grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages); - initrd_mem = 0; - } -} - -/* Allocate pages for the real mode code and the protected mode code - for linux as well as a memory map buffer. */ -static int -allocate_pages (grub_size_t prot_size) -{ - grub_efi_uintn_t desc_size; - grub_efi_memory_descriptor_t *mmap, *mmap_end; - grub_efi_uintn_t mmap_size, tmp_mmap_size; - grub_efi_memory_descriptor_t *desc; - grub_size_t real_size; - - /* Make sure that each size is aligned to a page boundary. */ - real_size = GRUB_LINUX_CL_END_OFFSET; - prot_size = page_align (prot_size); - mmap_size = find_mmap_size (); - - grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n", - (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size); - - /* Calculate the number of pages; Combine the real mode code with - the memory map buffer for simplicity. */ - real_mode_pages = ((real_size + mmap_size) >> 12); - prot_mode_pages = (prot_size >> 12); - - /* Initialize the memory pointers with NULL for convenience. */ - real_mode_mem = 0; - prot_mode_mem = 0; - - /* Read the memory map temporarily, to find free space. */ - mmap = grub_malloc (mmap_size); - if (! mmap) - return 0; - - tmp_mmap_size = mmap_size; - if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0) - grub_fatal ("cannot get memory map"); - - mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size); - - /* First, find free pages for the real mode code - and the memory map buffer. */ - for (desc = mmap; - desc < mmap_end; - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) - { - /* Probably it is better to put the real mode code in the traditional - space for safety. */ - if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY - && desc->physical_start <= 0x90000 - && desc->num_pages >= real_mode_pages) - { - grub_efi_physical_address_t physical_end; - grub_efi_physical_address_t addr; - - physical_end = desc->physical_start + (desc->num_pages << 12); - if (physical_end > 0x90000) - physical_end = 0x90000; - - grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n", - (unsigned) desc->physical_start, - (unsigned) physical_end); - addr = physical_end - real_size - mmap_size; - if (addr < 0x10000) - continue; - - grub_dprintf ("linux", "trying to allocate %u pages at %lx\n", - (unsigned) real_mode_pages, (unsigned long) addr); - real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages); - if (! real_mode_mem) - grub_fatal ("cannot allocate pages"); - - desc->num_pages -= real_mode_pages; - break; - } - } - - if (! real_mode_mem) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); - goto fail; - } - - mmap_buf = (void *) ((char *) real_mode_mem + real_size); - - /* Next, find free pages for the protected mode code. */ - /* XXX what happens if anything is using this address? */ - prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages + 1); - if (! prot_mode_mem) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, - "cannot allocate protected mode pages"); - goto fail; - } - - grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, " - "prot_mode_mem = %lx, prot_mode_pages = %x\n", - (unsigned long) real_mode_mem, (unsigned) real_mode_pages, - (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages); - - grub_free (mmap); - return 1; - - fail: - grub_free (mmap); - free_pages (); - return 0; -} - -static void -grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num, - grub_uint64_t start, grub_uint64_t size, - grub_uint32_t type) -{ - int n = *e820_num; - - if (n >= GRUB_E820_MAX_ENTRY) - grub_fatal ("Too many e820 memory map entries"); - - if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) && - (e820_map[n - 1].type == type)) - e820_map[n - 1].size += size; - else - { - e820_map[n].addr = start; - e820_map[n].size = size; - e820_map[n].type = type; - (*e820_num)++; - } -} - -static grub_err_t -grub_linux_setup_video (struct linux_kernel_params *params) -{ - struct grub_video_mode_info mode_info; - void *framebuffer; - grub_err_t err; - - err = grub_video_get_info_and_fini (&mode_info, &framebuffer); - - if (err) - return err; - - params->lfb_width = mode_info.width; - params->lfb_height = mode_info.height; - params->lfb_depth = mode_info.bpp; - params->lfb_line_len = mode_info.pitch; - - params->lfb_base = (grub_size_t) framebuffer; - params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, - 65536); - - params->red_mask_size = mode_info.red_mask_size; - params->red_field_pos = mode_info.red_field_pos; - params->green_mask_size = mode_info.green_mask_size; - params->green_field_pos = mode_info.green_field_pos; - params->blue_mask_size = mode_info.blue_mask_size; - params->blue_field_pos = mode_info.blue_field_pos; - params->reserved_mask_size = mode_info.reserved_mask_size; - params->reserved_field_pos = mode_info.reserved_field_pos; - - params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; - -#ifdef GRUB_MACHINE_PCBIOS - /* VESA packed modes may come with zeroed mask sizes, which need - to be set here according to DAC Palette width. If we don't, - this results in Linux displaying a black screen. */ - if (mode_info.bpp <= 8) - { - struct grub_vbe_info_block controller_info; - int status; - int width = 8; - - status = grub_vbe_bios_get_controller_info (&controller_info); - - if (status == GRUB_VBE_STATUS_OK && - (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH)) - status = grub_vbe_bios_set_dac_palette_width (&width); - - if (status != GRUB_VBE_STATUS_OK) - /* 6 is default after mode reset. */ - width = 6; - - params->red_mask_size = params->green_mask_size - = params->blue_mask_size = width; - params->reserved_mask_size = 0; - } -#endif - - return 0; -} - -#ifdef __x86_64__ -extern grub_uint8_t grub_linux_trampoline_start[]; -extern grub_uint8_t grub_linux_trampoline_end[]; -#endif - -static grub_err_t -grub_linux_boot (void) -{ - struct linux_kernel_params *params; - grub_efi_uintn_t mmap_size; - grub_efi_uintn_t map_key; - grub_efi_uintn_t desc_size; - grub_efi_uint32_t desc_version; - int e820_num; - const char *modevar; - char *tmp; - grub_err_t err; - - params = real_mode_mem; - - grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n", - (unsigned) params->code32_start, - (unsigned long) &(idt_desc.limit), - (unsigned long) &(gdt_desc.limit)); - grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n", - (unsigned) idt_desc.limit, (unsigned long) idt_desc.base, - (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base); - - auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); - int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) - { - switch (type) - { - case GRUB_MACHINE_MEMORY_AVAILABLE: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_RAM); - break; - -#ifdef GRUB_MACHINE_MEMORY_ACPI - case GRUB_MACHINE_MEMORY_ACPI: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_ACPI); - break; -#endif - -#ifdef GRUB_MACHINE_MEMORY_NVS - case GRUB_MACHINE_MEMORY_NVS: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_NVS); - break; -#endif - -#ifdef GRUB_MACHINE_MEMORY_CODE - case GRUB_MACHINE_MEMORY_CODE: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_EXEC_CODE); - break; -#endif - - default: - grub_e820_add_region (params->e820_map, &e820_num, - addr, size, GRUB_E820_RESERVED); - } - return 0; - } - - e820_num = 0; - grub_mmap_iterate (hook); - params->mmap_size = e820_num; - - grub_dprintf ("linux", "Trampoline at %p. code32=%x, real_mode_mem=%p\n", - ((char *) prot_mode_mem + (prot_mode_pages << 12)), - (unsigned) params->code32_start, real_mode_mem); - - modevar = grub_env_get ("gfxpayload"); - - /* Now all graphical modes are acceptable. - May change in future if we have modes without framebuffer. */ - if (modevar && *modevar != 0) - { - tmp = grub_xasprintf ("%s;auto", modevar); - if (! tmp) - return grub_errno; - err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); - grub_free (tmp); - } - else - err = grub_video_set_mode ("auto", GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); - - if (!err) - err = grub_linux_setup_video (params); - - if (err) - { - grub_print_error (); - grub_printf ("Booting however\n"); - grub_errno = GRUB_ERR_NONE; - } - - mmap_size = find_mmap_size (); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, - &desc_size, &desc_version) <= 0) - grub_fatal ("cannot get memory map"); - - if (! grub_efi_exit_boot_services (map_key)) - grub_fatal ("cannot exit boot services"); - - /* Note that no boot services are available from here. */ - - /* Pass EFI parameters. */ - if (grub_le_to_cpu16 (params->version) >= 0x0206) - { - params->v0206.efi_mem_desc_size = desc_size; - params->v0206.efi_mem_desc_version = desc_version; - params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf; - params->v0206.efi_mmap_size = mmap_size; -#ifdef __x86_64__ - params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) mmap_buf >> 32); -#endif - } - else if (grub_le_to_cpu16 (params->version) >= 0x0204) - { - params->v0204.efi_mem_desc_size = desc_size; - params->v0204.efi_mem_desc_version = desc_version; - params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf; - params->v0204.efi_mmap_size = mmap_size; - } - -#ifdef __x86_64__ - - grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12), - grub_linux_trampoline_start, - grub_linux_trampoline_end - grub_linux_trampoline_start); - - ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem - + (prot_mode_pages << 12))) - (params->code32_start, real_mode_mem); - -#else - - /* Hardware interrupts are not safe any longer. */ - asm volatile ("cli" : : ); - - /* Load the IDT and the GDT for the bootstrap. */ - asm volatile ("lidt %0" : : "m" (idt_desc)); - asm volatile ("lgdt %0" : : "m" (gdt_desc)); - - /* Pass parameters. */ - asm volatile ("movl %0, %%ecx" : : "m" (params->code32_start)); - asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem)); - - asm volatile ("xorl %%ebx, %%ebx" : : ); - - /* Enter Linux. */ - asm volatile ("jmp *%%ecx" : : ); - -#endif - - /* Never reach here. */ - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_linux_unload (void) -{ - free_pages (); - grub_dl_unref (my_mod); - loaded = 0; - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - struct linux_kernel_header lh; - struct linux_kernel_params *params; - grub_uint8_t setup_sects; - grub_size_t real_size, prot_size; - grub_ssize_t len; - int i; - char *dest; - - grub_dl_ref (my_mod); - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); - goto fail; - } - - file = grub_file_open (argv[0]); - if (! file) - goto fail; - - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) - { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); - goto fail; - } - - if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) - { - grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); - goto fail; - } - - if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) - { - grub_error (GRUB_ERR_BAD_OS, "too many setup sectors"); - goto fail; - } - - /* EFI support is quite new, so reject old versions. */ - if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE) - || grub_le_to_cpu16 (lh.version) < 0x0203) - { - grub_error (GRUB_ERR_BAD_OS, "too old version"); - goto fail; - } - - /* I'm not sure how to support zImage on EFI. */ - if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL)) - { - grub_error (GRUB_ERR_BAD_OS, "zImage is not supported"); - goto fail; - } - - setup_sects = lh.setup_sects; - - /* If SETUP_SECTS is not set, set it to the default (4). */ - if (! setup_sects) - setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; - - real_size = setup_sects << GRUB_DISK_SECTOR_BITS; - prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - - if (! allocate_pages (prot_size)) - goto fail; - - params = (struct linux_kernel_params *) real_mode_mem; - grub_memset (params, 0, GRUB_LINUX_CL_END_OFFSET); - grub_memcpy (¶ms->setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1); - - params->ps_mouse = params->padding10 = 0; - - len = 0x400 - sizeof (lh); - if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; - } - - params->type_of_loader = (LINUX_LOADER_ID_GRUB << 4); - - params->cl_magic = GRUB_LINUX_CL_MAGIC; - params->cl_offset = 0x1000; - params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000; - params->ramdisk_image = 0; - params->ramdisk_size = 0; - - params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET; - params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP; - - /* These are not needed to be precise, because Linux uses these values - only to raise an error when the decompression code cannot find good - space. */ - params->ext_mem = ((32 * 0x100000) >> 10); - params->alt_mem = ((32 * 0x100000) >> 10); - - { - grub_term_output_t term; - int found = 0; - FOR_ACTIVE_TERM_OUTPUTS(term) - if (grub_strcmp (term->name, "vga_text") == 0 - || grub_strcmp (term->name, "console") == 0) - { - grub_uint16_t pos = grub_term_getxy (term); - params->video_cursor_x = pos >> 8; - params->video_cursor_y = pos & 0xff; - params->video_width = grub_term_width (term); - params->video_height = grub_term_height (term); - found = 1; - break; - } - if (!found) - { - params->video_cursor_x = 0; - params->video_cursor_y = 0; - params->video_width = 80; - params->video_height = 25; - } - } - params->video_page = 0; /* ??? */ - params->video_mode = grub_efi_system_table->con_out->mode->mode; - params->video_ega_bx = 0; - params->have_vga = 0; - params->font_size = 16; /* XXX */ - - if (grub_le_to_cpu16 (params->version) >= 0x0206) - { - params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE; - params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table; -#ifdef __x86_64__ - params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32); -#endif - } - else if (grub_le_to_cpu16 (params->version) >= 0x0204) - { - params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204; - params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table; - } - -#if 0 - /* The structure is zeroed already. */ - - /* No VBE on EFI. */ - params->lfb_width = 0; - params->lfb_height = 0; - params->lfb_depth = 0; - params->lfb_base = 0; - params->lfb_size = 0; - params->lfb_line_len = 0; - params->red_mask_size = 0; - params->red_field_pos = 0; - params->green_mask_size = 0; - params->green_field_pos = 0; - params->blue_mask_size = 0; - params->blue_field_pos = 0; - params->reserved_mask_size = 0; - params->reserved_field_pos = 0; - params->vesapm_segment = 0; - params->vesapm_offset = 0; - params->lfb_pages = 0; - params->vesa_attrib = 0; - - /* No APM on EFI. */ - params->apm_version = 0; - params->apm_code_segment = 0; - params->apm_entry = 0; - params->apm_16bit_code_segment = 0; - params->apm_data_segment = 0; - params->apm_flags = 0; - params->apm_code_len = 0; - params->apm_data_len = 0; - - /* XXX is there any way to use SpeedStep on EFI? */ - params->ist_signature = 0; - params->ist_command = 0; - params->ist_event = 0; - params->ist_perf_level = 0; - - /* Let the kernel probe the information. */ - grub_memset (params->hd0_drive_info, 0, sizeof (params->hd0_drive_info)); - grub_memset (params->hd1_drive_info, 0, sizeof (params->hd1_drive_info)); - - /* No MCA on EFI. */ - params->rom_config_len = 0; - - /* No need to fake the BIOS's memory map. */ - params->mmap_size = 0; - - /* Let the kernel probe the information. */ - params->ps_mouse = 0; - - /* Clear padding for future compatibility. */ - grub_memset (params->padding1, 0, sizeof (params->padding1)); - grub_memset (params->padding2, 0, sizeof (params->padding2)); - grub_memset (params->padding3, 0, sizeof (params->padding3)); - grub_memset (params->padding4, 0, sizeof (params->padding4)); - grub_memset (params->padding5, 0, sizeof (params->padding5)); - grub_memset (params->padding6, 0, sizeof (params->padding6)); - grub_memset (params->padding7, 0, sizeof (params->padding7)); - grub_memset (params->padding8, 0, sizeof (params->padding8)); - grub_memset (params->padding9, 0, sizeof (params->padding9)); - -#endif - - /* The other EFI parameters are filled when booting. */ - - grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); - - /* XXX there is no way to know if the kernel really supports EFI. */ - grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n", - (unsigned) real_size, (unsigned) prot_size); - - /* Detect explicitly specified memory size, if any. */ - linux_mem_size = 0; - for (i = 1; i < argc; i++) - if (grub_memcmp (argv[i], "mem=", 4) == 0) - { - char *val = argv[i] + 4; - - linux_mem_size = grub_strtoul (val, &val, 0); - - if (grub_errno) - { - grub_errno = GRUB_ERR_NONE; - linux_mem_size = 0; - } - else - { - int shift = 0; - - switch (grub_tolower (val[0])) - { - case 'g': - shift += 10; - case 'm': - shift += 10; - case 'k': - shift += 10; - default: - break; - } - - /* Check an overflow. */ - if (linux_mem_size > (~0UL >> shift)) - linux_mem_size = 0; - else - linux_mem_size <<= shift; - } - } - else if (grub_memcmp (argv[i], "video=efifb", 11) == 0) - { - if (params->have_vga) - params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE; - } - - /* Specify the boot file. */ - dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET, - "BOOT_IMAGE="); - dest = grub_stpcpy (dest, argv[0]); - - /* Copy kernel parameters. */ - for (i = 1; - i < argc - && dest + grub_strlen (argv[i]) + 1 < ((char *) real_mode_mem - + GRUB_LINUX_CL_END_OFFSET); - i++) - { - *dest++ = ' '; - dest = grub_stpcpy (dest, argv[i]); - } - - len = prot_size; - if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len) - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - - if (grub_errno == GRUB_ERR_NONE) - { - grub_loader_set (grub_linux_boot, grub_linux_unload, 0); - loaded = 1; - } - - fail: - - if (file) - grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_dl_unref (my_mod); - loaded = 0; - } - - return grub_errno; -} - -static grub_err_t -grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - grub_ssize_t size; - grub_addr_t addr_min, addr_max; - grub_addr_t addr; - grub_efi_uintn_t mmap_size; - grub_efi_memory_descriptor_t *desc; - grub_efi_uintn_t desc_size; - struct linux_kernel_header *lh; - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); - goto fail; - } - - if (! loaded) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); - goto fail; - } - - file = grub_file_open (argv[0]); - if (! file) - goto fail; - - size = grub_file_size (file); - initrd_pages = (page_align (size) >> 12); - - lh = (struct linux_kernel_header *) real_mode_mem; - - addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10); - if (linux_mem_size != 0 && linux_mem_size < addr_max) - addr_max = linux_mem_size; - - /* Linux 2.3.xx has a bug in the memory range check, so avoid - the last page. - Linux 2.2.xx has a bug in the memory range check, which is - worse than that of Linux 2.3.xx, so avoid the last 64kb. */ - addr_max -= 0x10000; - - /* Usually, the compression ratio is about 50%. */ - addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12) - + page_align (size); - - /* Find the highest address to put the initrd. */ - mmap_size = find_mmap_size (); - if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0) - grub_fatal ("cannot get memory map"); - - addr = 0; - for (desc = mmap_buf; - desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) - { - if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY - && desc->num_pages >= initrd_pages) - { - grub_efi_physical_address_t physical_end; - - physical_end = desc->physical_start + (desc->num_pages << 12); - if (physical_end > addr_max) - physical_end = addr_max; - - if (physical_end < page_align (size)) - continue; - - physical_end -= page_align (size); - - if ((physical_end >= addr_min) && - (physical_end >= desc->physical_start) && - (physical_end > addr)) - addr = physical_end; - } - } - - if (addr == 0) - { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free pages available"); - goto fail; - } - - initrd_mem = grub_efi_allocate_pages (addr, initrd_pages); - if (! initrd_mem) - grub_fatal ("cannot allocate pages"); - - if (grub_file_read (file, initrd_mem, size) != size) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; - } - - grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n", - (unsigned) addr, (unsigned) size); - - lh->ramdisk_image = addr; - lh->ramdisk_size = size; - lh->root_dev = 0x0100; /* XXX */ - - fail: - if (file) - grub_file_close (file); - - return grub_errno; -} - -static grub_command_t cmd_linux, cmd_initrd; - -GRUB_MOD_INIT(linux) -{ - cmd_linux = grub_register_command ("linux", grub_cmd_linux, - 0, N_("Load Linux.")); - cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, N_("Load initrd.")); - my_mod = mod; -} - -GRUB_MOD_FINI(linux) -{ - grub_unregister_command (cmd_linux); - grub_unregister_command (cmd_initrd); -} diff --git a/grub-core/loader/i386/ieee1275/linux.c b/grub-core/loader/i386/ieee1275/linux.c deleted file mode 100644 index 9f7556ffa..000000000 --- a/grub-core/loader/i386/ieee1275/linux.c +++ /dev/null @@ -1,311 +0,0 @@ -/* linux.c - boot Linux zImage or bzImage */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008,2009,2010 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define GRUB_OFW_LINUX_PARAMS_ADDR 0x90000 -#define GRUB_OFW_LINUX_KERNEL_ADDR 0x100000 -#define GRUB_OFW_LINUX_INITRD_ADDR 0x800000 - -#define GRUB_OFW_LINUX_CL_OFFSET 0x1e00 -#define GRUB_OFW_LINUX_CL_LENGTH 0x100 - -static grub_dl_t my_mod; - -static grub_size_t kernel_size; -static char *kernel_addr, *kernel_cmdline; -static grub_size_t initrd_size; - -static grub_err_t -grub_linux_unload (void) -{ - grub_free (kernel_cmdline); - grub_free (kernel_addr); - kernel_cmdline = 0; - kernel_addr = 0; - initrd_size = 0; - - grub_dl_unref (my_mod); - - return GRUB_ERR_NONE; -} - -/* -static int -grub_ieee1275_debug (void) -{ - struct enter_args - { - struct grub_ieee1275_common_hdr common; - } - args; - - INIT_IEEE1275_COMMON (&args.common, "enter", 0, 0); - - if (IEEE1275_CALL_ENTRY_FN (&args) == -1) - return -1; - - return 0; -} -*/ - -static grub_err_t -grub_linux_boot (void) -{ - struct linux_kernel_params *params; - struct linux_kernel_header *lh; - char *prot_code; - char *bootpath; - grub_ssize_t len; - - bootpath = grub_env_get ("root"); - if (bootpath) - grub_ieee1275_set_property (grub_ieee1275_chosen, - "bootpath", bootpath, - grub_strlen (bootpath) + 1, - &len); - - params = (struct linux_kernel_params *) GRUB_OFW_LINUX_PARAMS_ADDR; - lh = (struct linux_kernel_header *) params; - - grub_memset ((char *) params, 0, GRUB_OFW_LINUX_CL_OFFSET); - - params->alt_mem = grub_mmap_get_upper () >> 10; - params->ext_mem = params->alt_mem; - - lh->cmd_line_ptr = (char *) - (GRUB_OFW_LINUX_PARAMS_ADDR + GRUB_OFW_LINUX_CL_OFFSET); - - params->cl_magic = GRUB_LINUX_CL_MAGIC; - params->cl_offset = GRUB_OFW_LINUX_CL_OFFSET; - - { - grub_term_output_t term; - int found = 0; - FOR_ACTIVE_TERM_OUTPUTS(term) - if (grub_strcmp (term->name, "ofconsole") == 0) - { - grub_uint16_t pos = grub_term_getxy (term); - params->video_cursor_x = pos >> 8; - params->video_cursor_y = pos & 0xff; - params->video_width = grub_term_width (term); - params->video_height = grub_term_height (term); - found = 1; - break; - } - if (!found) - { - params->video_cursor_x = 0; - params->video_cursor_y = 0; - params->video_width = 80; - params->video_height = 25; - } - } - - params->font_size = 16; - - params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE; - params->ofw_num_items = 1; - params->ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn; - params->ofw_idt = 0; - - if (initrd_size) - { - lh->type_of_loader = 1; - lh->ramdisk_image = GRUB_OFW_LINUX_INITRD_ADDR; - lh->ramdisk_size = initrd_size; - } - - if (kernel_cmdline) - grub_strcpy (lh->cmd_line_ptr, kernel_cmdline); - - prot_code = (char *) GRUB_OFW_LINUX_KERNEL_ADDR; - grub_memcpy (prot_code, kernel_addr, kernel_size); - - asm volatile ("movl %0, %%esi" : : "m" (params)); - asm volatile ("movl %%esi, %%esp" : : ); - asm volatile ("movl %0, %%ecx" : : "m" (prot_code)); - asm volatile ("xorl %%ebx, %%ebx" : : ); - asm volatile ("jmp *%%ecx" : : ); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - struct linux_kernel_header lh; - grub_uint8_t setup_sects; - grub_size_t real_size, prot_size; - int i; - char *dest; - - grub_dl_ref (my_mod); - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); - goto fail; - } - - file = grub_file_open (argv[0]); - if (! file) - goto fail; - - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) - { - grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); - goto fail; - } - - if ((lh.boot_flag != grub_cpu_to_le16 (0xaa55)) || - (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE))) - { - grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); - goto fail; - } - - setup_sects = lh.setup_sects; - if (! setup_sects) - setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; - - real_size = setup_sects << GRUB_DISK_SECTOR_BITS; - prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - - grub_dprintf ("linux", "Linux-%s, setup=0x%x, size=0x%x\n", - "bzImage", real_size, prot_size); - - grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); - if (grub_errno) - goto fail; - - kernel_cmdline = grub_malloc (GRUB_OFW_LINUX_CL_LENGTH); - if (! kernel_cmdline) - goto fail; - - dest = kernel_cmdline; - for (i = 1; - i < argc - && dest + grub_strlen (argv[i]) + 1 < (kernel_cmdline - + GRUB_OFW_LINUX_CL_LENGTH); - i++) - { - *dest++ = ' '; - dest = grub_stpcpy (dest, argv[i]); - } - - kernel_addr = grub_malloc (prot_size); - if (! kernel_addr) - goto fail; - - kernel_size = prot_size; - if (grub_file_read (file, kernel_addr, prot_size) != (int) prot_size) - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - - if (grub_errno == GRUB_ERR_NONE) - grub_loader_set (grub_linux_boot, grub_linux_unload, 1); - -fail: - - if (file) - grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_free (kernel_cmdline); - grub_free (kernel_addr); - kernel_cmdline = 0; - kernel_addr = 0; - - grub_dl_unref (my_mod); - } - - return grub_errno; -} - -static grub_err_t -grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), - int argc, char *argv[]) -{ - grub_file_t file = 0; - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); - goto fail; - } - - if (! kernel_addr) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the kernel first"); - goto fail; - } - - file = grub_file_open (argv[0]); - if (! file) - goto fail; - - initrd_size = grub_file_size (file); - if (grub_file_read (file, (void *) GRUB_OFW_LINUX_INITRD_ADDR, - initrd_size) != (int) initrd_size) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); - goto fail; - } - -fail: - if (file) - grub_file_close (file); - - return grub_errno; -} - -static grub_command_t cmd_linux, cmd_initrd; - -GRUB_MOD_INIT(linux) -{ - cmd_linux = grub_register_command ("linux", grub_cmd_linux, - 0, N_("Load Linux.")); - cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, - 0, N_("Load initrd.")); - my_mod = mod; -} - -GRUB_MOD_FINI(linux) -{ - grub_unregister_command (cmd_linux); - grub_unregister_command (cmd_initrd); -} diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index d3d935182..cc2d20af3 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -32,9 +32,23 @@ #include #include #include +#include +#include + +#ifdef GRUB_MACHINE_EFI +#include +#define HAS_VGA_TEXT 0 +#define DEFAULT_VIDEO_MODE "800x600" +#elif defined (GRUB_MACHINE_IEEE1275) +#include +#define HAS_VGA_TEXT 0 +#define DEFAULT_VIDEO_MODE "text" +#else #include #include -#include +#define HAS_VGA_TEXT 1 +#define DEFAULT_VIDEO_MODE "text" +#endif #define GRUB_LINUX_CL_OFFSET 0x1000 #define GRUB_LINUX_CL_END_OFFSET 0x2000 @@ -44,36 +58,24 @@ static grub_dl_t my_mod; static grub_size_t linux_mem_size; static int loaded; static void *real_mode_mem; +static grub_addr_t real_mode_target; static void *prot_mode_mem; +static grub_addr_t prot_mode_target; static void *initrd_mem; +static grub_addr_t initrd_mem_target; static grub_uint32_t real_mode_pages; static grub_uint32_t prot_mode_pages; static grub_uint32_t initrd_pages; +static struct grub_relocator *relocator = NULL; +static void *efi_mmap_buf; +#ifdef GRUB_MACHINE_EFI +static grub_efi_uintn_t efi_mmap_size; +#else +static const grub_size_t efi_mmap_size = 0; +#endif -static grub_uint8_t gdt[] __attribute__ ((aligned(16))) = - { - /* NULL. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Reserved. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Code segment. */ - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00, - /* Data segment. */ - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 - }; - -struct gdt_descriptor -{ - grub_uint16_t limit; - void *base; -} __attribute__ ((packed)); - -static struct gdt_descriptor gdt_desc = - { - sizeof (gdt) - 1, - gdt - }; - +/* FIXME */ +#if 0 struct idt_descriptor { grub_uint16_t limit; @@ -85,6 +87,7 @@ static struct idt_descriptor idt_desc = 0, 0 }; +#endif #ifdef GRUB_MACHINE_PCBIOS struct linux_vesafb_res @@ -261,6 +264,48 @@ page_align (grub_size_t size) return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); } +#ifdef GRUB_MACHINE_EFI +/* Find the optimal number of pages for the memory map. Is it better to + move this code to efi/mm.c? */ +static grub_efi_uintn_t +find_efi_mmap_size (void) +{ + static grub_efi_uintn_t mmap_size = 0; + + if (mmap_size != 0) + return mmap_size; + + mmap_size = (1 << 12); + while (1) + { + int ret; + grub_efi_memory_descriptor_t *mmap; + grub_efi_uintn_t desc_size; + + mmap = grub_malloc (mmap_size); + if (! mmap) + return 0; + + ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); + grub_free (mmap); + + if (ret < 0) + grub_fatal ("cannot get memory map"); + else if (ret > 0) + break; + + mmap_size += (1 << 12); + } + + /* Increase the size a bit for safety, because GRUB allocates more on + later, and EFI itself may allocate more. */ + mmap_size += (1 << 12); + + return page_align (mmap_size); +} + +#endif + /* Find the optimal number of pages for the memory map. */ static grub_size_t find_mmap_size (void) @@ -290,32 +335,47 @@ find_mmap_size (void) static void free_pages (void) { + grub_relocator_unload (relocator); + relocator = NULL; real_mode_mem = prot_mode_mem = initrd_mem = 0; + real_mode_target = prot_mode_target = initrd_mem_target = 0; } /* Allocate pages for the real mode code and the protected mode code for linux as well as a memory map buffer. */ -static int +static grub_err_t allocate_pages (grub_size_t prot_size) { grub_size_t real_size, mmap_size; + grub_err_t err; /* Make sure that each size is aligned to a page boundary. */ real_size = GRUB_LINUX_CL_END_OFFSET; prot_size = page_align (prot_size); mmap_size = find_mmap_size (); +#ifdef GRUB_MACHINE_EFI + efi_mmap_size = find_efi_mmap_size (); +#endif + grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n", (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size); /* Calculate the number of pages; Combine the real mode code with the memory map buffer for simplicity. */ - real_mode_pages = ((real_size + mmap_size) >> 12); + real_mode_pages = ((real_size + mmap_size + efi_mmap_size) >> 12); prot_mode_pages = (prot_size >> 12); /* Initialize the memory pointers with NULL for convenience. */ free_pages (); + relocator = grub_relocator_new (); + if (!relocator) + { + err = grub_errno; + goto fail; + } + /* FIXME: Should request low memory from the heap when this feature is implemented. */ @@ -336,35 +396,55 @@ allocate_pages (grub_size_t prot_size) if (addr + size > 0x90000) size = 0x90000 - addr; - if (real_size + mmap_size > size) + if (real_size + mmap_size + efi_mmap_size > size) return 0; - real_mode_mem = - (void *) (grub_size_t) ((addr + size) - (real_size + mmap_size)); + real_mode_target = ((addr + size) - (real_size + mmap_size + efi_mmap_size)); return 1; } return 0; } grub_mmap_iterate (hook); - if (! real_mode_mem) + if (! real_mode_target) { - grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); + err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); goto fail; } - prot_mode_mem = (void *) 0x100000; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + real_mode_target, + (real_size + mmap_size + + efi_mmap_size)); + if (err) + goto fail; + real_mode_mem = get_virtual_current_address (ch); + } + efi_mmap_buf = (grub_uint8_t *) real_mode_mem + real_size + mmap_size; + + prot_mode_target = GRUB_LINUX_BZIMAGE_ADDR; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + prot_mode_target, prot_size); + if (err) + goto fail; + prot_mode_mem = get_virtual_current_address (ch); + } grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, " "prot_mode_mem = %lx, prot_mode_pages = %x\n", (unsigned long) real_mode_mem, (unsigned) real_mode_pages, (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages); - return 1; + return GRUB_ERR_NONE; fail: free_pages (); - return 0; + return err; } static void @@ -389,7 +469,7 @@ grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num, } } -static int +static grub_err_t grub_linux_setup_video (struct linux_kernel_params *params) { struct grub_video_mode_info mode_info; @@ -448,14 +528,9 @@ grub_linux_setup_video (struct linux_kernel_params *params) } #endif - return 0; + return GRUB_ERR_NONE; } -#ifdef __x86_64__ -extern grub_uint8_t grub_linux_trampoline_start[]; -extern grub_uint8_t grub_linux_trampoline_end[]; -#endif - static grub_err_t grub_linux_boot (void) { @@ -463,16 +538,26 @@ grub_linux_boot (void) int e820_num; grub_err_t err = 0; char *modevar, *tmp; + struct grub_relocator32_state state; params = real_mode_mem; - grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n", - (unsigned) params->code32_start, - (unsigned long) &(idt_desc.limit), - (unsigned long) &(gdt_desc.limit)); - grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n", - (unsigned) idt_desc.limit, (unsigned long) idt_desc.base, - (unsigned) gdt_desc.limit, (unsigned long) gdt_desc.base); +#ifdef GRUB_MACHINE_IEEE1275 + { + char *bootpath; + grub_ssize_t len; + + bootpath = grub_env_get ("root"); + if (bootpath) + grub_ieee1275_set_property (grub_ieee1275_chosen, + "bootpath", bootpath, + grub_strlen (bootpath) + 1, + &len); + } +#endif + + grub_dprintf ("linux", "code32_start = %x\n", + (unsigned) params->code32_start); auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t, grub_uint32_t); int NESTED_FUNC_ATTR hook (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) @@ -522,14 +607,14 @@ grub_linux_boot (void) May change in future if we have modes without framebuffer. */ if (modevar && *modevar != 0) { - tmp = grub_xasprintf ("%s;text", modevar); + tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar); if (! tmp) return grub_errno; err = grub_video_set_mode (tmp, 0, 0); grub_free (tmp); } else - err = grub_video_set_mode ("text", 0, 0); + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); if (err) { @@ -548,23 +633,34 @@ grub_linux_boot (void) } else { +#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) params->have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT; - params->video_width = 80; - params->video_height = 25; + params->video_mode = 0x3; +#else + params->have_vga = 0; + params->video_mode = 0; + params->video_width = 0; + params->video_height = 0; +#endif } /* Initialize these last, because terminal position could be affected by printfs above. */ +#ifndef GRUB_MACHINE_IEEE1275 if (params->have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT) +#endif { grub_term_output_t term; int found = 0; FOR_ACTIVE_TERM_OUTPUTS(term) if (grub_strcmp (term->name, "vga_text") == 0 - || grub_strcmp (term->name, "console") == 0) + || grub_strcmp (term->name, "console") == 0 + || grub_strcmp (term->name, "ofconsole") == 0) { grub_uint16_t pos = grub_term_getxy (term); params->video_cursor_x = pos >> 8; params->video_cursor_y = pos & 0xff; + params->video_width = grub_term_width (term); + params->video_height = grub_term_height (term); found = 1; break; } @@ -572,34 +668,59 @@ grub_linux_boot (void) { params->video_cursor_x = 0; params->video_cursor_y = 0; + params->video_width = 80; + params->video_height = 25; } } -#ifdef __x86_64__ - - grub_memcpy ((char *) prot_mode_mem + (prot_mode_pages << 12), - grub_linux_trampoline_start, - grub_linux_trampoline_end - grub_linux_trampoline_start); - - ((void (*) (unsigned long, void *)) ((char *) prot_mode_mem - + (prot_mode_pages << 12))) - (params->code32_start, real_mode_mem); -#else - - /* Hardware interrupts are not safe any longer. */ - asm volatile ("cli" : : ); - - /* Load the IDT and the GDT for the bootstrap. */ - asm volatile ("lidt %0" : : "m" (idt_desc)); - asm volatile ("lgdt %0" : : "m" (gdt_desc)); - - /* Enter Linux. */ - asm volatile ("jmp *%2" : : "b" (0), "S" (real_mode_mem), "g" (params->code32_start)); - +#ifdef GRUB_MACHINE_IEEE1275 + { + params->ofw_signature = GRUB_LINUX_OFW_SIGNATURE; + params->ofw_num_items = 1; + params->ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn; + params->ofw_idt = 0; + } #endif - /* Never reach here. */ - return GRUB_ERR_NONE; +#ifdef GRUB_MACHINE_EFI + { + grub_efi_uintn_t efi_desc_size; + grub_efi_uint32_t efi_desc_version; + err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL, + &efi_desc_size, &efi_desc_version); + if (err) + return err; + + /* Note that no boot services are available from here. */ + + /* Pass EFI parameters. */ + if (grub_le_to_cpu16 (params->version) >= 0x0206) + { + params->v0206.efi_mem_desc_size = efi_desc_size; + params->v0206.efi_mem_desc_version = efi_desc_version; + params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) efi_mmap_buf; + params->v0206.efi_mmap_size = efi_mmap_size; +#ifdef __x86_64__ + params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) efi_mmap_buf >> 32); +#endif + } + else if (grub_le_to_cpu16 (params->version) >= 0x0204) + { + params->v0204.efi_mem_desc_size = efi_desc_size; + params->v0204.efi_mem_desc_version = efi_desc_version; + params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) efi_mmap_buf; + params->v0204.efi_mmap_size = efi_mmap_size; + } + } +#endif + + /* FIXME. */ + /* asm volatile ("lidt %0" : : "m" (idt_desc)); */ + state.ebp = state.edi = state.ebx = 0; + state.esi = real_mode_target; + state.esp = real_mode_target; + state.eip = params->code32_start; + return grub_relocator32_boot (relocator, state); } static grub_err_t @@ -685,7 +806,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), real_size = setup_sects << GRUB_DISK_SECTOR_BITS; prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - if (! allocate_pages (prot_size)) + if (allocate_pages (prot_size)) goto fail; params = (struct linux_kernel_params *) real_mode_mem; @@ -708,7 +829,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), params->cl_magic = GRUB_LINUX_CL_MAGIC; params->cl_offset = 0x1000; - params->cmd_line_ptr = (unsigned long) real_mode_mem + 0x1000; + params->cmd_line_ptr = real_mode_target + 0x1000; params->ramdisk_image = 0; params->ramdisk_size = 0; @@ -724,14 +845,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), /* Ignored by Linux. */ params->video_page = 0; - /* Must be non-zero even in text mode, or Linux will think there's no VGA. */ - params->video_mode = 0x3; - /* Only used when `video_mode == 0x7', otherwise ignored. */ params->video_ega_bx = 0; params->font_size = 16; /* XXX */ +#ifdef GRUB_MACHINE_EFI + if (grub_le_to_cpu16 (params->version) >= 0x0206) + { + params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE; + params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table; +#ifdef __x86_64__ + params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32); +#endif + } + else if (grub_le_to_cpu16 (params->version) >= 0x0204) + { + params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204; + params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table; + } +#endif + /* The other parameters are filled when booting. */ grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); @@ -888,7 +1022,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), } len = prot_size; - if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len) + if (grub_file_read (file, prot_mode_mem, len) != len) grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); if (grub_errno == GRUB_ERR_NONE) @@ -920,6 +1054,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), grub_ssize_t size; grub_addr_t addr_min, addr_max; grub_addr_t addr; + grub_err_t err; struct linux_kernel_header *lh; if (argc == 0) @@ -934,6 +1069,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } + grub_file_filter_disable_compression (); file = grub_file_open (argv[0]); if (! file) goto fail; @@ -967,12 +1103,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), addr_max -= 0x10000; /* Usually, the compression ratio is about 50%. */ - addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12) + addr_min = (grub_addr_t) prot_mode_target + ((prot_mode_pages * 3) << 12) + page_align (size); - if (addr_max > grub_os_area_addr + grub_os_area_size) - addr_max = grub_os_area_addr + grub_os_area_size; - /* Put the initrd as high as possible, 4KiB aligned. */ addr = (addr_max - size) & ~0xFFF; @@ -982,7 +1115,16 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } - initrd_mem = (void *) addr; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + addr_min, addr, size, 0x1000, + GRUB_RELOCATOR_PREFERENCE_HIGH); + if (err) + return err; + initrd_mem = get_virtual_current_address (ch); + initrd_mem_target = get_physical_target_address (ch); + } if (grub_file_read (file, initrd_mem, size) != size) { @@ -993,7 +1135,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n", (unsigned) addr, (unsigned) size); - lh->ramdisk_image = addr; + lh->ramdisk_image = initrd_mem_target; lh->ramdisk_size = size; lh->root_dev = 0x0100; /* XXX */ diff --git a/grub-core/loader/i386/linux_trampoline.S b/grub-core/loader/i386/linux_trampoline.S deleted file mode 100644 index 4acea7b11..000000000 --- a/grub-core/loader/i386/linux_trampoline.S +++ /dev/null @@ -1,129 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include - - - .p2align 4 /* force 16-byte alignment */ -VARIABLE(grub_linux_trampoline_start) - cli - /* %rdi contains protected memory start and %rsi - contains real memory start. */ - - mov %rsi, %rbx - - call base -base: - pop %rsi - -#ifdef APPLE_CC - lea (cont1 - base) (%esi, 1), %rax - mov %eax, (jump_vector - base) (%esi, 1) - - lea (gdt - base) (%esi, 1), %rax - mov %rax, (gdtaddr - base) (%esi, 1) - - /* Switch to compatibility mode. */ - - lidt (idtdesc - base) (%esi, 1) - lgdt (gdtdesc - base) (%esi, 1) - - /* Update %cs. Thanks to David Miller for pointing this mistake out. */ - ljmp *(jump_vector - base) (%esi, 1) -#else - lea (cont1 - base) (%rsi, 1), %rax - mov %eax, (jump_vector - base) (%rsi, 1) - - lea (gdt - base) (%rsi, 1), %rax - mov %rax, (gdtaddr - base) (%rsi, 1) - - /* Switch to compatibility mode. */ - - lidt (idtdesc - base) (%rsi, 1) - lgdt (gdtdesc - base) (%rsi, 1) - - /* Update %cs. Thanks to David Miller for pointing this mistake out. */ - ljmp *(jump_vector - base) (%rsi, 1) -#endif - -cont1: - .code32 - - /* Update other registers. */ - mov $0x18, %eax - mov %eax, %ds - mov %eax, %es - mov %eax, %fs - mov %eax, %gs - mov %eax, %ss - - /* Disable paging. */ - mov %cr0, %eax - and $0x7fffffff, %eax - mov %eax, %cr0 - - /* Disable amd64. */ - mov $0xc0000080, %ecx - rdmsr - and $0xfffffeff, %eax - wrmsr - - /* Turn off PAE. */ - movl %cr4, %eax - and $0xffffffcf, %eax - mov %eax, %cr4 - - jmp cont2 -cont2: - .code32 - - mov %ebx, %esi - - jmp *%edi - - /* GDT. */ - .p2align 4 -gdt: - /* NULL. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Reserved. */ - .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - /* Code segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00 - - /* Data segment. */ - .byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 - -gdtdesc: - .word 31 -gdtaddr: - .quad gdt - -idtdesc: - .word 0 -idtaddr: - .quad 0 - - .p2align 4 -jump_vector: - /* Jump location. Is filled by the code */ - .long 0 - .long 0x10 -VARIABLE(grub_linux_trampoline_end) diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index d984e4e4e..bf17863cf 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -22,7 +22,6 @@ #include #endif #include -#include #include #include #include @@ -30,6 +29,7 @@ #include #include #include +#include #include #include @@ -52,6 +52,10 @@ static unsigned modcnt; static char *cmdline = NULL; static grub_uint32_t bootdev; static int bootdev_set; +static grub_size_t elf_sec_num, elf_sec_entsize; +static unsigned elf_sec_shstrndx; +static void *elf_sections; + grub_err_t grub_multiboot_load (grub_file_t file) @@ -103,25 +107,24 @@ grub_multiboot_load (grub_file_t file) int load_size = ((header->load_end_addr == 0) ? file->size - offset : header->load_end_addr - header->load_addr); grub_size_t code_size; + void *source; + grub_relocator_chunk_t ch; if (header->bss_end_addr) code_size = (header->bss_end_addr - header->load_addr); else code_size = load_size; - grub_multiboot_payload_dest = header->load_addr; - grub_multiboot_pure_size += code_size; - - /* Allocate a bit more to avoid relocations in most cases. */ - grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; - grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); - - if (! grub_multiboot_payload_orig) + err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, + &ch, header->load_addr, + code_size); + if (err) { + grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); grub_free (buffer); - return grub_errno; + return err; } + source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { @@ -129,7 +132,7 @@ grub_multiboot_load (grub_file_t file) return grub_errno; } - grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + grub_file_read (file, source, load_size); if (grub_errno) { grub_free (buffer); @@ -137,11 +140,10 @@ grub_multiboot_load (grub_file_t file) } if (header->bss_end_addr) - grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + grub_memset ((grub_uint32_t *) source + load_size, 0, header->bss_end_addr - header->load_addr - load_size); grub_multiboot_payload_eip = header->entry_addr; - } else { @@ -184,13 +186,14 @@ grub_multiboot_load (grub_file_t file) return err; } -grub_size_t +static grub_size_t grub_multiboot_get_mbi_size (void) { return sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4) + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd + ALIGN_UP (sizeof(PACKAGE_STRING), 4) + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry) + + elf_sec_entsize * elf_sec_num + 256 * sizeof (struct multiboot_color); } @@ -309,20 +312,32 @@ retrieve_video_parameters (struct multiboot_info *mbi, } grub_err_t -grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, - grub_size_t bufsize) +grub_multiboot_make_mbi (grub_uint32_t *target) { - grub_uint8_t *ptrorig = (grub_uint8_t *) orig + buf_off; - grub_uint32_t ptrdest = dest + buf_off; struct multiboot_info *mbi; struct multiboot_mod_list *modlist; unsigned i; struct module *cur; grub_size_t mmap_size; - grub_err_t err; + grub_uint8_t *ptrorig; + grub_addr_t ptrdest; - if (bufsize < grub_multiboot_get_mbi_size ()) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + grub_err_t err; + grub_size_t bufsize; + grub_relocator_chunk_t ch; + + bufsize = grub_multiboot_get_mbi_size (); + + err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, + 0, 0xffffffff - bufsize, + bufsize, 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + ptrorig = get_virtual_current_address (ch); + ptrdest = (grub_addr_t) get_virtual_current_address (ch); + + *target = ptrdest; mbi = (struct multiboot_info *) ptrorig; ptrorig += sizeof (*mbi); @@ -386,6 +401,17 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, mbi->flags |= MULTIBOOT_INFO_BOOTDEV; } + if (elf_sec_num) + { + mbi->u.elf_sec.addr = ptrdest; + grub_memcpy (ptrorig, elf_sections, elf_sec_entsize * elf_sec_num); + mbi->u.elf_sec.num = elf_sec_num; + mbi->u.elf_sec.size = elf_sec_entsize; + mbi->u.elf_sec.shndx = elf_sec_shstrndx; + + mbi->flags |= MULTIBOOT_INFO_ELF_SHDR; + } + err = retrieve_video_parameters (mbi, ptrorig, ptrdest); if (err) { @@ -396,6 +422,16 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, return GRUB_ERR_NONE; } +void +grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize, + unsigned shndx, void *data) +{ + elf_sec_num = num; + elf_sec_shstrndx = shndx; + elf_sec_entsize = entsize; + elf_sections = data; +} + void grub_multiboot_free_mbi (void) { @@ -416,6 +452,11 @@ grub_multiboot_free_mbi (void) } modules = NULL; modules_last = NULL; + + grub_free (elf_sections); + elf_sections = NULL; + elf_sec_entsize = 0; + elf_sec_num = 0; } grub_err_t diff --git a/grub-core/loader/i386/pc/chainloader.c b/grub-core/loader/i386/pc/chainloader.c index 502031d0e..e76f84f08 100644 --- a/grub-core/loader/i386/pc/chainloader.c +++ b/grub-core/loader/i386/pc/chainloader.c @@ -69,6 +69,7 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags) grub_dl_ref (my_mod); + grub_file_filter_disable_compression (); file = grub_file_open (filename); if (! file) goto fail; diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index 04bc66661..2f5dfec70 100644 --- a/grub-core/loader/i386/pc/linux.c +++ b/grub-core/loader/i386/pc/linux.c @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include #define GRUB_LINUX_CL_OFFSET 0x9000 #define GRUB_LINUX_CL_END_OFFSET 0x90FF @@ -41,22 +43,37 @@ static grub_dl_t my_mod; static grub_size_t linux_mem_size; static int loaded; +static struct grub_relocator *relocator = NULL; +static grub_addr_t grub_linux_real_target; +static char *grub_linux_real_chunk; +static grub_size_t grub_linux16_prot_size; + +static grub_err_t +grub_linux16_boot (void) +{ + grub_uint16_t segment; + struct grub_relocator16_state state; + + segment = grub_linux_real_target >> 4; + state.gs = state.fs = state.es = state.ds = state.ss = segment; + state.sp = GRUB_LINUX_SETUP_STACK; + state.cs = segment + 0x20; + state.ip = 0; + + grub_video_set_mode ("text", 0, 0); + + grub_stop_floppy (); + + return grub_relocator16_boot (relocator, state); +} static grub_err_t grub_linux_unload (void) { grub_dl_unref (my_mod); loaded = 0; - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_linux16_boot (void) -{ - grub_video_set_mode ("text", 0, 0); - grub_linux16_real_boot (); - - /* Not reached. */ + grub_relocator_unload (relocator); + relocator = NULL; return GRUB_ERR_NONE; } @@ -67,10 +84,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_file_t file = 0; struct linux_kernel_header lh; grub_uint8_t setup_sects; - grub_size_t real_size, prot_size; + grub_size_t real_size; grub_ssize_t len; int i; char *dest; + char *grub_linux_prot_chunk; + int grub_linux_is_bzimage; + grub_addr_t grub_linux_prot_target; + grub_err_t err; grub_dl_ref (my_mod); @@ -84,14 +105,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (! file) goto fail; - if ((grub_size_t) grub_file_size (file) > grub_os_area_size) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "too big kernel (0x%x > 0x%x)", - (grub_size_t) grub_file_size (file), - grub_os_area_size); - goto fail; - } - if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { grub_error (GRUB_ERR_READ_ERROR, "cannot read the Linux header"); @@ -121,12 +134,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), lh.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE; /* Put the real mode part at as a high location as possible. */ - grub_linux_real_addr - = (char *) UINT_TO_PTR (grub_mmap_get_lower () - - GRUB_LINUX_SETUP_MOVE_SIZE); + grub_linux_real_target = grub_mmap_get_lower () + - GRUB_LINUX_SETUP_MOVE_SIZE; /* But it must not exceed the traditional area. */ - if (grub_linux_real_addr > (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR) - grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR; + if (grub_linux_real_target > GRUB_LINUX_OLD_REAL_MODE_ADDR) + grub_linux_real_target = GRUB_LINUX_OLD_REAL_MODE_ADDR; if (grub_le_to_cpu16 (lh.version) >= 0x0201) { @@ -135,7 +147,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), } if (grub_le_to_cpu16 (lh.version) >= 0x0202) - lh.cmd_line_ptr = grub_linux_real_addr + GRUB_LINUX_CL_OFFSET; + lh.cmd_line_ptr = grub_linux_real_target + GRUB_LINUX_CL_OFFSET; else { lh.cl_magic = grub_cpu_to_le16 (GRUB_LINUX_CL_MAGIC); @@ -151,7 +163,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; - grub_linux_real_addr = (char *) GRUB_LINUX_OLD_REAL_MODE_ADDR; + grub_linux_real_target = GRUB_LINUX_OLD_REAL_MODE_ADDR; } /* If SETUP_SECTS is not set, set it to the default (4). */ @@ -159,32 +171,36 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS; real_size = setup_sects << GRUB_DISK_SECTOR_BITS; - prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - - grub_linux_tmp_addr = (char *) GRUB_LINUX_BZIMAGE_ADDR + prot_size; + grub_linux16_prot_size = grub_file_size (file) + - real_size - GRUB_DISK_SECTOR_SIZE; if (! grub_linux_is_bzimage - && ((char *) GRUB_LINUX_ZIMAGE_ADDR + prot_size > grub_linux_real_addr)) + && GRUB_LINUX_ZIMAGE_ADDR + grub_linux16_prot_size + > grub_linux_real_target) { grub_error (GRUB_ERR_BAD_OS, "too big zImage (0x%x > 0x%x), use bzImage instead", - (char *) GRUB_LINUX_ZIMAGE_ADDR + prot_size, - (grub_size_t) grub_linux_real_addr); + (char *) GRUB_LINUX_ZIMAGE_ADDR + grub_linux16_prot_size, + (grub_size_t) grub_linux_real_target); goto fail; } - if (grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE - > (char *) UINT_TO_PTR (grub_mmap_get_lower ())) + if (grub_linux_real_target + GRUB_LINUX_SETUP_MOVE_SIZE + > grub_mmap_get_lower ()) { grub_error (GRUB_ERR_OUT_OF_RANGE, "too small lower memory (0x%x > 0x%x)", - grub_linux_real_addr + GRUB_LINUX_SETUP_MOVE_SIZE, + grub_linux_real_target + GRUB_LINUX_SETUP_MOVE_SIZE, (int) grub_mmap_get_lower ()); goto fail; } - grub_dprintf ("linux", "Linux-%s, setup=0x%x, size=0x%x\n", - grub_linux_is_bzimage ? "bzImage" : "zImage", - real_size, prot_size); + grub_printf (" [Linux-%s, setup=0x%x, size=0x%x]\n", + grub_linux_is_bzimage ? "bzImage" : "zImage", real_size, + grub_linux16_prot_size); + + relocator = grub_relocator_new (); + if (!relocator) + goto fail; for (i = 1; i < argc; i++) if (grub_memcmp (argv[i], "vga=", 4) == 0) @@ -242,11 +258,21 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), } } + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + grub_linux_real_target, + GRUB_LINUX_SETUP_MOVE_SIZE); + if (err) + return err; + grub_linux_real_chunk = get_virtual_current_address (ch); + } + /* Put the real mode code at the temporary address. */ - grub_memmove (grub_linux_tmp_addr, &lh, sizeof (lh)); + grub_memmove (grub_linux_real_chunk, &lh, sizeof (lh)); len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh); - if (grub_file_read (file, grub_linux_tmp_addr + sizeof (lh), len) != len) + if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len) { grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; @@ -255,21 +281,21 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), if (lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE) || grub_le_to_cpu16 (lh.version) < 0x0200) /* Clear the heap space. */ - grub_memset (grub_linux_tmp_addr + grub_memset (grub_linux_real_chunk + ((setup_sects + 1) << GRUB_DISK_SECTOR_BITS), 0, ((GRUB_LINUX_MAX_SETUP_SECTS - setup_sects - 1) << GRUB_DISK_SECTOR_BITS)); /* Specify the boot file. */ - dest = grub_stpcpy (grub_linux_tmp_addr + GRUB_LINUX_CL_OFFSET, + dest = grub_stpcpy (grub_linux_real_chunk + GRUB_LINUX_CL_OFFSET, "BOOT_IMAGE="); dest = grub_stpcpy (dest, argv[0]); /* Copy kernel parameters. */ for (i = 1; i < argc - && dest + grub_strlen (argv[i]) + 1 < (grub_linux_tmp_addr + && dest + grub_strlen (argv[i]) + 1 < (grub_linux_real_chunk + GRUB_LINUX_CL_END_OFFSET); i++) { @@ -277,14 +303,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), dest = grub_stpcpy (dest, argv[i]); } - len = prot_size; - if (grub_file_read (file, (void *) GRUB_LINUX_BZIMAGE_ADDR, len) != len) + if (grub_linux_is_bzimage) + grub_linux_prot_target = GRUB_LINUX_BZIMAGE_ADDR; + else + grub_linux_prot_target = GRUB_LINUX_ZIMAGE_ADDR; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + grub_linux_prot_target, + grub_linux16_prot_size); + if (err) + return err; + grub_linux_prot_chunk = get_virtual_current_address (ch); + } + + len = grub_linux16_prot_size; + if (grub_file_read (file, grub_linux_prot_chunk, grub_linux16_prot_size) + != (grub_ssize_t) grub_linux16_prot_size) grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); if (grub_errno == GRUB_ERR_NONE) { - grub_linux_prot_size = prot_size; - grub_loader_set (grub_linux16_boot, grub_linux_unload, 1); + grub_loader_set (grub_linux16_boot, grub_linux_unload, 0); loaded = 1; } @@ -297,6 +337,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), { grub_dl_unref (my_mod); loaded = 0; + grub_relocator_unload (relocator); } return grub_errno; @@ -308,8 +349,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file = 0; grub_ssize_t size; - grub_addr_t addr_max, addr_min, addr; + grub_addr_t addr_max, addr_min; struct linux_kernel_header *lh; + grub_uint8_t *initrd_chunk; + grub_addr_t initrd_addr; + grub_err_t err; if (argc == 0) { @@ -323,7 +367,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } - lh = (struct linux_kernel_header *) grub_linux_tmp_addr; + lh = (struct linux_kernel_header *) grub_linux_real_chunk; if (!(lh->header == grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE) && grub_le_to_cpu16 (lh->version) >= 0x0200)) @@ -355,33 +399,34 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), worse than that of Linux 2.3.xx, so avoid the last 64kb. */ addr_max -= 0x10000; - if (addr_max > grub_os_area_addr + grub_os_area_size) - addr_max = grub_os_area_addr + grub_os_area_size; - - addr_min = (grub_addr_t) grub_linux_tmp_addr + GRUB_LINUX_CL_END_OFFSET; + addr_min = GRUB_LINUX_BZIMAGE_ADDR + grub_linux16_prot_size; + grub_file_filter_disable_compression (); file = grub_file_open (argv[0]); if (!file) goto fail; size = grub_file_size (file); - /* Put the initrd as high as possible, 4KiB aligned. */ - addr = (addr_max - size) & ~0xFFF; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (relocator, &ch, + addr_min, addr_max - size, + size, 0x1000, + GRUB_RELOCATOR_PREFERENCE_HIGH); + if (err) + return err; + initrd_chunk = get_virtual_current_address (ch); + initrd_addr = get_physical_target_address (ch); + } - if (addr < addr_min) - { - grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big"); - goto fail; - } - - if (grub_file_read (file, (void *) addr, size) != size) + if (grub_file_read (file, initrd_chunk, size) != size) { grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); goto fail; } - lh->ramdisk_image = addr; + lh->ramdisk_image = initrd_addr; lh->ramdisk_size = size; fail: diff --git a/grub-core/loader/i386/pc/ntldr.c b/grub-core/loader/i386/pc/ntldr.c new file mode 100644 index 000000000..0c33a0680 --- /dev/null +++ b/grub-core/loader/i386/pc/ntldr.c @@ -0,0 +1,157 @@ +/* chainloader.c - boot another boot loader */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2004,2007,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_dl_t my_mod; +static struct grub_relocator *rel; +static grub_uint32_t edx = 0xffffffff; + +#define GRUB_NTLDR_SEGMENT 0x2000 + +static grub_err_t +grub_ntldr_boot (void) +{ + struct grub_relocator16_state state = { + .cs = GRUB_NTLDR_SEGMENT, + .ip = 0, + .ds = 0, + .es = 0, + .fs = 0, + .gs = 0, + .ss = 0, + .sp = 0x7c00, + .edx = edx + }; + grub_video_set_mode ("text", 0, 0); + + return grub_relocator16_boot (rel, state); +} + +static grub_err_t +grub_ntldr_unload (void) +{ + grub_relocator_unload (rel); + rel = NULL; + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_ntldr (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_err_t err; + void *bs, *ntldr; + grub_size_t ntldrsize; + grub_device_t dev; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified"); + + grub_dl_ref (my_mod); + + rel = grub_relocator_new (); + if (!rel) + goto fail; + + file = grub_file_open (argv[0]); + if (! file) + goto fail; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (rel, &ch, 0x7C00, + GRUB_DISK_SECTOR_SIZE); + if (err) + goto fail; + bs = get_virtual_current_address (ch); + } + + edx = grub_get_root_biosnumber (); + dev = grub_device_open (0); + + if (dev && dev->disk) + { + err = grub_disk_read (dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, bs); + if (err) + { + grub_device_close (dev); + goto fail; + } + } + + if (dev) + grub_device_close (dev); + + ntldrsize = grub_file_size (file); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (rel, &ch, GRUB_NTLDR_SEGMENT << 4, + ntldrsize); + if (err) + goto fail; + ntldr = get_virtual_current_address (ch); + } + + if (grub_file_read (file, ntldr, ntldrsize) + != (grub_ssize_t) ntldrsize) + goto fail; + + grub_loader_set (grub_ntldr_boot, grub_ntldr_unload, 1); + return GRUB_ERR_NONE; + + fail: + + if (file) + grub_file_close (file); + + grub_ntldr_unload (); + + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(ntldr) +{ + cmd = grub_register_command ("ntldr", grub_cmd_ntldr, + 0, N_("Load NTLDR or BootMGR.")); + my_mod = mod; +} + +GRUB_MOD_FINI(ntldr) +{ + grub_unregister_command (cmd); +} diff --git a/grub-core/loader/i386/xnu.c b/grub-core/loader/i386/xnu.c index 5f18d744b..a9435eff3 100644 --- a/grub-core/loader/i386/xnu.c +++ b/grub-core/loader/i386/xnu.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -41,7 +40,6 @@ #define DEFAULT_VIDEO_MODE "auto" char grub_xnu_cmdline[1024]; -grub_uint32_t grub_xnu_heap_will_be_at; grub_uint32_t grub_xnu_entry_point, grub_xnu_arg1, grub_xnu_stack; /* Aliases set for some tables. */ @@ -536,7 +534,7 @@ grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)), if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); - file = grub_gzfile_open (args[0], 1); + file = grub_file_open (args[0]); if (! file) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't load device-propertie dump"); @@ -837,11 +835,11 @@ grub_xnu_boot_resume (void) struct grub_relocator32_state state; state.esp = grub_xnu_stack; + state.ebp = grub_xnu_stack; state.eip = grub_xnu_entry_point; state.eax = grub_xnu_arg1; - return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at, - state); + return grub_relocator32_boot (grub_xnu_relocator, state); } /* Setup video for xnu. */ @@ -883,6 +881,18 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters"); if (grub_xnu_bitmap) + { + if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH) + err = grub_video_bitmap_create_scaled (&bitmap, + mode_info.width, + mode_info.height, + grub_xnu_bitmap, + GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST); + else + bitmap = grub_xnu_bitmap; + } + + if (bitmap) { if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH) err = grub_video_bitmap_create_scaled (&bitmap, @@ -940,18 +950,18 @@ grub_xnu_set_video (struct grub_xnu_boot_params *params) grub_err_t grub_xnu_boot (void) { - struct grub_xnu_boot_params *bootparams_relloc; - grub_off_t bootparams_relloc_off; - grub_off_t mmap_relloc_off; + struct grub_xnu_boot_params *bootparams; + grub_addr_t bootparams_target; grub_err_t err; grub_efi_uintn_t memory_map_size = 0; grub_efi_memory_descriptor_t *memory_map; + grub_addr_t memory_map_target; grub_efi_uintn_t map_key = 0; grub_efi_uintn_t descriptor_size = 0; grub_efi_uint32_t descriptor_version = 0; grub_uint64_t firstruntimepage, lastruntimepage; grub_uint64_t curruntimepage; - void *devtree; + grub_addr_t devtree_target; grub_size_t devtreelen; int i; struct grub_relocator32_state state; @@ -995,26 +1005,25 @@ grub_xnu_boot (void) } /* Relocate the boot parameters to heap. */ - bootparams_relloc = grub_xnu_heap_malloc (sizeof (*bootparams_relloc)); - if (! bootparams_relloc) - return grub_errno; - bootparams_relloc_off = (grub_uint8_t *) bootparams_relloc - - (grub_uint8_t *) grub_xnu_heap_start; + err = grub_xnu_heap_malloc (sizeof (*bootparams), + (void **) &bootparams, &bootparams_target); + if (err) + return err; /* Set video. */ - err = grub_xnu_set_video (bootparams_relloc); + err = grub_xnu_set_video (bootparams); if (err != GRUB_ERR_NONE) { grub_print_error (); grub_errno = GRUB_ERR_NONE; grub_printf ("Booting in blind mode\n"); - bootparams_relloc->lfb_mode = 0; - bootparams_relloc->lfb_width = 0; - bootparams_relloc->lfb_height = 0; - bootparams_relloc->lfb_depth = 0; - bootparams_relloc->lfb_line_len = 0; - bootparams_relloc->lfb_base = 0; + bootparams->lfb_mode = 0; + bootparams->lfb_width = 0; + bootparams->lfb_height = 0; + bootparams->lfb_depth = 0; + bootparams->lfb_line_len = 0; + bootparams->lfb_base = 0; } if (grub_autoefi_get_memory_map (&memory_map_size, memory_map, @@ -1025,38 +1034,30 @@ grub_xnu_boot (void) /* We will do few allocations later. Reserve some space for possible memory map growth. */ memory_map_size += 20 * descriptor_size; - memory_map = grub_xnu_heap_malloc (memory_map_size); - if (! memory_map) - return grub_errno; - mmap_relloc_off = (grub_uint8_t *) memory_map - - (grub_uint8_t *) grub_xnu_heap_start; - - err = grub_xnu_writetree_toheap (&devtree, &devtreelen); + err = grub_xnu_heap_malloc (memory_map_size, + (void **) &memory_map, &memory_map_target); if (err) return err; - bootparams_relloc = (struct grub_xnu_boot_params *) - (bootparams_relloc_off + (grub_uint8_t *) grub_xnu_heap_start); - grub_memcpy (bootparams_relloc->cmdline, grub_xnu_cmdline, - sizeof (bootparams_relloc->cmdline)); + err = grub_xnu_writetree_toheap (&devtree_target, &devtreelen); + if (err) + return err; - bootparams_relloc->devtree - = ((grub_uint8_t *) devtree - (grub_uint8_t *) grub_xnu_heap_start) - + grub_xnu_heap_will_be_at; - bootparams_relloc->devtreelen = devtreelen; + grub_memcpy (bootparams->cmdline, grub_xnu_cmdline, + sizeof (bootparams->cmdline)); - memory_map = (grub_efi_memory_descriptor_t *) - ((grub_uint8_t *) grub_xnu_heap_start + mmap_relloc_off); + bootparams->devtree = devtree_target; + bootparams->devtreelen = devtreelen; - if (grub_autoefi_get_memory_map (&memory_map_size, memory_map, - &map_key, &descriptor_size, - &descriptor_version) <= 0) - return grub_errno; + err = grub_autoefi_finish_boot_services (&memory_map_size, memory_map, + &map_key, &descriptor_size, + &descriptor_version); + if (err) + return err; - bootparams_relloc->efi_system_table - = PTR_TO_UINT32 (grub_autoefi_system_table); + bootparams->efi_system_table = PTR_TO_UINT32 (grub_autoefi_system_table); - firstruntimepage = (((grub_addr_t) grub_xnu_heap_will_be_at + firstruntimepage = (((grub_addr_t) grub_xnu_heap_target_start + grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1) / GRUB_XNU_PAGESIZE) + 20; curruntimepage = firstruntimepage; @@ -1077,7 +1078,7 @@ grub_xnu_boot (void) <= PTR_TO_UINT64 (grub_autoefi_system_table) && curdesc->physical_start + (curdesc->num_pages << 12) > PTR_TO_UINT64 (grub_autoefi_system_table)) - bootparams_relloc->efi_system_table + bootparams->efi_system_table = PTR_TO_UINT64 (grub_autoefi_system_table) - curdesc->physical_start + curdesc->virtual_start; if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit) @@ -1087,28 +1088,25 @@ grub_xnu_boot (void) lastruntimepage = curruntimepage; - bootparams_relloc->efi_mmap = grub_xnu_heap_will_be_at + mmap_relloc_off; - bootparams_relloc->efi_mmap_size = memory_map_size; - bootparams_relloc->efi_mem_desc_size = descriptor_size; - bootparams_relloc->efi_mem_desc_version = descriptor_version; + bootparams->efi_mmap = memory_map_target; + bootparams->efi_mmap_size = memory_map_size; + bootparams->efi_mem_desc_size = descriptor_size; + bootparams->efi_mem_desc_version = descriptor_version; - bootparams_relloc->heap_start = grub_xnu_heap_will_be_at; - bootparams_relloc->heap_size = grub_xnu_heap_size; - bootparams_relloc->efi_runtime_first_page = firstruntimepage; + bootparams->heap_start = grub_xnu_heap_target_start; + bootparams->heap_size = grub_xnu_heap_size; + bootparams->efi_runtime_first_page = firstruntimepage; - bootparams_relloc->efi_runtime_npages = lastruntimepage - firstruntimepage; - bootparams_relloc->efi_uintnbits = SIZEOF_OF_UINTN * 8; + bootparams->efi_runtime_npages = lastruntimepage - firstruntimepage; + bootparams->efi_uintnbits = SIZEOF_OF_UINTN * 8; - bootparams_relloc->verminor = GRUB_XNU_BOOTARGS_VERMINOR; - bootparams_relloc->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR; + bootparams->verminor = GRUB_XNU_BOOTARGS_VERMINOR; + bootparams->vermajor = GRUB_XNU_BOOTARGS_VERMAJOR; /* Parameters for asm helper. */ - grub_xnu_stack = bootparams_relloc->heap_start - + bootparams_relloc->heap_size + GRUB_XNU_PAGESIZE; - grub_xnu_arg1 = bootparams_relloc_off + grub_xnu_heap_will_be_at; - - if (! grub_autoefi_exit_boot_services (map_key)) - return grub_error (GRUB_ERR_IO, "can't exit boot services"); + grub_xnu_stack = bootparams->heap_start + + bootparams->heap_size + GRUB_XNU_PAGESIZE; + grub_xnu_arg1 = bootparams_target; grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size, descriptor_version,memory_map); @@ -1116,8 +1114,8 @@ grub_xnu_boot (void) state.eip = grub_xnu_entry_point; state.eax = grub_xnu_arg1; state.esp = grub_xnu_stack; - return grub_relocator32_boot (grub_xnu_heap_start, grub_xnu_heap_will_be_at, - state); + state.ebp = grub_xnu_stack; + return grub_relocator32_boot (grub_xnu_relocator, state); } static grub_command_t cmd_devprop_load; diff --git a/grub-core/loader/macho.c b/grub-core/loader/macho.c index 199d6f111..ecf0d8c53 100644 --- a/grub-core/loader/macho.c +++ b/grub-core/loader/macho.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -149,7 +148,7 @@ grub_macho_open (const char *name) grub_file_t file; grub_macho_t macho; - file = grub_gzfile_open (name, 1); + file = grub_file_open (name); if (! file) return 0; diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c index 64497f466..48f77dffb 100644 --- a/grub-core/loader/mips/linux.c +++ b/grub-core/loader/mips/linux.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -33,15 +32,13 @@ #include #include -#define ELF32_LOADMASK (0x00000000UL) -#define ELF64_LOADMASK (0x0000000000000000ULL) - static grub_dl_t my_mod; static int loaded; static grub_size_t linux_size; +static struct grub_relocator *relocator; static grub_uint8_t *playground; static grub_addr_t target_addr, entry_addr; static int linux_argc; @@ -60,15 +57,7 @@ grub_linux_boot (void) state.gpr[5] = target_addr + argv_off; state.gpr[6] = target_addr + envp_off; state.jumpreg = 1; - grub_relocator32_boot (playground, target_addr, state); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_linux_release_mem (void) -{ - grub_relocator32_free (playground); + grub_relocator32_boot (relocator, state); return GRUB_ERR_NONE; } @@ -76,14 +65,12 @@ grub_linux_release_mem (void) static grub_err_t grub_linux_unload (void) { - grub_err_t err; - - err = grub_linux_release_mem (); + grub_relocator_unload (relocator); grub_dl_unref (my_mod); loaded = 0; - return err; + return GRUB_ERR_NONE; } static grub_err_t @@ -91,9 +78,10 @@ grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) { Elf32_Addr base; int extraoff; + grub_err_t err; /* Linux's entry point incorrectly contains a virtual address. */ - entry_addr = elf->ehdr.ehdr32.e_entry & ~ELF32_LOADMASK; + entry_addr = elf->ehdr.ehdr32.e_entry; linux_size = grub_elf32_size (elf, &base); if (linux_size == 0) @@ -105,10 +93,20 @@ grub_linux_load32 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) extraoff = linux_size; linux_size += extra_size; - playground = grub_relocator32_alloc (linux_size); - if (!playground) + relocator = grub_relocator_new (); + if (!relocator) return grub_errno; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + target_addr & 0x1fffffff, + linux_size); + if (err) + return err; + playground = get_virtual_current_address (ch); + } + *extra_mem = playground + extraoff; /* Now load the segments into the area we claimed. */ @@ -135,9 +133,10 @@ grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) { Elf64_Addr base; int extraoff; + grub_err_t err; /* Linux's entry point incorrectly contains a virtual address. */ - entry_addr = elf->ehdr.ehdr64.e_entry & ~ELF64_LOADMASK; + entry_addr = elf->ehdr.ehdr64.e_entry; linux_size = grub_elf64_size (elf, &base); if (linux_size == 0) @@ -149,10 +148,20 @@ grub_linux_load64 (grub_elf_t elf, void **extra_mem, grub_size_t extra_size) extraoff = linux_size; linux_size += extra_size; - playground = grub_relocator32_alloc (linux_size); - if (!playground) + relocator = grub_relocator_new (); + if (!relocator) return grub_errno; + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (relocator, &ch, + target_addr & 0x1fffffff, + linux_size); + if (err) + return err; + playground = get_virtual_current_address (ch); + } + *extra_mem = playground + extraoff; /* Now load the segments into the area we claimed. */ @@ -322,7 +331,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file = 0; grub_ssize_t size; - grub_size_t overhead; + void *initrd_src; + grub_addr_t initrd_dest; + grub_err_t err; if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified"); @@ -333,25 +344,32 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), if (initrd_loaded) return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd can be loaded."); + grub_file_filter_disable_compression (); file = grub_file_open (argv[0]); if (! file) return grub_errno; size = grub_file_size (file); - overhead = ALIGN_UP (target_addr + linux_size + 0x10000, 0x10000) - - (target_addr + linux_size); + { + grub_relocator_chunk_t ch; - playground = grub_relocator32_realloc (playground, - linux_size + overhead + size); + err = grub_relocator_alloc_chunk_align (relocator, &ch, + target_addr + linux_size + 0x10000, + (0xffffffff - size) + 1, + size, 0x10000, + GRUB_RELOCATOR_PREFERENCE_NONE); - if (!playground) - { - grub_file_close (file); - return grub_errno; - } + if (err) + { + grub_file_close (file); + return err; + } + initrd_src = get_virtual_current_address (ch); + initrd_dest = get_physical_target_address (ch) | 0x80000000; + } - if (grub_file_read (file, playground + linux_size + overhead, size) != size) + if (grub_file_read (file, initrd_src, size) != size) { grub_error (GRUB_ERR_FILE_READ_ERROR, "couldn't read file"); grub_file_close (file); @@ -361,7 +379,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), grub_snprintf ((char *) playground + rd_addr_arg_off, sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%llx", - (unsigned long long) target_addr + linux_size + overhead); + (unsigned long long) initrd_dest); ((grub_uint32_t *) (playground + argv_off))[linux_argc] = target_addr + rd_addr_arg_off; linux_argc++; diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index b4ea8bf21..8780ec061 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -29,9 +29,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -50,18 +49,14 @@ #include #endif +struct grub_relocator *grub_multiboot_relocator = NULL; +grub_uint32_t grub_multiboot_payload_eip; #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU) #define DEFAULT_VIDEO_MODE "text" #else #define DEFAULT_VIDEO_MODE "auto" #endif -grub_size_t grub_multiboot_alloc_mbi; - -char *grub_multiboot_payload_orig; -grub_addr_t grub_multiboot_payload_dest; -grub_size_t grub_multiboot_pure_size; -grub_uint32_t grub_multiboot_payload_eip; static int accepts_video; static int accepts_ega_text; static int console_required; @@ -119,45 +114,23 @@ grub_multiboot_set_video_mode (void) static grub_err_t grub_multiboot_boot (void) { - grub_size_t mbi_size; grub_err_t err; struct grub_relocator32_state state = MULTIBOOT_INITIAL_STATE; state.MULTIBOOT_ENTRY_REGISTER = grub_multiboot_payload_eip; - mbi_size = grub_multiboot_get_mbi_size (); - if (grub_multiboot_alloc_mbi < mbi_size) - { - grub_multiboot_payload_orig - = grub_relocator32_realloc (grub_multiboot_payload_orig, - grub_multiboot_pure_size + mbi_size); - if (!grub_multiboot_payload_orig) - return grub_errno; - grub_multiboot_alloc_mbi = mbi_size; - } + err = grub_multiboot_make_mbi (&state.MULTIBOOT_MBI_REGISTER); -#ifdef GRUB_USE_MULTIBOOT2 - state.MULTIBOOT_MBI_REGISTER = ALIGN_UP (grub_multiboot_payload_dest - + grub_multiboot_pure_size, - MULTIBOOT_TAG_ALIGN); -#else - state.MULTIBOOT_MBI_REGISTER = grub_multiboot_payload_dest - + grub_multiboot_pure_size; -#endif - err = grub_multiboot_make_mbi (grub_multiboot_payload_orig, - grub_multiboot_payload_dest, - grub_multiboot_pure_size, mbi_size); if (err) return err; #ifdef GRUB_MACHINE_EFI - if (! grub_efi_finish_boot_services ()) - grub_fatal ("cannot exit boot services"); + err = grub_efi_finish_boot_services (NULL, NULL, NULL, NULL, NULL); + if (err) + return err; #endif - grub_relocator32_boot (grub_multiboot_payload_orig, - grub_multiboot_payload_dest, - state); + grub_relocator32_boot (grub_multiboot_relocator, state); /* Not reached. */ return GRUB_ERR_NONE; @@ -168,11 +141,9 @@ grub_multiboot_unload (void) { grub_multiboot_free_mbi (); - grub_relocator32_free (grub_multiboot_payload_orig); + grub_relocator_unload (grub_multiboot_relocator); + grub_multiboot_relocator = NULL; - grub_multiboot_alloc_mbi = 0; - - grub_multiboot_payload_orig = NULL; grub_dl_unref (my_mod); return GRUB_ERR_NONE; @@ -253,7 +224,7 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no kernel specified"); - file = grub_gzfile_open (argv[0], 1); + file = grub_file_open (argv[0]); if (! file) return grub_error (GRUB_ERR_BAD_ARGUMENT, "couldn't open file"); @@ -262,8 +233,11 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), /* Skip filename. */ grub_multiboot_init_mbi (argc - 1, argv + 1); - grub_relocator32_free (grub_multiboot_payload_orig); - grub_multiboot_payload_orig = NULL; + grub_relocator_unload (grub_multiboot_relocator); + grub_multiboot_relocator = grub_relocator_new (); + + if (!grub_multiboot_relocator) + goto fail; err = grub_multiboot_load (file); if (err) @@ -279,8 +253,8 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)), if (grub_errno != GRUB_ERR_NONE) { - grub_relocator32_free (grub_multiboot_payload_orig); - grub_multiboot_free_mbi (); + grub_relocator_unload (grub_multiboot_relocator); + grub_multiboot_relocator = NULL; grub_dl_unref (my_mod); } @@ -293,7 +267,8 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file = 0; grub_ssize_t size; - char *module = 0; + void *module = NULL; + grub_addr_t target; grub_err_t err; int nounzip = 0; @@ -310,27 +285,34 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)), if (argc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no module specified"); - if (!grub_multiboot_payload_orig) + if (!grub_multiboot_relocator) return grub_error (GRUB_ERR_BAD_ARGUMENT, "you need to load the multiboot kernel first"); if (nounzip) - file = grub_file_open (argv[0]); - else - file = grub_gzfile_open (argv[0], 1); + grub_file_filter_disable_compression (); + + file = grub_file_open (argv[0]); if (! file) return grub_errno; size = grub_file_size (file); - module = grub_memalign (MULTIBOOT_MOD_ALIGN, size); - if (! module) - { - grub_file_close (file); - return grub_errno; - } + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, + 0, (0xffffffff - size) + 1, + size, MULTIBOOT_MOD_ALIGN, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + { + grub_file_close (file); + return err; + } + module = get_virtual_current_address (ch); + target = (grub_addr_t) get_virtual_current_address (ch); + } - err = grub_multiboot_add_module ((grub_addr_t) module, size, - argc - 1, argv + 1); + err = grub_multiboot_add_module (target, size, argc - 1, argv + 1); if (err) { grub_file_close (file); diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index 78b7c542c..0c29fe9c2 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -51,9 +51,7 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) { Elf_Ehdr *ehdr = (Elf_Ehdr *) buffer; char *phdr_base; - int lowest_segment = -1, highest_segment = -1; int i; - grub_size_t code_size; if (ehdr->e_ident[EI_CLASS] != ELFCLASSXX) return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); @@ -87,55 +85,45 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) phdr_base = (char *) buffer + ehdr->e_phoff; #define phdr(i) ((Elf_Phdr *) (phdr_base + (i) * ehdr->e_phentsize)) - for (i = 0; i < ehdr->e_phnum; i++) - if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0) - { - /* Beware that segment 0 isn't necessarily loadable */ - if (lowest_segment == -1 - || phdr(i)->p_paddr < phdr(lowest_segment)->p_paddr) - lowest_segment = i; - if (highest_segment == -1 - || phdr(i)->p_paddr > phdr(highest_segment)->p_paddr) - highest_segment = i; - } - - if (lowest_segment == -1) - return grub_error (GRUB_ERR_BAD_OS, "ELF contains no loadable segments"); - - code_size = (phdr(highest_segment)->p_paddr + phdr(highest_segment)->p_memsz) - phdr(lowest_segment)->p_paddr; - grub_multiboot_payload_dest = phdr(lowest_segment)->p_paddr; - - grub_multiboot_pure_size += code_size; - - grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; - grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); - - if (!grub_multiboot_payload_orig) - return grub_errno; - /* Load every loadable segment in memory. */ for (i = 0; i < ehdr->e_phnum; i++) { - if (phdr(i)->p_type == PT_LOAD && phdr(i)->p_filesz != 0) + if (phdr(i)->p_type == PT_LOAD) { - char *load_this_module_at = (char *) (grub_multiboot_payload_orig + (long) (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr)); + grub_err_t err; + void *source; grub_dprintf ("multiboot_loader", "segment %d: paddr=0x%lx, memsz=0x%lx, vaddr=0x%lx\n", i, (long) phdr(i)->p_paddr, (long) phdr(i)->p_memsz, (long) phdr(i)->p_vaddr); - if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset) - == (grub_off_t) -1) - return grub_error (GRUB_ERR_BAD_OS, - "invalid offset in program header"); + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, + &ch, phdr(i)->p_paddr, + phdr(i)->p_memsz); + if (err) + { + grub_dprintf ("multiboot_loader", "Error loading phdr %d\n", i); + return err; + } + source = get_virtual_current_address (ch); + } - if (grub_file_read (file, load_this_module_at, phdr(i)->p_filesz) - != (grub_ssize_t) phdr(i)->p_filesz) - return grub_error (GRUB_ERR_BAD_OS, - "couldn't read segment from file"); + if (phdr(i)->p_filesz != 0) + { + if (grub_file_seek (file, (grub_off_t) phdr(i)->p_offset) + == (grub_off_t) -1) + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset in program header"); + + if (grub_file_read (file, source, phdr(i)->p_filesz) + != (grub_ssize_t) phdr(i)->p_filesz) + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read segment from file"); + } if (phdr(i)->p_filesz < phdr(i)->p_memsz) - grub_memset (load_this_module_at + phdr(i)->p_filesz, 0, + grub_memset ((grub_uint8_t *) source + phdr(i)->p_filesz, 0, phdr(i)->p_memsz - phdr(i)->p_filesz); } } @@ -144,14 +132,87 @@ CONCAT(grub_multiboot_load_elf, XX) (grub_file_t file, void *buffer) if (phdr(i)->p_vaddr <= ehdr->e_entry && phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry) { - grub_multiboot_payload_eip = grub_multiboot_payload_dest - + (ehdr->e_entry - phdr(i)->p_vaddr) + (phdr(i)->p_paddr - phdr(lowest_segment)->p_paddr); + grub_multiboot_payload_eip = (ehdr->e_entry - phdr(i)->p_vaddr) + + phdr(i)->p_paddr; break; } if (i == ehdr->e_phnum) return grub_error (GRUB_ERR_BAD_OS, "entry point isn't in a segment"); +#if defined (__i386__) || defined (__x86_64__) + +#elif defined (__mips) + grub_multiboot_payload_eip |= 0x80000000; +#else +#error Please complete this +#endif + + if (ehdr->e_shnum) + { + grub_uint8_t *shdr, *shdrptr; + + shdr = grub_malloc (ehdr->e_shnum * ehdr->e_shentsize); + if (!shdr) + return grub_errno; + + if (grub_file_seek (file, ehdr->e_shoff) == (grub_off_t) -1) + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset to section headers"); + + if (grub_file_read (file, shdr, ehdr->e_shnum * ehdr->e_shentsize) + != (grub_ssize_t) ehdr->e_shnum * ehdr->e_shentsize) + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read sections headers from file"); + + for (shdrptr = shdr, i = 0; i < ehdr->e_shnum; + shdrptr += ehdr->e_shentsize, i++) + { + Elf_Shdr *sh = (Elf_Shdr *) shdrptr; + void *src; + grub_addr_t target; + grub_err_t err; + + /* This section is a loaded section, + so we don't care. */ + if (sh->sh_addr != 0) + continue; + + /* This section is empty, so we don't care. */ + if (sh->sh_size == 0) + continue; + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, + &ch, 0, + (0xffffffff - sh->sh_size) + + 1, sh->sh_size, + sh->sh_addralign, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + { + grub_dprintf ("multiboot_loader", "Error loading shdr %d\n", i); + return err; + } + src = get_virtual_current_address (ch); + target = get_physical_target_address (ch); + } + + if (grub_file_seek (file, sh->sh_offset) == (grub_off_t) -1) + return grub_error (GRUB_ERR_BAD_OS, + "invalid offset in section header"); + + if (grub_file_read (file, src, sh->sh_size) + != (grub_ssize_t) sh->sh_size) + return grub_error (GRUB_ERR_BAD_OS, + "couldn't read segment from file"); + sh->sh_addr = target; + } + grub_multiboot_add_elfsyms (ehdr->e_shnum, ehdr->e_shentsize, + ehdr->e_shstrndx, shdr); + } + #undef phdr return grub_errno; diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c index 3ad6a6c4a..f453dcc6a 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -55,6 +55,19 @@ static unsigned modcnt; static char *cmdline = NULL; static int bootdev_set; static grub_uint32_t biosdev, slice, part; +static grub_size_t elf_sec_num, elf_sec_entsize; +static unsigned elf_sec_shstrndx; +static void *elf_sections; + +void +grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize, + unsigned shndx, void *data) +{ + elf_sec_num = num; + elf_sec_shstrndx = shndx; + elf_sec_entsize = entsize; + elf_sections = data; +} grub_err_t grub_multiboot_load (grub_file_t file) @@ -190,25 +203,24 @@ grub_multiboot_load (grub_file_t file) int load_size = ((addr_tag->load_end_addr == 0) ? file->size - offset : addr_tag->load_end_addr - addr_tag->load_addr); grub_size_t code_size; + void *source; + grub_relocator_chunk_t ch; if (addr_tag->bss_end_addr) code_size = (addr_tag->bss_end_addr - addr_tag->load_addr); else code_size = load_size; - grub_multiboot_payload_dest = addr_tag->load_addr; - grub_multiboot_pure_size += code_size; - - /* Allocate a bit more to avoid relocations in most cases. */ - grub_multiboot_alloc_mbi = grub_multiboot_get_mbi_size () + 65536; - grub_multiboot_payload_orig - = grub_relocator32_alloc (grub_multiboot_pure_size + grub_multiboot_alloc_mbi); - - if (! grub_multiboot_payload_orig) + err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, + &ch, addr_tag->load_addr, + code_size); + if (err) { + grub_dprintf ("multiboot_loader", "Error loading aout kludge\n"); grub_free (buffer); - return grub_errno; + return err; } + source = get_virtual_current_address (ch); if ((grub_file_seek (file, offset)) == (grub_off_t) -1) { @@ -216,7 +228,7 @@ grub_multiboot_load (grub_file_t file) return grub_errno; } - grub_file_read (file, (void *) grub_multiboot_payload_orig, load_size); + grub_file_read (file, source, load_size); if (grub_errno) { grub_free (buffer); @@ -224,7 +236,7 @@ grub_multiboot_load (grub_file_t file) } if (addr_tag->bss_end_addr) - grub_memset ((void *) (grub_multiboot_payload_orig + load_size), 0, + grub_memset ((grub_uint32_t *) source + load_size, 0, addr_tag->bss_end_addr - addr_tag->load_addr - load_size); } else @@ -252,7 +264,7 @@ grub_multiboot_load (grub_file_t file) return err; } -grub_size_t +static grub_size_t grub_multiboot_get_mbi_size (void) { return 2 * sizeof (grub_uint32_t) + sizeof (struct multiboot_tag) @@ -263,6 +275,8 @@ grub_multiboot_get_mbi_size (void) + (modcnt * sizeof (struct multiboot_tag_module) + total_modcmd) + sizeof (struct multiboot_tag_basic_meminfo) + ALIGN_UP (sizeof (struct multiboot_tag_bootdev), MULTIBOOT_TAG_ALIGN) + + sizeof (struct multiboot_tag_elf_sections) + + elf_sec_entsize * elf_sec_num + (sizeof (struct multiboot_tag_mmap) + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry)) + sizeof (struct multiboot_tag_vbe) + MULTIBOOT_TAG_ALIGN - 1; @@ -456,18 +470,34 @@ retrieve_video_parameters (grub_uint8_t **ptrorig) } grub_err_t -grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, - grub_size_t bufsize) +grub_multiboot_make_mbi (grub_uint32_t *target) { grub_uint8_t *ptrorig; - grub_uint8_t *mbistart = (grub_uint8_t *) orig + buf_off - + (ALIGN_UP (dest + buf_off, MULTIBOOT_TAG_ALIGN) - (dest + buf_off)); + grub_uint8_t *mbistart; grub_err_t err; + grub_size_t bufsize; + grub_relocator_chunk_t ch; - if (bufsize < grub_multiboot_get_mbi_size ()) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "mbi buffer is too small"); + bufsize = grub_multiboot_get_mbi_size (); - ptrorig = mbistart + 2 * sizeof (grub_uint32_t); + err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, + 0, 0xffffffff - bufsize, + bufsize, 4, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + return err; + + ptrorig = get_virtual_current_address (ch); +#if defined (__i386__) || defined (__x86_64__) + *target = get_physical_target_address (ch); +#elif defined (__mips) + *target = get_physical_target_address (ch) | 0x80000000; +#else +#error Please complete this +#endif + + mbistart = ptrorig; + ptrorig += 2 * sizeof (grub_uint32_t); { struct multiboot_tag_string *tag = (struct multiboot_tag_string *) ptrorig; @@ -508,6 +538,19 @@ grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, grub_off_t buf_off, ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); } + { + struct multiboot_tag_elf_sections *tag + = (struct multiboot_tag_elf_sections *) ptrorig; + tag->type = MULTIBOOT_TAG_TYPE_ELF_SECTIONS; + tag->size = sizeof (struct multiboot_tag_elf_sections) + + elf_sec_entsize * elf_sec_num; + grub_memcpy (tag->sections, elf_sections, elf_sec_entsize * elf_sec_num); + tag->num = elf_sec_num; + tag->entsize = elf_sec_entsize; + tag->shndx = elf_sec_shstrndx; + ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN); + } + { struct multiboot_tag_basic_meminfo *tag = (struct multiboot_tag_basic_meminfo *) ptrorig; diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c index 6b17a47ad..249238d45 100644 --- a/grub-core/loader/powerpc/ieee1275/linux.c +++ b/grub-core/loader/powerpc/ieee1275/linux.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -302,6 +301,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } + grub_file_filter_disable_compression (); file = grub_file_open (argv[0]); if (! file) goto fail; diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c index f55b4fa2a..177a6976e 100644 --- a/grub-core/loader/sparc64/ieee1275/linux.c +++ b/grub-core/loader/sparc64/ieee1275/linux.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -306,7 +305,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), goto out; } - file = grub_gzfile_open (argv[0], 1); + file = grub_file_open (argv[0]); if (!file) goto out; @@ -394,6 +393,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } + grub_file_filter_disable_compression (); file = grub_file_open (argv[0]); if (! file) goto fail; diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c index 8f1d0c641..ece65611a 100644 --- a/grub-core/loader/xnu.c +++ b/grub-core/loader/xnu.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -40,45 +39,30 @@ static int driverspackagenum = 0; static int driversnum = 0; int grub_xnu_is_64bit = 0; -void *grub_xnu_heap_start = 0; +grub_addr_t grub_xnu_heap_target_start = 0; grub_size_t grub_xnu_heap_size = 0; - -/* Allocate heap by 32MB-blocks. */ -#define GRUB_XNU_HEAP_ALLOC_BLOCK 0x2000000 +struct grub_relocator *grub_xnu_relocator; static grub_err_t grub_xnu_register_memory (char *prefix, int *suffix, - void *addr, grub_size_t size); -void * -grub_xnu_heap_malloc (int size) + grub_addr_t addr, grub_size_t size); +grub_err_t +grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target) { - void *val; - int oldblknum, newblknum; + grub_err_t err; + grub_relocator_chunk_t ch; + + err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch, + grub_xnu_heap_target_start + + grub_xnu_heap_size, size); + if (err) + return err; - /* The page after the heap is used for stack. Ensure it's usable. */ - if (grub_xnu_heap_size) - oldblknum = (grub_xnu_heap_size + GRUB_XNU_PAGESIZE - + GRUB_XNU_HEAP_ALLOC_BLOCK - 1) / GRUB_XNU_HEAP_ALLOC_BLOCK; - else - oldblknum = 0; - newblknum = (grub_xnu_heap_size + size + GRUB_XNU_PAGESIZE - + GRUB_XNU_HEAP_ALLOC_BLOCK - 1) / GRUB_XNU_HEAP_ALLOC_BLOCK; - if (oldblknum != newblknum) - { - /* FIXME: instruct realloc to allocate at 1MB if possible once - advanced mm is ready. */ - grub_xnu_heap_start - = XNU_RELOCATOR (realloc) (grub_xnu_heap_start, - newblknum - * GRUB_XNU_HEAP_ALLOC_BLOCK); - if (!grub_xnu_heap_start) - return NULL; - } - - val = (grub_uint8_t *) grub_xnu_heap_start + grub_xnu_heap_size; + *src = get_virtual_current_address (ch); + *target = grub_xnu_heap_target_start + grub_xnu_heap_size; grub_xnu_heap_size += size; - grub_dprintf ("xnu", "val=%p\n", val); - return val; + grub_dprintf ("xnu", "val=%p\n", *src); + return GRUB_ERR_NONE; } /* Make sure next block of the heap will be aligned. @@ -87,11 +71,9 @@ grub_xnu_heap_malloc (int size) grub_err_t grub_xnu_align_heap (int align) { - int align_overhead = align - grub_xnu_heap_size % align; - if (align_overhead == align) - return GRUB_ERR_NONE; - if (! grub_xnu_heap_malloc (align_overhead)) - return grub_errno; + grub_xnu_heap_size + = ALIGN_UP (grub_xnu_heap_target_start+ grub_xnu_heap_size, align) + - grub_xnu_heap_target_start; return GRUB_ERR_NONE; } @@ -207,13 +189,14 @@ grub_xnu_writetree_toheap_real (void *curptr, } grub_err_t -grub_xnu_writetree_toheap (void **start, grub_size_t *size) +grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size) { struct grub_xnu_devtree_key *chosen; struct grub_xnu_devtree_key *memorymap; struct grub_xnu_devtree_key *driverkey; struct grub_xnu_extdesc *extdesc; grub_err_t err; + void *src; err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) @@ -244,16 +227,17 @@ grub_xnu_writetree_toheap (void **start, grub_size_t *size) /* Allocate the space based on the size with dummy value. */ *size = grub_xnu_writetree_get_size (grub_xnu_devtree_root, "/"); - *start = grub_xnu_heap_malloc (*size + GRUB_XNU_PAGESIZE - - *size % GRUB_XNU_PAGESIZE); + err = grub_xnu_heap_malloc (ALIGN_UP (*size + 1, GRUB_XNU_PAGESIZE), + &src, target); + if (err) + return err; /* Put real data in the dummy. */ - extdesc->addr = (grub_uint8_t *) *start - (grub_uint8_t *) grub_xnu_heap_start - + grub_xnu_heap_will_be_at; + extdesc->addr = *target; extdesc->size = (grub_uint32_t) *size; /* Write the tree to heap. */ - grub_xnu_writetree_toheap_real (*start, grub_xnu_devtree_root, "/"); + grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/"); return GRUB_ERR_NONE; } @@ -338,8 +322,9 @@ grub_xnu_unload (void) /* Free loaded image. */ driversnum = 0; driverspackagenum = 0; - grub_free (grub_xnu_heap_start); - grub_xnu_heap_start = 0; + grub_relocator_unload (grub_xnu_relocator); + grub_xnu_relocator = NULL; + grub_xnu_heap_target_start = 0; grub_xnu_heap_size = 0; grub_xnu_unlock (); return GRUB_ERR_NONE; @@ -354,6 +339,7 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), grub_uint32_t startcode, endcode; int i; char *ptr, *loadaddr; + grub_addr_t loadaddr_target; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); @@ -381,15 +367,18 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)), grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n", (unsigned long) endcode, (unsigned long) startcode); - loadaddr = grub_xnu_heap_malloc (endcode - startcode); - grub_xnu_heap_will_be_at = startcode; + grub_xnu_relocator = grub_relocator_new (); + if (!grub_xnu_relocator) + return grub_errno; + grub_xnu_heap_target_start = startcode; + err = grub_xnu_heap_malloc (endcode - startcode, (void **) &loadaddr, + &loadaddr_target); - if (! loadaddr) + if (err) { grub_macho_close (macho); grub_xnu_unload (); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "not enough memory to load kernel"); + return err; } /* Load kernel. */ @@ -452,6 +441,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), grub_uint64_t startcode, endcode; int i; char *ptr, *loadaddr; + grub_addr_t loadaddr_target; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); @@ -482,15 +472,18 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n", (unsigned long) endcode, (unsigned long) startcode); - loadaddr = grub_xnu_heap_malloc (endcode - startcode); - grub_xnu_heap_will_be_at = startcode; + grub_xnu_relocator = grub_relocator_new (); + if (!grub_xnu_relocator) + return grub_errno; + grub_xnu_heap_target_start = startcode; + err = grub_xnu_heap_malloc (endcode - startcode, (void **) &loadaddr, + &loadaddr_target); - if (! loadaddr) + if (err) { grub_macho_close (macho); grub_xnu_unload (); - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "not enough memory to load kernel"); + return err; } /* Load kernel. */ @@ -548,7 +541,7 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)), and increment SUFFIX. */ static grub_err_t grub_xnu_register_memory (char *prefix, int *suffix, - void *addr, grub_size_t size) + grub_addr_t addr, grub_size_t size) { struct grub_xnu_devtree_key *chosen; struct grub_xnu_devtree_key *memorymap; @@ -585,8 +578,7 @@ grub_xnu_register_memory (char *prefix, int *suffix, = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc)); if (! driverkey->data) return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register extension"); - extdesc->addr = grub_xnu_heap_will_be_at + - ((grub_uint8_t *) addr - (grub_uint8_t *) grub_xnu_heap_start); + extdesc->addr = addr; extdesc->size = (grub_uint32_t) size; return GRUB_ERR_NONE; } @@ -628,7 +620,8 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) grub_file_t infoplist; struct grub_xnu_extheader *exthead; int neededspace = sizeof (*exthead); - grub_uint8_t *buf; + grub_uint8_t *buf, *buf0; + grub_addr_t buf_target; grub_size_t infoplistsize = 0, machosize = 0; char *name, *nameend; int namelen; @@ -667,7 +660,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) macho = 0; if (infoplistname) - infoplist = grub_gzfile_open (infoplistname, 1); + infoplist = grub_file_open (infoplistname); else infoplist = 0; grub_errno = GRUB_ERR_NONE; @@ -683,7 +676,10 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE); if (err) return err; - buf = grub_xnu_heap_malloc (neededspace); + err = grub_xnu_heap_malloc (neededspace, (void **) &buf0, &buf_target); + if (err) + return err; + buf = buf0; exthead = (struct grub_xnu_extheader *) buf; grub_memset (exthead, 0, sizeof (*exthead)); @@ -692,8 +688,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) /* Load the binary. */ if (macho) { - exthead->binaryaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) - + grub_xnu_heap_will_be_at; + exthead->binaryaddr = buf_target + (buf - buf0); exthead->binarysize = machosize; if (grub_xnu_is_64bit) err = grub_macho_readfile64 (macho, buf); @@ -712,8 +707,7 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) /* Load the plist. */ if (infoplist) { - exthead->infoplistaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) - + grub_xnu_heap_will_be_at; + exthead->infoplistaddr = buf_target + (buf - buf0); exthead->infoplistsize = infoplistsize + 1; if (grub_file_read (infoplist, buf, infoplistsize) != (grub_ssize_t) (infoplistsize)) @@ -729,15 +723,14 @@ grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile) } grub_errno = GRUB_ERR_NONE; - exthead->nameaddr = (buf - (grub_uint8_t *) grub_xnu_heap_start) - + grub_xnu_heap_will_be_at; + exthead->nameaddr = (buf - buf0) + buf_target; exthead->namesize = namelen + 1; grub_memcpy (buf, name, namelen); buf[namelen] = 0; buf += namelen + 1; /* Announce to kernel */ - return grub_xnu_register_memory ("Driver-", &driversnum, exthead, + return grub_xnu_register_memory ("Driver-", &driversnum, buf_target, neededspace); } @@ -748,6 +741,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file; void *loadto; + grub_addr_t loadto_target; grub_err_t err; grub_off_t readoff = 0; grub_ssize_t readlen = -1; @@ -761,7 +755,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); - file = grub_gzfile_open (args[0], 1); + file = grub_file_open (args[0]); if (! file) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't load driver package"); @@ -836,11 +830,11 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), return err; } - loadto = grub_xnu_heap_malloc (readlen); - if (! loadto) + err = grub_xnu_heap_malloc (readlen, &loadto, &loadto_target); + if (err) { grub_file_close (file); - return grub_errno; + return err; } /* Read the file. */ @@ -855,7 +849,7 @@ grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)), /* Pass it to kernel. */ return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum, - loadto, readlen); + loadto_target, readlen); } static grub_err_t @@ -864,6 +858,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), { grub_file_t file; void *loadto; + grub_addr_t loadto_target; grub_err_t err; grub_size_t size; @@ -873,7 +868,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), if (! grub_xnu_heap_size) return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded"); - file = grub_gzfile_open (args[0], 1); + file = grub_file_open (args[0]); if (! file) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't load ramdisk"); @@ -884,9 +879,9 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), size = grub_file_size (file); - loadto = grub_xnu_heap_malloc (size); - if (! loadto) - return grub_errno; + err = grub_xnu_heap_malloc (size, &loadto, &loadto_target); + if (err) + return err; if (grub_file_read (file, loadto, size) != (grub_ssize_t) (size)) { @@ -894,7 +889,7 @@ grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)), grub_error_push (); return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]); } - return grub_xnu_register_memory ("RAMDisk", 0, loadto, size); + return grub_xnu_register_memory ("RAMDisk", 0, loadto_target, size); } /* Returns true if the kext should be loaded according to plist @@ -913,7 +908,7 @@ grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq, if (binname) *binname = 0; - file = grub_gzfile_open (plistname, 1); + file = grub_file_open (plistname); if (! file) { grub_file_close (file); @@ -1170,7 +1165,7 @@ grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, grub_strcpy (binname + grub_strlen (binname), "/"); grub_strcpy (binname + grub_strlen (binname), binsuffix); grub_dprintf ("xnu", "%s:%s\n", plistname, binname); - binfile = grub_gzfile_open (binname, 1); + binfile = grub_file_open (binname); if (! binfile) grub_errno = GRUB_ERR_NONE; @@ -1208,7 +1203,7 @@ grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)), /* User explicitly specified plist and binary. */ if (grub_strcmp (args[1], "-") != 0) { - binfile = grub_gzfile_open (args[1], 1); + binfile = grub_file_open (args[1]); if (! binfile) { grub_error (GRUB_ERR_BAD_OS, "can't open file"); @@ -1368,15 +1363,15 @@ static const struct grub_arg_option xnu_splash_cmd_options[] = }; static grub_err_t -grub_cmd_xnu_splash (grub_extcmd_t cmd, +grub_cmd_xnu_splash (grub_extcmd_context_t ctxt, int argc, char *args[]) { grub_err_t err; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); - if (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set && - grub_strcmp (cmd->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg, + if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set && + grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg, "stretch") == 0) grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH; else diff --git a/grub-core/loader/xnu_resume.c b/grub-core/loader/xnu_resume.c index e6620e7b7..8f0e24483 100644 --- a/grub-core/loader/xnu_resume.c +++ b/grub-core/loader/xnu_resume.c @@ -45,11 +45,14 @@ grub_xnu_resume (char *imagename) grub_file_t file; grub_size_t total_header_size; struct grub_xnu_hibernate_header hibhead; - grub_uint8_t *buf; - + void *code; + void *image; grub_uint32_t codedest; grub_uint32_t codesize; + grub_addr_t target_image; + grub_err_t err; + grub_file_filter_disable_compression (); file = grub_file_open (imagename); if (! file) return 0; @@ -94,18 +97,44 @@ grub_xnu_resume (char *imagename) /* Try to allocate necessary space. FIXME: mm isn't good enough yet to handle huge allocations. */ - grub_xnu_hibernate_image = buf = XNU_RELOCATOR (alloc) (hibhead.image_size - + codesize - + GRUB_XNU_PAGESIZE); - if (! buf) + grub_xnu_relocator = grub_relocator_new (); + if (!grub_xnu_relocator) { grub_file_close (file); return grub_errno; } + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch, codedest, + codesize + GRUB_XNU_PAGESIZE); + if (err) + { + grub_file_close (file); + return err; + } + code = get_virtual_current_address (ch); + } + + { + grub_relocator_chunk_t ch; + err = grub_relocator_alloc_chunk_align (grub_xnu_relocator, &ch, 0, + (0xffffffff - hibhead.image_size) + 1, + hibhead.image_size, + GRUB_XNU_PAGESIZE, + GRUB_RELOCATOR_PREFERENCE_NONE); + if (err) + { + grub_file_close (file); + return err; + } + image = get_virtual_current_address (ch); + target_image = get_physical_target_address (ch); + } + /* Read code part. */ if (grub_file_seek (file, total_header_size) == (grub_off_t) -1 - || grub_file_read (file, buf, codesize) + || grub_file_read (file, code, codesize) != (grub_ssize_t) codesize) { grub_file_close (file); @@ -114,8 +143,7 @@ grub_xnu_resume (char *imagename) /* Read image. */ if (grub_file_seek (file, 0) == (grub_off_t) -1 - || grub_file_read (file, buf + codesize + GRUB_XNU_PAGESIZE, - hibhead.image_size) + || grub_file_read (file, image, hibhead.image_size) != (grub_ssize_t) hibhead.image_size) { grub_file_close (file); @@ -124,12 +152,11 @@ grub_xnu_resume (char *imagename) grub_file_close (file); /* Setup variables needed by asm helper. */ - grub_xnu_heap_will_be_at = codedest; - grub_xnu_heap_start = buf; - grub_xnu_heap_size = codesize + GRUB_XNU_PAGESIZE + hibhead.image_size; + grub_xnu_heap_target_start = codedest; + grub_xnu_heap_size = target_image + hibhead.image_size - codedest; grub_xnu_stack = (codedest + hibhead.stack); grub_xnu_entry_point = (codedest + hibhead.entry_point); - grub_xnu_arg1 = codedest + codesize + GRUB_XNU_PAGESIZE; + grub_xnu_arg1 = target_image; grub_dprintf ("xnu", "entry point 0x%x\n", codedest + hibhead.entry_point); grub_dprintf ("xnu", "image at 0x%x\n", diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c index fd377e1c6..b7f775c4f 100644 --- a/grub-core/normal/charset.c +++ b/grub-core/normal/charset.c @@ -297,13 +297,10 @@ grub_utf8_to_ucs4_alloc (const char *msg, grub_uint32_t **unicode_msg, { grub_size_t msg_len = grub_strlen (msg); - *unicode_msg = grub_malloc (grub_strlen (msg) * sizeof (grub_uint32_t)); + *unicode_msg = grub_malloc (msg_len * sizeof (grub_uint32_t)); if (!*unicode_msg) - { - grub_printf ("utf8_to_ucs4 ERROR1: %s", msg); - return -1; - } + return -1; msg_len = grub_utf8_to_ucs4 (*unicode_msg, msg_len, (grub_uint8_t *) msg, -1, 0); @@ -1215,6 +1212,8 @@ grub_bidi_logical_to_visual (const grub_uint32_t *logical, struct grub_unicode_glyph *visual_ptr; *visual_out = visual_ptr = grub_malloc (2 * sizeof (visual_ptr[0]) * logical_len); + if (!visual_ptr) + return -1; for (ptr = logical; ptr <= logical + logical_len; ptr++) { if (ptr == logical + logical_len || *ptr == '\n') diff --git a/grub-core/normal/cmdline.c b/grub-core/normal/cmdline.c index daa0a1adb..3647dcd3a 100644 --- a/grub-core/normal/cmdline.c +++ b/grub-core/normal/cmdline.c @@ -585,6 +585,7 @@ grub_cmdline_get (const char *prompt) break; case '\e': + grub_free (cl_terms); return 0; case '\b': @@ -635,5 +636,6 @@ grub_cmdline_get (const char *prompt) ret = grub_ucs4_to_utf8_alloc (buf + lpos, llen - lpos + 1); grub_free (buf); + grub_free (cl_terms); return ret; } diff --git a/grub-core/normal/color.c b/grub-core/normal/color.c index a16d1c2f9..2e6c80b94 100644 --- a/grub-core/normal/color.c +++ b/grub-core/normal/color.c @@ -125,10 +125,11 @@ 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, const char *val) +grub_env_write_color_normal (struct grub_env_var *var __attribute__ ((unused)), + const char *val) { if (grub_parse_color_name_pair (&color_normal, val)) - return 0; + return NULL; set_colors (); @@ -137,10 +138,11 @@ grub_env_write_color_normal (struct grub_env_var *var, const char *val) /* Replace default `highlight' colors with the ones specified by user (if any). */ char * -grub_env_write_color_highlight (struct grub_env_var *var, const char *val) +grub_env_write_color_highlight (struct grub_env_var *var __attribute__ ((unused)), + const char *val) { if (grub_parse_color_name_pair (&color_highlight, val)) - return 0; + return NULL; set_colors (); diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c index 40a645fb4..1b51dab3a 100644 --- a/grub-core/normal/completion.c +++ b/grub-core/normal/completion.c @@ -499,7 +499,10 @@ grub_normal_do_completion (char *buf, int *restore, fail: if (argc != 0) - grub_free (argv[0]); + { + grub_free (argv[0]); + grub_free (argv); + } grub_free (match); grub_errno = GRUB_ERR_NONE; diff --git a/grub-core/normal/dyncmd.c b/grub-core/normal/dyncmd.c index a3cafa514..3519253f6 100644 --- a/grub-core/normal/dyncmd.c +++ b/grub-core/normal/dyncmd.c @@ -23,16 +23,21 @@ #include #include #include +#include +#include #include static grub_err_t -grub_dyncmd_dispatcher (struct grub_command *cmd, +grub_dyncmd_dispatcher (struct grub_extcmd_context *ctxt, int argc, char **args) { - char *modname = cmd->data; + char *modname; grub_dl_t mod; grub_err_t ret; + grub_extcmd_t extcmd = ctxt->extcmd; + grub_command_t cmd = extcmd->cmd; + modname = extcmd->data; mod = grub_dl_load (modname); if (mod) { @@ -42,11 +47,17 @@ grub_dyncmd_dispatcher (struct grub_command *cmd, grub_dl_ref (mod); name = (char *) cmd->name; - grub_unregister_command (cmd); + grub_unregister_extcmd (extcmd); cmd = grub_command_find (name); if (cmd) - ret = (cmd->func) (cmd, argc, args); + { + if (cmd->flags & GRUB_COMMAND_FLAG_BLOCKS && + cmd->flags & GRUB_COMMAND_FLAG_EXTCMD) + ret = grub_extcmd_dispatcher (cmd, argc, args, ctxt->script); + else + ret = (cmd->func) (cmd, argc, args); + } else ret = grub_errno; @@ -81,13 +92,14 @@ read_command_list (const char *prefix) for (ptr = grub_command_list; ptr; ptr = next) { next = ptr->next; - if (ptr->func == grub_dyncmd_dispatcher) + if (ptr->flags & GRUB_COMMAND_FLAG_DYNCMD) { if (last) last->next = ptr->next; else grub_command_list = ptr->next; grub_free (ptr); + grub_free (ptr->data); /* extcmd struct */ } else last = ptr; @@ -96,7 +108,7 @@ read_command_list (const char *prefix) for (;; grub_free (buf)) { char *p, *name, *modname; - grub_command_t cmd; + grub_extcmd_t cmd; int prio = 0; buf = grub_file_getline (file); @@ -139,16 +151,20 @@ read_command_list (const char *prefix) continue; } - cmd = grub_register_command_prio (name, - grub_dyncmd_dispatcher, - 0, N_("not loaded"), prio); + cmd = grub_register_extcmd_prio (name, + grub_dyncmd_dispatcher, + GRUB_COMMAND_FLAG_BLOCKS + | GRUB_COMMAND_FLAG_EXTCMD + | GRUB_COMMAND_FLAG_CMDLINE + | GRUB_COMMAND_FLAG_DYNCMD, + 0, N_("not loaded"), 0, + prio); if (! cmd) { grub_free (name); grub_free (modname); continue; } - cmd->flags |= GRUB_COMMAND_FLAG_DYNCMD; cmd->data = modname; /* Update the active flag. */ diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index cddb15216..c7e83fba0 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -141,209 +141,6 @@ free_menu (grub_menu_t menu) grub_env_unset_menu (); } -static void -free_menu_entry_classes (struct grub_menu_entry_class *head) -{ - /* Free all the classes. */ - while (head) - { - struct grub_menu_entry_class *next; - - grub_free (head->name); - next = head->next; - grub_free (head); - head = next; - } -} - -static struct -{ - char *name; - int key; -} hotkey_aliases[] = - { - {"backspace", '\b'}, - {"tab", '\t'}, - {"delete", GRUB_TERM_DC} - }; - -/* Add a menu entry to the current menu context (as given by the environment - variable data slot `menu'). As the configuration file is read, the script - parser calls this when a menu entry is to be created. */ -grub_err_t -grub_normal_add_menu_entry (int argc, const char **args, - const char *sourcecode) -{ - const char *menutitle = 0; - const char *menusourcecode; - grub_menu_t menu; - grub_menu_entry_t *last; - int failed = 0; - int i; - struct grub_menu_entry_class *classes_head; /* Dummy head node for list. */ - struct grub_menu_entry_class *classes_tail; - char *users = NULL; - int hotkey = 0; - - /* Allocate dummy head node for class list. */ - classes_head = grub_zalloc (sizeof (struct grub_menu_entry_class)); - if (! classes_head) - return grub_errno; - classes_tail = classes_head; - - menu = grub_env_get_menu (); - if (! menu) - return grub_error (GRUB_ERR_MENU, "no menu context"); - - last = &menu->entry_list; - - menusourcecode = grub_strdup (sourcecode); - if (! menusourcecode) - return grub_errno; - - /* Parse menu arguments. */ - for (i = 0; i < argc; i++) - { - /* Capture arguments. */ - if (grub_strncmp ("--", args[i], 2) == 0 && i + 1 < argc) - { - const char *arg = &args[i][2]; - - /* Handle menu class. */ - if (grub_strcmp(arg, "class") == 0) - { - char *class_name; - struct grub_menu_entry_class *new_class; - - i++; - class_name = grub_strdup (args[i]); - if (! class_name) - { - failed = 1; - break; - } - - /* Create a new class and add it at the tail of the list. */ - new_class = grub_zalloc (sizeof (struct grub_menu_entry_class)); - if (! new_class) - { - grub_free (class_name); - failed = 1; - break; - } - /* Fill in the new class node. */ - new_class->name = class_name; - /* Link the tail to it, and make it the new tail. */ - classes_tail->next = new_class; - classes_tail = new_class; - continue; - } - else if (grub_strcmp(arg, "users") == 0) - { - i++; - users = grub_strdup (args[i]); - if (! users) - { - failed = 1; - break; - } - - continue; - } - else if (grub_strcmp(arg, "hotkey") == 0) - { - unsigned j; - - i++; - if (args[i][1] == 0) - { - hotkey = args[i][0]; - continue; - } - - for (j = 0; j < ARRAY_SIZE (hotkey_aliases); j++) - if (grub_strcmp (args[i], hotkey_aliases[j].name) == 0) - { - hotkey = hotkey_aliases[j].key; - break; - } - - if (j < ARRAY_SIZE (hotkey_aliases)) - continue; - - failed = 1; - grub_error (GRUB_ERR_MENU, - "Invalid hotkey: '%s'.", args[i]); - break; - } - else - { - /* Handle invalid argument. */ - failed = 1; - grub_error (GRUB_ERR_MENU, - "invalid argument for menuentry: %s", args[i]); - break; - } - } - - /* Capture title. */ - if (! menutitle) - { - menutitle = grub_strdup (args[i]); - } - else - { - failed = 1; - grub_error (GRUB_ERR_MENU, - "too many titles for menuentry: %s", args[i]); - break; - } - } - - /* Validate arguments. */ - if ((! failed) && (! menutitle)) - { - grub_error (GRUB_ERR_MENU, "menuentry is missing title"); - failed = 1; - } - - /* If argument parsing failed, free any allocated resources. */ - if (failed) - { - free_menu_entry_classes (classes_head); - grub_free ((void *) menutitle); - grub_free ((void *) menusourcecode); - - /* Here we assume that grub_error has been used to specify failure details. */ - return grub_errno; - } - - /* Add the menu entry at the end of the list. */ - while (*last) - last = &(*last)->next; - - *last = grub_zalloc (sizeof (**last)); - if (! *last) - { - free_menu_entry_classes (classes_head); - grub_free ((void *) menutitle); - grub_free ((void *) menusourcecode); - return grub_errno; - } - - (*last)->title = menutitle; - (*last)->hotkey = hotkey; - (*last)->classes = classes_head; - if (users) - (*last)->restricted = 1; - (*last)->users = users; - (*last)->sourcecode = menusourcecode; - - menu->size++; - - return GRUB_ERR_NONE; -} - static grub_menu_t read_config_file (const char *config) { @@ -677,8 +474,12 @@ static void (*grub_xputs_saved) (const char *str); GRUB_MOD_INIT(normal) { + /* Previously many modules depended on gzio. Be nice to user and load it. */ + grub_dl_load ("gzio"); + grub_context_init (); grub_script_init (); + grub_menu_init (); grub_xputs_saved = grub_xputs; grub_xputs = grub_xputs_normal; @@ -718,6 +519,7 @@ GRUB_MOD_FINI(normal) { grub_context_fini (); grub_script_fini (); + grub_menu_fini (); grub_xputs = grub_xputs_saved; diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c index b57990b0d..6827a893f 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c @@ -43,9 +43,20 @@ grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, void grub_wait_after_message (void) { + grub_uint64_t endtime; grub_xputs ("\n"); grub_printf_ (N_("Press any key to continue...")); - (void) grub_getkey (); + grub_refresh (); + + endtime = grub_get_time_ms () + 10000; + + while (grub_get_time_ms () < endtime) + if (grub_checkkey () >= 0) + { + grub_getkey (); + break; + } + grub_xputs ("\n"); } @@ -142,44 +153,6 @@ get_and_remove_first_entry_number (const char *name) return entry; } -static void -grub_menu_execute_entry_real (grub_menu_entry_t entry) -{ - const char *source; - - auto grub_err_t getline (char **line, int cont); - grub_err_t getline (char **line, int cont __attribute__ ((unused))) - { - const char *p; - - if (!source) - { - *line = 0; - return 0; - } - - p = grub_strchr (source, '\n'); - - if (p) - *line = grub_strndup (source, p - source); - else - *line = grub_strdup (source); - source = p ? p + 1 : 0; - return 0; - } - - source = entry->sourcecode; - - while (source) - { - char *line; - - getline (&line, 0); - grub_normal_parse_line (line, getline); - grub_free (line); - } -} - /* Run a menu entry. */ void grub_menu_execute_entry(grub_menu_entry_t entry) @@ -197,8 +170,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry) } grub_env_set ("chosen", entry->title); - - grub_menu_execute_entry_real (entry); + grub_script_execute_sourcecode (entry->sourcecode, entry->argc, entry->args); if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) /* Implicit execution of boot, only if something is loaded. */ diff --git a/grub-core/normal/term.c b/grub-core/normal/term.c index 4f5779abe..b55c0f06a 100644 --- a/grub-core/normal/term.c +++ b/grub-core/normal/term.c @@ -44,6 +44,9 @@ static int grub_more; static int grub_normal_char_counter = 0; +static void +putcode_real (grub_uint32_t code, struct grub_term_output *term); + int grub_normal_get_char_counter (void) { @@ -83,7 +86,7 @@ print_more (void) { grub_print_ucs4 (unicode_str, unicode_last_position, 0, 0, term); } - grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); + grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); grub_free (unicode_str); @@ -94,6 +97,7 @@ print_more (void) FOR_ACTIVE_TERM_OUTPUTS(term) grub_print_spaces (term, 8); grub_term_restore_pos (pos); + grub_free (pos); /* Scroll one lines or an entire page, depending on the key. */ @@ -202,8 +206,39 @@ void grub_puts_terminal (const char *str, struct grub_term_output *term) { grub_uint32_t *unicode_str, *unicode_last_position; + grub_error_push (); grub_utf8_to_ucs4_alloc (str, &unicode_str, &unicode_last_position); + grub_error_pop (); + if (!unicode_str) + { + for (; *str; str++) + { + struct grub_unicode_glyph c = + { + .variant = 0, + .attributes = 0, + .ncomb = 0, + .combining = 0, + .estimated_width = 1, + .base = *str + }; + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + (term->putchar) (term, &c); + } + if (*str == '\n') + { + c.base = '\r'; + FOR_ACTIVE_TERM_OUTPUTS(term) + { + (term->putchar) (term, &c); + } + } + } + return; + } grub_print_ucs4 (unicode_str, unicode_last_position, 0, 0, term); grub_free (unicode_str); @@ -742,15 +777,43 @@ grub_print_ucs4 (const grub_uint32_t * str, void grub_xputs_normal (const char *str) { - grub_term_output_t term; - grub_uint32_t *unicode_str, *unicode_last_position; + grub_uint32_t *unicode_str = NULL, *unicode_last_position; int backlog = 0; + grub_term_output_t term; + + grub_error_push (); grub_utf8_to_ucs4_alloc (str, &unicode_str, - &unicode_last_position); + &unicode_last_position); + grub_error_pop (); if (!unicode_str) { - grub_errno = GRUB_ERR_NONE; + for (; *str; str++) + { + struct grub_unicode_glyph c = + { + .variant = 0, + .attributes = 0, + .ncomb = 0, + .combining = 0, + .estimated_width = 1, + .base = *str + }; + + FOR_ACTIVE_TERM_OUTPUTS(term) + { + (term->putchar) (term, &c); + } + if (*str == '\n') + { + c.base = '\r'; + FOR_ACTIVE_TERM_OUTPUTS(term) + { + (term->putchar) (term, &c); + } + } + } + return; } diff --git a/grub-core/script/argv.c b/grub-core/script/argv.c index b69ee39c5..50f810fcf 100644 --- a/grub-core/script/argv.c +++ b/grub-core/script/argv.c @@ -18,6 +18,7 @@ */ #include +#include #include /* Return nearest power of two that is >= v. */ @@ -55,6 +56,24 @@ grub_script_argv_free (struct grub_script_argv *argv) argv->argc = 0; argv->args = 0; + argv->script = 0; +} + +/* Make argv from argc, args pair. */ +int +grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args) +{ + int i; + struct grub_script_argv r = { 0, 0, 0 }; + + for (i = 0; i < argc; i++) + if (grub_script_argv_next (&r) || grub_script_argv_append (&r, args[i])) + { + grub_script_argv_free (&r); + return 1; + } + *argv = r; + return 0; } /* Prepare for next argc. */ @@ -63,7 +82,7 @@ grub_script_argv_next (struct grub_script_argv *argv) { char **p = argv->args; - if (argv->args && argv->args[argv->argc - 1] == 0) + if (argv->args && argv->argc && argv->args[argv->argc - 1] == 0) return 0; p = grub_realloc (p, round_up_exp ((argv->argc + 2) * sizeof (char *))); @@ -83,7 +102,8 @@ grub_script_argv_next (struct grub_script_argv *argv) int grub_script_argv_append (struct grub_script_argv *argv, const char *s) { - int a, b; + int a; + int b; char *p = argv->args[argv->argc - 1]; if (! s) @@ -98,6 +118,7 @@ grub_script_argv_append (struct grub_script_argv *argv, const char *s) grub_strcpy (p + a, s); argv->args[argv->argc - 1] = p; + return 0; } diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index 26a46b12b..a7baee96c 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -25,6 +25,7 @@ #include #include #include +#include /* Max digits for a char is 3 (0xFF is 255), similarly for an int it is sizeof (int) * 3, and one extra for a possible -ve sign. */ @@ -33,14 +34,40 @@ static unsigned long is_continue; static unsigned long active_loops; static unsigned long active_breaks; +static unsigned long function_return; + +#define GRUB_SCRIPT_SCOPE_MALLOCED 1 +#define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2 /* Scope for grub script functions. */ struct grub_script_scope { + unsigned flags; + unsigned shifts; struct grub_script_argv argv; }; static struct grub_script_scope *scope = 0; +/* Wildcard translator for GRUB script. */ +struct grub_script_wildcard_translator *grub_wildcard_translator; + +static void +replace_scope (struct grub_script_scope *new_scope) +{ + if (scope) + { + scope->argv.argc += scope->shifts; + scope->argv.args -= scope->shifts; + + if (scope->flags & GRUB_SCRIPT_SCOPE_ARGS_MALLOCED) + grub_script_argv_free (&scope->argv); + + if (scope->flags & GRUB_SCRIPT_SCOPE_MALLOCED) + grub_free (scope); + } + scope = new_scope; +} + grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]) { @@ -85,11 +112,65 @@ grub_script_shift (grub_command_t cmd __attribute__((unused)), if (n > scope->argv.argc) return GRUB_ERR_BAD_ARGUMENT; + scope->shifts += n; scope->argv.argc -= n; scope->argv.args += n; return GRUB_ERR_NONE; } +grub_err_t +grub_script_setparams (grub_command_t cmd __attribute__((unused)), + int argc, char **args) +{ + struct grub_script_scope *new_scope; + struct grub_script_argv argv = { 0, 0, 0 }; + + if (! scope) + return GRUB_ERR_INVALID_COMMAND; + + new_scope = grub_malloc (sizeof (*new_scope)); + if (! new_scope) + return grub_errno; + + if (grub_script_argv_make (&argv, argc, args)) + { + grub_free (new_scope); + return grub_errno; + } + + new_scope->shifts = 0; + new_scope->argv = argv; + new_scope->flags = GRUB_SCRIPT_SCOPE_MALLOCED | + GRUB_SCRIPT_SCOPE_ARGS_MALLOCED; + + replace_scope (new_scope); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_script_return (grub_command_t cmd __attribute__((unused)), + int argc, char *argv[]) +{ + char *p; + unsigned long n; + + if (! scope || argc > 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in function scope"); + + if (argc == 0) + { + function_return = 1; + return grub_strtoul (grub_env_get ("?"), NULL, 10); + } + + n = grub_strtoul (argv[0], &p, 10); + if (*p != '\0') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "bad argument"); + + function_return = 1; + return n ? grub_error (GRUB_ERR_TEST_FAILURE, "false") : GRUB_ERR_NONE; +} + static int grub_env_special (const char *name) { @@ -104,7 +185,8 @@ grub_env_special (const char *name) static char ** grub_script_env_get (const char *name, grub_script_arg_type_t type) { - struct grub_script_argv result = { 0, 0 }; + unsigned i; + struct grub_script_argv result = { 0, 0, 0 }; if (grub_script_argv_next (&result)) goto fail; @@ -138,8 +220,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "*") == 0) { - unsigned i; - for (i = 0; i < scope->argv.argc; i++) if (type == GRUB_SCRIPT_ARG_TYPE_VAR) { @@ -160,8 +240,6 @@ grub_script_env_get (const char *name, grub_script_arg_type_t type) } else if (grub_strcmp (name, "@") == 0) { - unsigned i; - for (i = 0; i < scope->argv.argc; i++) { if (i != 0 && grub_script_argv_next (&result)) @@ -214,7 +292,7 @@ grub_script_env_set (const char *name, const char *val) return grub_env_set (name, val); } -/* Expand arguments in ARGLIST into multiple arguments. */ +/* Convert arguments in ARGLIST into ARGV form. */ static int grub_script_arglist_to_argv (struct grub_script_arglist *arglist, struct grub_script_argv *argv) @@ -222,7 +300,29 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, int i; char **values = 0; struct grub_script_arg *arg = 0; - struct grub_script_argv result = { 0, 0 }; + struct grub_script_argv result = { 0, 0, 0 }; + + auto int append (char *s, int escape_type); + int append (char *s, int escape_type) + { + int r; + char *p = 0; + + if (! grub_wildcard_translator || escape_type == 0) + return grub_script_argv_append (&result, s); + + if (escape_type > 0) + p = grub_wildcard_translator->escape (s); + else if (escape_type < 0) + p = grub_wildcard_translator->unescape (s); + + if (! p) + return 1; + + r = grub_script_argv_append (&result, p); + grub_free (p); + return r; + } for (; arglist && arglist->arg; arglist = arglist->next) { @@ -242,12 +342,30 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, if (i != 0 && grub_script_argv_next (&result)) goto fail; - if (grub_script_argv_append (&result, values[i])) - goto fail; + if (arg->type == GRUB_SCRIPT_ARG_TYPE_VAR) + { + if (grub_script_argv_append (&result, values[i])) + goto fail; + } + else + { + if (append (values[i], 1)) + goto fail; + } + + grub_free (values[i]); } grub_free (values); break; + case GRUB_SCRIPT_ARG_TYPE_BLOCK: + if (grub_script_argv_append (&result, "{") || + grub_script_argv_append (&result, arg->str) || + grub_script_argv_append (&result, "}")) + goto fail; + result.script = arg->script; + break; + case GRUB_SCRIPT_ARG_TYPE_TEXT: if (grub_strlen (arg->str) && grub_script_argv_append (&result, arg->str)) @@ -267,6 +385,51 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, if (! result.args[result.argc - 1]) result.argc--; + /* Perform wildcard expansion. */ + + if (grub_wildcard_translator) + { + int j; + int failed = 0; + char **expansions = 0; + struct grub_script_argv unexpanded = result; + + result.argc = 0; + result.args = 0; + for (i = 0; unexpanded.args[i]; i++) + { + if (grub_wildcard_translator->expand (unexpanded.args[i], + &expansions)) + { + grub_script_argv_free (&unexpanded); + goto fail; + } + + if (! expansions) + { + grub_script_argv_next (&result); + append (unexpanded.args[i], -1); + } + else + { + for (j = 0; expansions[j]; j++) + { + failed = (failed || grub_script_argv_next (&result) || + append (expansions[j], -1)); + grub_free (expansions[j]); + } + grub_free (expansions); + + if (failed) + { + grub_script_argv_free (&unexpanded); + goto fail; + } + } + } + grub_script_argv_free (&unexpanded); + } + *argv = result; return 0; @@ -302,6 +465,8 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) struct grub_script_scope new_scope; active_loops = 0; + new_scope.flags = 0; + new_scope.shifts = 0; new_scope.argv.argc = argc; new_scope.argv.args = args; @@ -310,7 +475,64 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) ret = grub_script_execute (func->func); + function_return = 0; active_loops = loops; + replace_scope (old_scope); /* free any scopes by setparams */ + return ret; +} + +/* Execute a source script. */ +grub_err_t +grub_script_execute_sourcecode (const char *source, int argc, char **args) +{ + grub_err_t ret = 0; + struct grub_script *parsed_script; + struct grub_script_scope new_scope; + struct grub_script_scope *old_scope; + + auto grub_err_t getline (char **line, int cont); + grub_err_t getline (char **line, int cont __attribute__ ((unused))) + { + const char *p; + + if (! source) + { + *line = 0; + return 0; + } + + p = grub_strchr (source, '\n'); + + if (p) + *line = grub_strndup (source, p - source); + else + *line = grub_strdup (source); + source = p ? p + 1 : 0; + return 0; + } + + new_scope.argv.argc = argc; + new_scope.argv.args = args; + + old_scope = scope; + scope = &new_scope; + + while (source) + { + char *line; + + getline (&line, 0); + parsed_script = grub_script_parse (line, getline); + if (! parsed_script) + { + ret = grub_errno; + break; + } + + ret = grub_script_execute (parsed_script); + grub_free (line); + } + scope = old_scope; return ret; } @@ -325,7 +547,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) grub_script_function_t func = 0; char errnobuf[18]; char *cmdname; - struct grub_script_argv argv = { 0, 0 }; + struct grub_script_argv argv = { 0, 0, 0 }; /* Lookup the command. */ if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0]) @@ -369,7 +591,14 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd) /* Execute the GRUB command or function. */ if (grubcmd) - ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1); + { + if ((grubcmd->flags & GRUB_COMMAND_FLAG_BLOCKS) && + (grubcmd->flags & GRUB_COMMAND_FLAG_EXTCMD)) + ret = grub_extcmd_dispatcher (grubcmd, argv.argc - 1, argv.args + 1, + argv.script); + else + ret = (grubcmd->func) (grubcmd, argv.argc - 1, argv.args + 1); + } else ret = grub_script_function_call (func, argv.argc - 1, argv.args + 1); @@ -395,8 +624,16 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list) struct grub_script_cmd *cmd; /* Loop over every command and execute it. */ - for (cmd = list->next; cmd && ! active_breaks; cmd = cmd->next) - ret = grub_script_execute_cmd (cmd); + for (cmd = list->next; cmd; cmd = cmd->next) + { + if (active_breaks) + break; + + ret = grub_script_execute_cmd (cmd); + + if (function_return) + break; + } return ret; } @@ -405,14 +642,17 @@ grub_script_execute_cmdlist (struct grub_script_cmd *list) grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd) { - struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd; + int ret; char *result; + struct grub_script_cmdif *cmdif = (struct grub_script_cmdif *) cmd; /* Check if the commands results in a true or a false. The value is read from the env variable `?'. */ - grub_script_execute_cmd (cmdif->exec_to_evaluate); - result = grub_env_get ("?"); + ret = grub_script_execute_cmd (cmdif->exec_to_evaluate); + if (function_return) + return ret; + result = grub_env_get ("?"); grub_errno = GRUB_ERR_NONE; /* Execute the `if' or the `else' part depending on the value of @@ -429,8 +669,7 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { unsigned i; grub_err_t result; - struct grub_script_argv argv = { 0, 0 }; - + struct grub_script_argv argv = { 0, 0, 0 }; struct grub_script_cmdfor *cmdfor = (struct grub_script_cmdfor *) cmd; if (grub_script_arglist_to_argv (cmdfor->words, &argv)) @@ -447,6 +686,8 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) { grub_script_env_set (cmdfor->name->str, argv.args[i]); result = grub_script_execute_cmd (cmdfor->list); + if (function_return) + break; } } @@ -462,18 +703,21 @@ grub_script_execute_cmdfor (struct grub_script_cmd *cmd) grub_err_t grub_script_execute_cmdwhile (struct grub_script_cmd *cmd) { - int cond; int result; struct grub_script_cmdwhile *cmdwhile = (struct grub_script_cmdwhile *) cmd; active_loops++; - result = 0; do { - cond = grub_script_execute_cmd (cmdwhile->cond); - if (cmdwhile->until ? !cond : cond) + result = grub_script_execute_cmd (cmdwhile->cond); + if (function_return) + break; + + if (cmdwhile->until ? !result : result) break; result = grub_script_execute_cmd (cmdwhile->list); + if (function_return) + break; if (active_breaks == 1 && is_continue) active_breaks = 0; @@ -490,31 +734,6 @@ grub_script_execute_cmdwhile (struct grub_script_cmd *cmd) return result; } -/* Execute the menu entry generate statement. */ -grub_err_t -grub_script_execute_menuentry (struct grub_script_cmd *cmd) -{ - struct grub_script_cmd_menuentry *cmd_menuentry; - struct grub_script_argv argv = { 0, 0 }; - - cmd_menuentry = (struct grub_script_cmd_menuentry *) cmd; - - if (cmd_menuentry->arglist) - { - if (grub_script_arglist_to_argv (cmd_menuentry->arglist, &argv)) - return grub_errno; - } - - grub_normal_add_menu_entry (argv.argc, (const char **) argv.args, - cmd_menuentry->sourcecode); - - grub_script_argv_free (&argv); - - return grub_errno; -} - - - /* Execute any GRUB pre-parsed command or script. */ grub_err_t grub_script_execute (struct grub_script *script) diff --git a/grub-core/script/lexer.c b/grub-core/script/lexer.c index 42a570348..8d1623fb8 100644 --- a/grub-core/script/lexer.c +++ b/grub-core/script/lexer.c @@ -38,68 +38,57 @@ grub_script_lexer_deref (struct grub_lexer_param *state) } /* Start recording all characters passing through the lexer. */ -void +unsigned grub_script_lexer_record_start (struct grub_parser_param *parser) { struct grub_lexer_param *lexer = parser->lexerstate; - lexer->record = 1; - lexer->recordpos = 0; - if (lexer->recording) /* reuse last record */ - return; + lexer->record++; + if (lexer->recording) + return lexer->recordpos; + lexer->recordpos = 0; lexer->recordlen = GRUB_LEXER_INITIAL_RECORD_SIZE; lexer->recording = grub_malloc (lexer->recordlen); if (!lexer->recording) { grub_script_yyerror (parser, 0); - lexer->record = 0; lexer->recordlen = 0; } + return lexer->recordpos; } char * -grub_script_lexer_record_stop (struct grub_parser_param *parser) +grub_script_lexer_record_stop (struct grub_parser_param *parser, unsigned offset) { - char *ptr; + int count; char *result; struct grub_lexer_param *lexer = parser->lexerstate; - auto char *compact (char *start, char *end); - char *compact (char *start, char *end) - { - /* Delete '{' and '}' characters and whitespaces. */ - while (*start && grub_isspace (*start)) start++; - if (*start == '{') start++; - while (*start && grub_isspace (*start)) start++; - - while (*end && grub_isspace (*end)) end--; - if (*end == '}') end--; - while (*end && grub_isspace (*end)) end--; - end[1] = '\0'; - - return start; - } - - if (!lexer->record || !lexer->recording) + if (!lexer->record) return 0; - /* XXX This is not necessary in BASH. */ + lexer->record--; + if (!lexer->recording) + return 0; - ptr = compact (lexer->recording, lexer->recording + lexer->recordpos - 1); - lexer->record = 0; - lexer->recordpos = 0; - - /* This memory would be freed by, grub_script_free. */ - result = grub_script_malloc (parser, grub_strlen (ptr) + 1); - if (result) - grub_strcpy (result, ptr); + count = lexer->recordpos - offset; + result = grub_script_malloc (parser, count + 1); + if (result) { + grub_strncpy (result, lexer->recording + offset, count); + result[count] = '\0'; + } + if (lexer->record == 0) + { + grub_free (lexer->recording); + lexer->recording = 0; + lexer->recordlen = 0; + lexer->recordpos = 0; + } return result; } -#define MAX(a,b) ((a) < (b) ? (b) : (a)) - /* Record STR if input recording is enabled. */ void grub_script_lexer_record (struct grub_parser_param *parser, char *str) @@ -108,21 +97,20 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str) char *old; struct grub_lexer_param *lexer = parser->lexerstate; - if (!lexer->record) + if (!lexer->record || !lexer->recording) return; len = grub_strlen (str); if (lexer->recordpos + len + 1 > lexer->recordlen) { old = lexer->recording; - lexer->recordlen = MAX (len, lexer->recordlen) * 2; + lexer->recordlen = grub_max (len, lexer->recordlen) * 2; lexer->recording = grub_realloc (lexer->recording, lexer->recordlen); if (!lexer->recording) { grub_free (old); - lexer->record = 0; lexer->recordpos = 0; - lexer->recordlen /= 2; + lexer->recordlen = 0; grub_script_yyerror (parser, 0); return; } @@ -131,85 +119,92 @@ grub_script_lexer_record (struct grub_parser_param *parser, char *str) lexer->recordpos += len; } -/* Append '\n' to SRC, before '\0' */ -static char * -append_newline (const char *src) -{ - char *line; - grub_size_t len; - - len = grub_strlen (src); - line = grub_malloc (len + 2); - if (!line) - return 0; - - grub_strcpy (line, src); - - line[len] = '\n'; - line[len + 1] = '\0'; - return line; -} - /* Read next line of input if necessary, and set yyscanner buffers. */ int -grub_script_lexer_yywrap (struct grub_parser_param *parserstate) +grub_script_lexer_yywrap (struct grub_parser_param *parserstate, + const char *input) { int len; - char *line; - char *line2; + char *p = 0; + char *line = 0; YY_BUFFER_STATE buffer; struct grub_lexer_param *lexerstate = parserstate->lexerstate; - if (!lexerstate->refs) - return 0; + if (! lexerstate->refs && ! lexerstate->prefix && ! input) + return 1; - if (!lexerstate->getline) + if (! lexerstate->getline && ! input) { grub_script_yyerror (parserstate, "unexpected end of file"); - return 0; + return 1; } line = 0; - buffer = 0; - lexerstate->getline (&line, 1); - if (!line) - { - grub_script_yyerror (parserstate, 0); /* XXX this could be for ^C case? */ - return 0; - } - - len = grub_strlen (line); - if (line[len - 1] == '\n') - { - buffer = yy_scan_string (line, lexerstate->yyscanner); - } + if (! input) + lexerstate->getline (&line, 1); else + line = grub_strdup (input); + + /* Ensure '\n' at the end. */ + if (line && line[0] == '\0') { - line2 = append_newline (line); - if (line2) - { - buffer = yy_scan_string (line2, lexerstate->yyscanner); - grub_free (line2); - } + grub_free (line); + line = grub_strdup ("\n"); } + if (line && (len = grub_strlen(line)) && line[len - 1] != '\n') + { + p = grub_realloc (line, len + 2); + if (p) + { + p[len++] = '\n'; + p[len] = '\0'; + } + line = p; + } + + if (! line) + { + grub_script_yyerror (parserstate, "out of memory"); + return 1; + } + + /* Prepend any left over unput-text. */ + if (lexerstate->prefix) + { + int plen = grub_strlen (lexerstate->prefix); + + p = grub_malloc (len + plen + 1); + if (! p) + { + grub_free (line); + return 1; + } + grub_strcpy (p, lexerstate->prefix); + lexerstate->prefix = 0; + + grub_strcpy (p + plen, line); + grub_free (line); + + line = p; + len = len + plen; + } + + buffer = yy_scan_string (line, lexerstate->yyscanner); grub_free (line); - if (!buffer) + + if (! buffer) { grub_script_yyerror (parserstate, 0); - return 0; + return 1; } - - return 1; + return 0; } struct grub_lexer_param * grub_script_lexer_init (struct grub_parser_param *parser, char *script, grub_reader_getline_t getline) { - int len; - char *script2; - YY_BUFFER_STATE buffer; struct grub_lexer_param *lexerstate; lexerstate = grub_zalloc (sizeof (*lexerstate)); @@ -232,34 +227,18 @@ grub_script_lexer_init (struct grub_parser_param *parser, char *script, return 0; } - buffer = 0; - script = script ? : "\n"; - len = grub_strlen (script); + yyset_extra (parser, lexerstate->yyscanner); + parser->lexerstate = lexerstate; - if (script[len - 1] == '\n') - { - buffer = yy_scan_string (script, lexerstate->yyscanner); - } - else - { - script2 = append_newline (script); - if (script2) - { - buffer = yy_scan_string (script2, lexerstate->yyscanner); - grub_free (script2); - } - } - - if (!buffer) + if (grub_script_lexer_yywrap (parser, script ?: "\n")) { + parser->lexerstate = 0; yylex_destroy (lexerstate->yyscanner); grub_free (lexerstate->yyscanner); - grub_free (lexerstate->text); grub_free (lexerstate); return 0; } - yyset_extra (parser, lexerstate->yyscanner); return lexerstate; } diff --git a/grub-core/script/main.c b/grub-core/script/main.c index ff714d060..482bb3fef 100644 --- a/grub-core/script/main.c +++ b/grub-core/script/main.c @@ -35,7 +35,7 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline) grub_script_execute (parsed_script); /* The parsed script was executed, throw it away. */ - grub_script_free (parsed_script); + grub_script_unref (parsed_script); } return grub_errno; @@ -44,6 +44,8 @@ grub_normal_parse_line (char *line, grub_reader_getline_t getline) static grub_command_t cmd_break; static grub_command_t cmd_continue; static grub_command_t cmd_shift; +static grub_command_t cmd_setparams; +static grub_command_t cmd_return; void grub_script_init (void) @@ -54,6 +56,11 @@ grub_script_init (void) N_("[n]"), N_("Continue loops")); cmd_shift = grub_register_command ("shift", grub_script_shift, N_("[n]"), N_("Shift positional parameters.")); + cmd_setparams = grub_register_command ("setparams", grub_script_setparams, + N_("[VALUE]..."), + N_("Set positional parameters.")); + cmd_return = grub_register_command ("return", grub_script_return, + N_("[n]"), N_("Return from a function.")); } void @@ -70,4 +77,12 @@ grub_script_fini (void) if (cmd_shift) grub_unregister_command (cmd_shift); cmd_shift = 0; + + if (cmd_setparams) + grub_unregister_command (cmd_setparams); + cmd_setparams = 0; + + if (cmd_return) + grub_unregister_command (cmd_return); + cmd_return = 0; } diff --git a/grub-core/script/parser.y b/grub-core/script/parser.y index 99cd2ee31..88c7fe9e3 100644 --- a/grub-core/script/parser.y +++ b/grub-core/script/parser.y @@ -20,6 +20,7 @@ %{ #include #include +#include #define YYFREE grub_free #define YYMALLOC grub_malloc @@ -34,6 +35,11 @@ struct grub_script_arglist *arglist; struct grub_script_arg *arg; char *string; + struct { + unsigned offset; + struct grub_script_mem *memory; + struct grub_script *scripts; + }; } %token GRUB_PARSER_TOKEN_BAD @@ -70,15 +76,15 @@ %token GRUB_PARSER_TOKEN_WHILE "while" %token GRUB_PARSER_TOKEN_TIME "time" %token GRUB_PARSER_TOKEN_FUNCTION "function" -%token GRUB_PARSER_TOKEN_MENUENTRY "menuentry" %token GRUB_PARSER_TOKEN_NAME "name" %token GRUB_PARSER_TOKEN_WORD "word" +%type block block0 %type word argument arguments0 arguments1 %type script_init script %type grubcmd ifclause ifcmd forcmd whilecmd untilcmd -%type command commands1 menuentry statement +%type command commands1 statement %pure-parser %lex-param { struct grub_parser_param *state }; @@ -124,7 +130,6 @@ word: GRUB_PARSER_TOKEN_NAME { $$ = grub_script_add_arglist (state, 0, $1); } statement: command { $$ = $1; } | function { $$ = 0; } - | menuentry { $$ = $1; } ; argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } @@ -142,10 +147,77 @@ argument : "case" { $$ = grub_script_add_arglist (state, 0, $1); } | "until" { $$ = grub_script_add_arglist (state, 0, $1); } | "while" { $$ = grub_script_add_arglist (state, 0, $1); } | "function" { $$ = grub_script_add_arglist (state, 0, $1); } - | "menuentry" { $$ = grub_script_add_arglist (state, 0, $1); } | word { $$ = $1; } ; +/* + Block parameter is passed to commands in two forms: as unparsed + string and as pre-parsed grub_script object. Passing as grub_script + object makes memory management difficult, because: + + (1) Command may want to keep a reference to grub_script objects for + later use, so script framework may not free the grub_script + object after command completes. + + (2) Command may get called multiple times with same grub_script + object under loops, so we should not let command implementation + to free the grub_script object. + + To solve above problems, we rely on reference counting for + grub_script objects. Commands that want to keep the grub_script + object must take a reference to it. + + Other complexity comes with arbitrary nesting of grub_script + objects: a grub_script object may have commands with several block + parameters, and each block parameter may further contain multiple + block parameters nested. We use temporary variable, state->scripts + to collect nested child scripts (that are linked by siblings and + children members), and will build grub_scripts tree from bottom. + */ +block: "{" + { + grub_script_lexer_ref (state->lexerstate); + $$ = grub_script_lexer_record_start (state); + $$ = grub_script_mem_record (state); + + /* save currently known scripts. */ + $$ = state->scripts; + state->scripts = 0; + } + commands1 delimiters0 "}" + { + char *p; + struct grub_script_mem *memory; + struct grub_script *s = $2; + + memory = grub_script_mem_record_stop (state, $2); + if ((p = grub_script_lexer_record_stop (state, $2))) + *grub_strrchr (p, '}') = '\0'; + + $$ = grub_script_arg_add (state, 0, GRUB_SCRIPT_ARG_TYPE_BLOCK, p); + if (! $$ || ! ($$->script = grub_script_create ($3, memory))) + grub_script_mem_free (memory); + + else { + /* attach nested scripts to $$->script as children */ + $$->script->children = state->scripts; + + /* restore old scripts; append $$->script to siblings. */ + state->scripts = $2 ?: $$->script; + if (s) { + while (s->next_siblings) + s = s->next_siblings; + s->next_siblings = $$->script; + } + } + + grub_script_lexer_deref (state->lexerstate); + } +; +block0: /* Empty */ { $$ = 0; } + | block { $$ = $1; } +; + arguments0: /* Empty */ { $$ = 0; } | arguments1 { $$ = $1; } ; @@ -161,12 +233,17 @@ arguments1: argument arguments0 } ; -grubcmd: word arguments0 +grubcmd: word arguments0 block0 { - if ($1 && $2) { - $1->next = $2; - $1->argcount += $2->argcount; - $2->argcount = 0; + struct grub_script_arglist *x = $2; + + if ($3) + x = grub_script_add_arglist (state, $2, $3); + + if ($1 && x) { + $1->next = x; + $1->argcount += x->argcount; + x->argcount = 0; } $$ = grub_script_create_cmdline (state, $1); } @@ -191,10 +268,13 @@ commands1: newlines0 command } ; -function: "function" "name" +function: "function" "name" { grub_script_lexer_ref (state->lexerstate); state->func_mem = grub_script_mem_record (state); + + $$ = state->scripts; + state->scripts = 0; } delimiters0 "{" commands1 delimiters1 "}" { @@ -202,30 +282,18 @@ function: "function" "name" state->func_mem = grub_script_mem_record_stop (state, state->func_mem); script = grub_script_create ($6, state->func_mem); - if (script) - grub_script_function_create ($2, script); + if (! script) + grub_script_mem_free (state->func_mem); + else { + script->children = state->scripts; + grub_script_function_create ($2, script); + } + state->scripts = $3; grub_script_lexer_deref (state->lexerstate); } ; -menuentry: "menuentry" - { - grub_script_lexer_ref (state->lexerstate); - } - arguments1 - { - grub_script_lexer_record_start (state); - } - delimiters0 "{" commands1 delimiters1 "}" - { - char *menu_entry; - menu_entry = grub_script_lexer_record_stop (state); - grub_script_lexer_deref (state->lexerstate); - $$ = grub_script_create_cmdmenu (state, $3, menu_entry, 0); - } -; - ifcmd: "if" { grub_script_lexer_ref (state->lexerstate); diff --git a/grub-core/script/script.c b/grub-core/script/script.c index 9cee40dcb..ad3018357 100644 --- a/grub-core/script/script.c +++ b/grub-core/script/script.c @@ -54,7 +54,7 @@ grub_script_malloc (struct grub_parser_param *state, grub_size_t size) } /* Free all memory described by MEM. */ -static void +void grub_script_mem_free (struct grub_script_mem *mem) { struct grub_script_mem *memfree; @@ -94,9 +94,21 @@ grub_script_mem_record_stop (struct grub_parser_param *state, void grub_script_free (struct grub_script *script) { - if (!script) + struct grub_script *s; + struct grub_script *t; + + if (! script) return; - grub_script_mem_free (script->mem); + + if (script->mem) + grub_script_mem_free (script->mem); + + s = script->children; + while (s) { + t = s->next_siblings; + grub_script_unref (s); + s = t; + } grub_free (script); } @@ -119,6 +131,8 @@ grub_script_arg_add (struct grub_parser_param *state, return arg; argpart->type = type; + argpart->script = 0; + len = grub_strlen (str) + 1; argpart->str = grub_script_malloc (state, len); if (!argpart->str) @@ -267,30 +281,6 @@ grub_script_create_cmdwhile (struct grub_parser_param *state, return (struct grub_script_cmd *) cmd; } -/* Create a command that adds a menu entry to the menu. Title is an - argument that is parsed to generate a string that can be used as - the title. The sourcecode for this entry is passed in SOURCECODE. - The options for this entry are passed in OPTIONS. */ -struct grub_script_cmd * -grub_script_create_cmdmenu (struct grub_parser_param *state, - struct grub_script_arglist *arglist, - char *sourcecode, int options) -{ - struct grub_script_cmd_menuentry *cmd; - - cmd = grub_script_malloc (state, sizeof (*cmd)); - if (!cmd) - return 0; - - cmd->cmd.exec = grub_script_execute_menuentry; - cmd->cmd.next = 0; - cmd->sourcecode = sourcecode; - cmd->arglist = arglist; - cmd->options = options; - - return (struct grub_script_cmd *) cmd; -} - /* Create a chain of commands. LAST contains the command that should be added at the end of LIST's list. If LIST is zero, a new list will be created. */ @@ -335,16 +325,14 @@ grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem) struct grub_script *parsed; parsed = grub_malloc (sizeof (*parsed)); - if (!parsed) - { - grub_script_mem_free (mem); - grub_free (cmd); - - return 0; - } + if (! parsed) + return 0; parsed->mem = mem; parsed->cmd = cmd; + parsed->refcnt = 0; + parsed->children = 0; + parsed->next_siblings = 0; return parsed; } @@ -359,13 +347,16 @@ grub_script_parse (char *script, grub_reader_getline_t getline) struct grub_lexer_param *lexstate; struct grub_parser_param *parsestate; - parsed = grub_malloc (sizeof (*parsed)); + parsed = grub_script_create (0, 0); if (!parsed) return 0; parsestate = grub_zalloc (sizeof (*parsestate)); if (!parsestate) - return 0; + { + grub_free (parsed); + return 0; + } /* Initialize the lexer. */ lexstate = grub_script_lexer_init (parsestate, script, getline); @@ -388,11 +379,13 @@ grub_script_parse (char *script, grub_reader_getline_t getline) grub_script_mem_free (memfree); grub_script_lexer_fini (lexstate); grub_free (parsestate); + grub_free (parsed); return 0; } parsed->mem = grub_script_mem_record_stop (parsestate, membackup); parsed->cmd = parsestate->parsed; + parsed->children = parsestate->scripts; grub_script_lexer_fini (lexstate); grub_free (parsestate); diff --git a/grub-core/script/yylex.l b/grub-core/script/yylex.l index 45760c158..d4cad8097 100644 --- a/grub-core/script/yylex.l +++ b/grub-core/script/yylex.l @@ -58,6 +58,9 @@ #define YY_INPUT(buf,res,max) do { res = 0; } while (0) /* forward declarations */ +static int grub_lexer_unput (const char *input, yyscan_t yyscanner); +static int grub_lexer_resplit (const char *input, yyscan_t yyscanner); + static void grub_lexer_yyfree (void *, yyscan_t yyscanner); static void* grub_lexer_yyalloc (yy_size_t, yyscan_t yyscanner); static void* grub_lexer_yyrealloc (void*, yy_size_t, yyscan_t yyscanner); @@ -99,7 +102,7 @@ typedef size_t yy_size_t; %option never-interactive %option noyyfree noyyalloc noyyrealloc -%option nounistd nostdinit nodefault noyylineno noyywrap +%option nounistd nostdinit nodefault noyylineno /* Reduce lexer size, by not defining these. */ %option noyy_top_state @@ -118,13 +121,17 @@ CHAR [^{}|&$;<> \t\n\'\"\\] DIGITS [[:digit:]]+ NAME [[:alpha:]_][[:alnum:]_]* -ESC \\. +ESC \\(.|\n) +SQCHR [^\'] +DQCHR {ESC}|[^\\\"] +DQSTR \"{DQCHR}*\" +SQSTR \'{SQCHR}*\' SPECIAL \?|\#|\*|\@ VARIABLE ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\} -DQSTR \"([^\\\"]|{ESC})*\" -SQSTR \'[^\']*\' WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ +MULTILINE {WORD}?((\"{DQCHR}*)|(\'{SQCHR}*)|(\\\n)) + %x SPLIT %x DQUOTE %x SQUOTE @@ -169,36 +176,33 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ "until" { RECORD; return GRUB_PARSER_TOKEN_UNTIL; } "while" { RECORD; return GRUB_PARSER_TOKEN_WHILE; } "function" { RECORD; return GRUB_PARSER_TOKEN_FUNCTION; } -"menuentry" { RECORD; return GRUB_PARSER_TOKEN_MENUENTRY; } + +{MULTILINE} { + if (grub_lexer_unput (yytext, yyscanner)) + return GRUB_PARSER_TOKEN_BAD; + } {NAME} { RECORD; return GRUB_PARSER_TOKEN_NAME; } {WORD} { RECORD; - /* resplit yytext */ - grub_dprintf ("lexer", "word: [%s]\n", yytext); - yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); - if (yy_scan_string (yytext, yyscanner)) - { - yyextra->lexerstate->merge_start = 1; - yy_push_state (SPLIT, yyscanner); - } - else - { - grub_script_yyerror (yyextra, 0); - yypop_buffer_state (yyscanner); - return GRUB_PARSER_TOKEN_WORD; - } + yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner); + if (grub_lexer_resplit (yytext, yyscanner)) + { + yypop_buffer_state (yyscanner); + return GRUB_PARSER_TOKEN_WORD; + } + yyextra->lexerstate->resplit = 1; } - -.|\n { - grub_script_yyerror (yyextra, "unrecognized token"); - return GRUB_PARSER_TOKEN_BAD; +. { + grub_script_yyerror (yyextra, yytext); + return GRUB_PARSER_TOKEN_BAD; } /* Split word into multiple args */ { \\. { COPY (yytext + 1, yyleng - 1); } + \\\n { /* ignore */ } \" { yy_push_state (DQUOTE, yyscanner); ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); @@ -216,6 +220,7 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ <> { yy_pop_state (yyscanner); yypop_buffer_state (yyscanner); + yyextra->lexerstate->resplit = 0; yyextra->lexerstate->merge_end = 1; ARG (GRUB_SCRIPT_ARG_TYPE_TEXT); } @@ -273,15 +278,20 @@ WORD ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE})+ <> { yypop_buffer_state (yyscanner); - if (! grub_script_lexer_yywrap (yyextra)) - { - yyextra->lexerstate->eof = 1; - return GRUB_PARSER_TOKEN_EOF; - } + yyextra->lexerstate->eof = 1; + return GRUB_PARSER_TOKEN_EOF; } - %% +int +yywrap (yyscan_t yyscanner) +{ + if (yyget_extra (yyscanner)->lexerstate->resplit) + return 1; + + return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0); +} + static void grub_lexer_yyfree (void *ptr, yyscan_t yyscanner __attribute__ ((unused))) { @@ -301,8 +311,6 @@ grub_lexer_yyrealloc (void *ptr, yy_size_t size, return grub_realloc (ptr, size); } -#define MAX(a,b) ((a) < (b) ? (b) : (a)) - static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint) { int size; @@ -312,7 +320,7 @@ static void copy_string (struct grub_parser_param *parser, const char *str, unsi len = hint ? hint : grub_strlen (str); if (parser->lexerstate->used + len >= parser->lexerstate->size) { - size = MAX (len, parser->lexerstate->size) * 2; + size = grub_max (len, parser->lexerstate->size) * 2; ptr = grub_realloc (parser->lexerstate->text, size); if (!ptr) { @@ -326,3 +334,34 @@ static void copy_string (struct grub_parser_param *parser, const char *str, unsi grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str); parser->lexerstate->used += len; } + +static int +grub_lexer_resplit (const char *text, yyscan_t yyscanner) +{ + /* resplit text */ + if (yy_scan_string (text, yyscanner)) + { + yyget_extra (yyscanner)->lexerstate->merge_start = 1; + yy_push_state (SPLIT, yyscanner); + return 0; + } + grub_script_yyerror (yyget_extra (yyscanner), 0); + return 1; +} + +static int +grub_lexer_unput (const char *text, yyscan_t yyscanner) +{ + struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate; + + if (lexerstate->prefix) + grub_free (lexerstate->prefix); + + lexerstate->prefix = grub_strdup (text); + if (! lexerstate->prefix) + { + grub_script_yyerror (yyget_extra (yyscanner), "out of memory"); + return 1; + } + return 0; +} diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c index dca002910..6027d0ab3 100644 --- a/grub-core/term/efi/console.c +++ b/grub-core/term/efi/console.c @@ -79,6 +79,9 @@ grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)), grub_efi_simple_text_output_interface_t *o; unsigned i, j; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; /* For now, do not try to use a surrogate pair. */ @@ -107,6 +110,9 @@ grub_console_checkkey (struct grub_term_input *term __attribute__ ((unused))) grub_efi_input_key_t key; grub_efi_status_t status; + if (grub_efi_is_finished) + return 0; + if (read_key >= 0) return 1; @@ -204,6 +210,9 @@ grub_console_getkey (struct grub_term_input *term) grub_efi_status_t status; int key; + if (grub_efi_is_finished) + return 0; + if (read_key >= 0) { key = read_key; @@ -236,7 +245,8 @@ grub_console_getwh (struct grub_term_output *term __attribute__ ((unused))) grub_efi_uintn_t columns, rows; o = grub_efi_system_table->con_out; - if (efi_call_4 (o->query_mode, o, o->mode->mode, &columns, &rows) != GRUB_EFI_SUCCESS) + if (grub_efi_is_finished || efi_call_4 (o->query_mode, o, o->mode->mode, + &columns, &rows) != GRUB_EFI_SUCCESS) { /* Why does this fail? */ columns = 80; @@ -251,6 +261,9 @@ grub_console_getxy (struct grub_term_output *term __attribute__ ((unused))) { grub_efi_simple_text_output_interface_t *o; + if (grub_efi_is_finished) + return 0; + o = grub_efi_system_table->con_out; return ((o->mode->cursor_column << 8) | o->mode->cursor_row); } @@ -261,6 +274,9 @@ grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)), { grub_efi_simple_text_output_interface_t *o; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; efi_call_3 (o->set_cursor_position, o, x, y); } @@ -271,6 +287,9 @@ grub_console_cls (struct grub_term_output *term __attribute__ ((unused))) grub_efi_simple_text_output_interface_t *o; grub_efi_int32_t orig_attr; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; orig_attr = o->mode->attribute; efi_call_2 (o->set_attributes, o, GRUB_EFI_BACKGROUND_BLACK); @@ -284,6 +303,9 @@ grub_console_setcolorstate (struct grub_term_output *term, { grub_efi_simple_text_output_interface_t *o; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; switch (state) { @@ -307,6 +329,9 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), { grub_efi_simple_text_output_interface_t *o; + if (grub_efi_is_finished) + return; + o = grub_efi_system_table->con_out; efi_call_2 (o->enable_cursor, o, on); } diff --git a/grub-core/term/gfxterm.c b/grub-core/term/gfxterm.c index bf9705abd..3616eb453 100644 --- a/grub-core/term/gfxterm.c +++ b/grub-core/term/gfxterm.c @@ -405,9 +405,16 @@ destroy_window (void) static grub_err_t grub_gfxterm_term_fini (struct grub_term_output *term __attribute__ ((unused))) { + unsigned i; destroy_window (); grub_video_restore (); + for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++) + { + grub_free (virtual_screen.text_buffer[i].code); + virtual_screen.text_buffer[i].code = 0; + } + /* Clear error state. */ grub_errno = GRUB_ERR_NONE; return GRUB_ERR_NONE; @@ -793,13 +800,8 @@ scroll_up (void) unsigned int i; /* Clear first line in text buffer. */ - for (i = 0; - i < virtual_screen.columns; - i++) - { - virtual_screen.text_buffer[i].code = 0; - clear_char (&(virtual_screen.text_buffer[i])); - } + for (i = 0; i < virtual_screen.columns; i++) + grub_free (virtual_screen.text_buffer[i].code); /* Scroll text buffer with one line to up. */ grub_memmove (virtual_screen.text_buffer, @@ -1111,11 +1113,10 @@ static const struct grub_arg_option background_image_cmd_options[] = }; static grub_err_t -grub_gfxterm_background_image_cmd (grub_extcmd_t cmd __attribute__ ((unused)), - int argc, - char **args) +grub_gfxterm_background_image_cmd (grub_extcmd_context_t ctxt, + int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; /* Check that we have video adapter active. */ if (grub_video_get_info(NULL) != GRUB_ERR_NONE) diff --git a/grub-core/term/i386/vga_common.c b/grub-core/term/i386/vga_common.c index 02fb5c02d..0c217697b 100644 --- a/grub-core/term/i386/vga_common.c +++ b/grub-core/term/i386/vga_common.c @@ -34,13 +34,13 @@ grub_console_setcolorstate (struct grub_term_output *term, { switch (state) { case GRUB_TERM_COLOR_STANDARD: - grub_console_cur_color = GRUB_TERM_DEFAULT_STANDARD_COLOR; + grub_console_cur_color = GRUB_TERM_DEFAULT_STANDARD_COLOR & 0x7f; break; case GRUB_TERM_COLOR_NORMAL: - grub_console_cur_color = term->normal_color; + grub_console_cur_color = term->normal_color & 0x7f; break; case GRUB_TERM_COLOR_HIGHLIGHT: - grub_console_cur_color = term->highlight_color; + grub_console_cur_color = term->highlight_color & 0x7f; break; default: break; diff --git a/grub-core/term/ns8250.c b/grub-core/term/ns8250.c index 315d3527f..f3a804d53 100644 --- a/grub-core/term/ns8250.c +++ b/grub-core/term/ns8250.c @@ -227,6 +227,16 @@ grub_ns8250_init (void) } } +/* Return the port number for the UNITth serial device. */ +grub_port_t +grub_ns8250_hw_get_port (const unsigned int unit) +{ + if (unit < GRUB_SERIAL_PORT_NUM) + return serial_hw_io_addr[unit]; + else + return 0; +} + char * grub_serial_ns8250_add_port (grub_port_t port) { diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c index 2268788af..394fc1576 100644 --- a/grub-core/term/serial.c +++ b/grub-core/term/serial.c @@ -150,9 +150,9 @@ grub_serial_find (char *name) } static grub_err_t -grub_cmd_serial (grub_extcmd_t cmd, int argc, char **args) +grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args) { - struct grub_arg_list *state = cmd->state; + struct grub_arg_list *state = ctxt->state; char pname[40]; char *name = NULL; struct grub_serial_port *port; diff --git a/grub-core/tests/boot/kbsd.init-i386.S b/grub-core/tests/boot/kbsd.init-i386.S new file mode 100644 index 000000000..7011c79ff --- /dev/null +++ b/grub-core/tests/boot/kbsd.init-i386.S @@ -0,0 +1,125 @@ +/* + * 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 . + */ + +#ifdef TARGET_NETBSD +#define SYSCALL_RESET 208 +#elif defined (TARGET_OPENBSD) +#define SYSCALL_RESET 55 +#else +#error unknown target +#endif + +#define MODE_RDRW 2 +#define FLAGS_NONE 0 +#define SYSCALL_OPEN 5 +#define SYSCALL_WRITE 4 +#define SYSCALL_EXIT 1 +#define SYSCALL_ARCH 165 +#define SYSCALL_INT 0x80 +#define SYSCALL_ARCH_IOPL 2 + +#define RESET_NOSYNC 0x4 +#define RESET_HALT 0x8 +#define RESET_POWEROFF 0x800 + +#define SHUTDOWN_PORT 0x8900 + + .section ".init", "ax" + .global start,_start +start: +_start: + /* open. */ + movl $SYSCALL_OPEN, %eax + pushl $FLAGS_NONE + pushl $MODE_RDRW + leal device, %ebx + pushl %ebx + pushl $0 + int $SYSCALL_INT + addl $16, %esp + movl %eax, %ecx + + /* write. */ + movl $SYSCALL_WRITE, %eax + pushl $(messageend-message) + leal message, %ebx + pushl %ebx + pushl %ecx + pushl $0 + int $SYSCALL_INT + addl $16, %esp + + /* IOPL. */ + movl $SYSCALL_ARCH, %eax + pushl $iopl_arg + pushl $SYSCALL_ARCH_IOPL + pushl $0 + int $SYSCALL_INT + addl $12, %esp + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movl $SYSCALL_RESET, %eax + pushl $0 + pushl $(RESET_POWEROFF|RESET_HALT|RESET_NOSYNC) + pushl $0 + int $SYSCALL_INT + addl $8, %esp + + /* exit (1). Shouldn't be reached. */ + movl $SYSCALL_EXIT, %eax + pushl $1 + pushl $0 + int $SYSCALL_INT + .section ".fini", "ax" +1: jmp 1b + .section ".text", "ax" +1: jmp 1b + /* This section is needed for NetBSD to identify the binary. */ + .section ".note.netbsd.ident", "a" + .long 0x7 + .long 0x4 + .long 0x1 + .ascii "NetBSD" + .byte 0 + .data +device: + .ascii "/dev/console" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: +iopl_arg: + .long 3 diff --git a/grub-core/tests/boot/kbsd.init-x86_64.S b/grub-core/tests/boot/kbsd.init-x86_64.S new file mode 100644 index 000000000..81f810e2c --- /dev/null +++ b/grub-core/tests/boot/kbsd.init-x86_64.S @@ -0,0 +1,111 @@ +/* + * 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 . + */ + +#define MODE_RDRW 2 +#define FLAGS_NONE 0 +#define SYSCALL_OPEN 5 +#define SYSCALL_WRITE 4 +#ifdef TARGET_NETBSD +#define SYSCALL_RESET 208 +#elif defined (TARGET_OPENBSD) +#define SYSCALL_RESET 55 +#else +#error unknown target +#endif +#define SYSCALL_EXIT 1 +#define SYSCALL_ARCH 165 +#define SYSCALL_INT 0x80 +#define SYSCALL_ARCH_IOPL 2 + +#define RESET_NOSYNC 0x4 +#define RESET_HALT 0x8 +#define RESET_POWEROFF 0x800 +#define SHUTDOWN_PORT 0x8900 + + .section ".init", "ax" + .global start,_start +start: +_start: + /* open. */ + movq $SYSCALL_OPEN, %rax + leaq device, %rdi + movq $MODE_RDRW, %rsi + movq $FLAGS_NONE, %rdx + syscall + movq %rax, %rdi + + /* write. */ + movq $SYSCALL_WRITE, %rax + movq $(messageend-message), %rdx + leaq message, %rsi + syscall + + /* IOPL. */ + movq $SYSCALL_ARCH, %rax + movq $SYSCALL_ARCH_IOPL, %rdi + leaq iopl_arg, %rsi + syscall + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movq $SYSCALL_RESET, %rax + movq $(RESET_POWEROFF|RESET_HALT|RESET_NOSYNC), %rdi + movq $0, %rsi + syscall + + /* exit (1). Shouldn't be reached. */ + movq $SYSCALL_EXIT, %rax + movq $1, %rdi + syscall + .section ".fini", "ax" +1: jmp 1b + .section ".text", "ax" +1: jmp 1b + /* This section is needed for NetBSD to identify the binary. */ + .section ".note.netbsd.ident", "a" + .long 0x7 + .long 0x4 + .long 0x1 + .ascii "NetBSD" + .byte 0 + .data +device: + .ascii "/dev/console" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: +iopl_arg: + .long 3 diff --git a/grub-core/tests/boot/kbsd.spec.txt b/grub-core/tests/boot/kbsd.spec.txt new file mode 100644 index 000000000..af171bc56 --- /dev/null +++ b/grub-core/tests/boot/kbsd.spec.txt @@ -0,0 +1,3 @@ +. type=dir + dev type=dir + console type=char device=0 mode=666 gid=0 uid=0 diff --git a/grub-core/tests/boot/kernel-8086.S b/grub-core/tests/boot/kernel-8086.S new file mode 100644 index 000000000..20040dabc --- /dev/null +++ b/grub-core/tests/boot/kernel-8086.S @@ -0,0 +1,69 @@ + +#define SHUTDOWN_PORT 0x8900 + + .text + .globl _start +_start: +base: + .code16 + jmp cont + +portmsg: + xorw %ax, %ax +1: + movb 0(%si), %al + test %ax, %ax + jz 1f + outb %al, %dx + incw %si + jmp 1b +1: + ret + +serialmsg: +1: + movb 0(%si), %bl + testb %bl, %bl + jz 1f + movw $0x3fd, %dx +2: + inb %dx, %al + testb $0x20, %al + jz 2b + + movw $0x3f8, %dx + movb %bl, %al + outb %al, %dx + incw %si + jmp 1b +1: + ret + +cont: +#ifdef TARGET_NTLDR + movw $0x2000, %ax +#elif defined (TARGET_CHAINLOADER) + xorw %ax, %ax +#else +#error unsupported target +#endif + movw %ax, %ds + lea message, %si + call serialmsg + lea shutdown, %si + movw $SHUTDOWN_PORT, %dx + call portmsg + +1: + hlt + jmp 1b + +shutdown: + .ascii "Shutdown" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" + .byte 0 + + . = base + 510 + .short 0xaa55 \ No newline at end of file diff --git a/grub-core/tests/boot/kernel-i386.S b/grub-core/tests/boot/kernel-i386.S new file mode 100644 index 000000000..904b0d4c7 --- /dev/null +++ b/grub-core/tests/boot/kernel-i386.S @@ -0,0 +1,89 @@ +#define ASM_FILE 1 +#ifdef TARGET_MULTIBOOT2 +#include +#elif defined (TARGET_MULTIBOOT) +#include +#endif + +#define SHUTDOWN_PORT 0x8900 + + .text + /* Align 32 bits boundary. */ + .align 8 + +#ifdef TARGET_MULTIBOOT2 + /* Multiboot header. */ +multiboot_header: + /* magic */ + .long MULTIBOOT2_HEADER_MAGIC + /* ISA: i386 */ + .long MULTIBOOT_ARCHITECTURE_I386 + /* Header length. */ + .long multiboot_header_end - multiboot_header + /* checksum */ + .long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (multiboot_header_end - multiboot_header)) + .short MULTIBOOT_HEADER_TAG_END + .short 0 + .long 8 +multiboot_header_end: +#elif defined (TARGET_MULTIBOOT) + /* Multiboot header. */ +multiboot_header: + /* magic */ + .long MULTIBOOT_HEADER_MAGIC + /* flags */ + .long 0 + /* checksum */ + .long -MULTIBOOT_HEADER_MAGIC +#endif + + .global start +portmsg: + xorl %eax, %eax +1: + movb 0(%esi), %al + test %eax, %eax + jz 1f + outb %al, %dx + incl %esi + jmp 1b +1: + ret + +serialmsg: +1: + movb 0(%esi), %bl + testb %bl, %bl + jz 1f + movw $0x3fd, %dx +2: + inb %dx, %al + testb $0x20, %al + jz 2b + + movw $0x3f8, %dx + movb %bl, %al + outb %al, %dx + incl %esi + jmp 1b +1: + ret + + .globl _start +_start: + lea message, %esi + call serialmsg + lea shutdown, %esi + movw $SHUTDOWN_PORT, %dx + call portmsg + +1: + hlt + jmp 1b + +shutdown: + .ascii "Shutdown" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" + .byte 0 diff --git a/grub-core/tests/boot/kfreebsd-aout.cfg b/grub-core/tests/boot/kfreebsd-aout.cfg new file mode 100644 index 000000000..31e34b4ee --- /dev/null +++ b/grub-core/tests/boot/kfreebsd-aout.cfg @@ -0,0 +1,4 @@ +kfreebsd /kfreebsd.aout +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/kfreebsd.cfg b/grub-core/tests/boot/kfreebsd.cfg new file mode 100644 index 000000000..f28ee7998 --- /dev/null +++ b/grub-core/tests/boot/kfreebsd.cfg @@ -0,0 +1,8 @@ +kfreebsd /kfreebsd -hv +kfreebsd_loadenv /kfreebsd_env +kfreebsd_module /mfsroot.gz type=mfs_root +set kFreeBSD.hw.hasbrokenint12=1 +fakebios +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/kfreebsd.init-i386.S b/grub-core/tests/boot/kfreebsd.init-i386.S new file mode 100644 index 000000000..12c94a036 --- /dev/null +++ b/grub-core/tests/boot/kfreebsd.init-i386.S @@ -0,0 +1,114 @@ +/* + * 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 . + */ + +#define MODE_RDRW 2 +#define FLAGS_NONE 0 +#define SYSCALL_OPEN 5 +#define SYSCALL_WRITE 4 +#define SYSCALL_RESET 55 +#define SYSCALL_FSYNC 95 +#define SYSCALL_ARCH 165 +#define SYSCALL_EXIT 1 +#define SYSCALL_ARCH_IOPL 4 +#define SYSCALL_INT 0x80 + +#define RESET_NOSYNC 0x4 +#define RESET_HALT 0x8 +#define RESET_POWEROFF 0x4000 +#define SHUTDOWN_PORT 0x8900 + + .section ".init", "ax" + .global start,_start +start: +_start: + /* open. */ + movl $SYSCALL_OPEN, %eax + pushl $FLAGS_NONE + pushl $MODE_RDRW + leal device, %ebx + pushl %ebx + pushl $0 + int $SYSCALL_INT + addl $16, %esp + movl %eax, %ecx + + /* write. */ + movl $SYSCALL_WRITE, %eax + pushl $(messageend-message) + leal message, %ebx + pushl %ebx + pushl %ecx + pushl $0 + int $SYSCALL_INT + addl $16, %esp + + /* fsync. */ + movl $SYSCALL_FSYNC, %eax + pushl %ecx + pushl $0 + int $SYSCALL_INT + addl $8, %esp + + /* IOPL. */ + movl $SYSCALL_ARCH, %eax + pushl $iopl_arg + pushl $SYSCALL_ARCH_IOPL + pushl $0 + int $SYSCALL_INT + addl $12, %esp + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movl $SYSCALL_RESET, %eax + pushl $(RESET_POWEROFF|RESET_HALT|RESET_NOSYNC) + pushl $0 + int $SYSCALL_INT + addl $8, %esp + + /* exit (1). Shouldn't be reached. */ + movl $SYSCALL_EXIT, %eax + pushl $1 + pushl $0 + int $SYSCALL_INT +device: + .ascii "/dev/console" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: +iopl_arg: + .long SHUTDOWN_PORT + .long 1 + .long 1 diff --git a/grub-core/tests/boot/kfreebsd.init-x86_64.S b/grub-core/tests/boot/kfreebsd.init-x86_64.S new file mode 100644 index 000000000..0a9ff511e --- /dev/null +++ b/grub-core/tests/boot/kfreebsd.init-x86_64.S @@ -0,0 +1,98 @@ +/* + * 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 . + */ + +#define MODE_RDRW 2 +#define FLAGS_NONE 0 +#define SYSCALL_ARCH 165 +#define SYSCALL_OPEN 5 +#define SYSCALL_WRITE 4 +#define SYSCALL_RESET 55 +#define SYSCALL_EXIT 1 +#define SYSCALL_ARCH_IOPL 4 +#define SYSCALL_FSYNC 95 + +#define RESET_NOSYNC 0x4 +#define RESET_HALT 0x8 +#define RESET_POWEROFF 0x4000 +#define SHUTDOWN_PORT 0x8900 + + .section ".init", "ax" + .global start,_start +start: +_start: + /* open. */ + movq $SYSCALL_OPEN, %rax + leaq device, %rdi + movq $MODE_RDRW, %rsi + movq $FLAGS_NONE, %rdx + syscall + movq %rax, %rdi + + /* write. */ + leaq message, %rsi + movq $SYSCALL_WRITE, %rax + movq $(messageend - message), %rdx + syscall + + /* fsync. */ + movq $SYSCALL_FSYNC, %rax + syscall + + /* IOPL. */ + movq $SYSCALL_ARCH, %rax + movq $SYSCALL_ARCH_IOPL, %rdi + leaq iopl_arg, %rsi + syscall + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movq $SYSCALL_RESET, %rax + movq $(RESET_POWEROFF|RESET_HALT|RESET_NOSYNC), %rdi + syscall + + /* exit (1). Shouldn't be reached. */ + movq $SYSCALL_EXIT, %rax + movq $1, %rdi + syscall +device: + .ascii "/dev/console" + .byte 0 +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: +iopl_arg: + .long SHUTDOWN_PORT + .long 1 + .long 1 diff --git a/grub-core/tests/boot/knetbsd.cfg b/grub-core/tests/boot/knetbsd.cfg new file mode 100644 index 000000000..f88a846e1 --- /dev/null +++ b/grub-core/tests/boot/knetbsd.cfg @@ -0,0 +1,5 @@ +knetbsd /knetbsd -h +knetbsd_module_elf /miniroot.gz +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/kopenbsd.cfg b/grub-core/tests/boot/kopenbsd.cfg new file mode 100644 index 000000000..132bec4b6 --- /dev/null +++ b/grub-core/tests/boot/kopenbsd.cfg @@ -0,0 +1,5 @@ +kopenbsd /kopenbsd -h +kopenbsd_ramdisk /ramdisk +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/kopenbsdlabel.txt b/grub-core/tests/boot/kopenbsdlabel.txt new file mode 100644 index 000000000..bb141133b --- /dev/null +++ b/grub-core/tests/boot/kopenbsdlabel.txt @@ -0,0 +1,3 @@ +# size offset fstype [fsize bsize bps/cpg] + a: 256 0 4.2BSD 0 0 1 + c: 256 0 unused 0 0 # "raw" part, don't edit diff --git a/grub-core/tests/boot/linux.cfg b/grub-core/tests/boot/linux.cfg new file mode 100644 index 000000000..f5bf6ac7d --- /dev/null +++ b/grub-core/tests/boot/linux.cfg @@ -0,0 +1,5 @@ +linux /linux console=ttyS0 root=/dev/ram0 +initrd /initrd +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/linux.init-i386.S b/grub-core/tests/boot/linux.init-i386.S new file mode 100644 index 000000000..5b0088e00 --- /dev/null +++ b/grub-core/tests/boot/linux.init-i386.S @@ -0,0 +1,79 @@ +/* + * 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 . + */ + +#define SYSCALL_WRITE 4 +#define SYSCALL_RESET 88 +#define SYSCALL_IOPL 110 +#define SYSCALL_EXIT 1 +#define SYSCALL_INT 0x80 + +#define STDOUT 1 +#define SHUTDOWN_MAGIC1 0xfee1dead +#define SHUTDOWN_MAGIC2 0x28121969 +#define SHUTDOWN_MAGIC3 0x4321fedc + +#define SHUTDOWN_PORT 0x8900 + + .text + .global start, _start +_start: +start: + /* write. */ + movl $SYSCALL_WRITE, %eax + movl $STDOUT, %ebx + leal message, %ecx + movl $(messageend-message), %edx + int $SYSCALL_INT + + movl $SYSCALL_IOPL, %eax + movl $3, %ebx + int $SYSCALL_INT + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movl $SYSCALL_RESET, %eax + movl $SHUTDOWN_MAGIC1, %ebx + movl $SHUTDOWN_MAGIC2, %ecx + movl $SHUTDOWN_MAGIC3, %edx + int $SYSCALL_INT + + /* exit (1). Shouldn't be reached. */ + movl $SYSCALL_EXIT, %eax + movl $1, %ebx + int $SYSCALL_INT + .data +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: diff --git a/grub-core/tests/boot/linux.init-x86_64.S b/grub-core/tests/boot/linux.init-x86_64.S new file mode 100644 index 000000000..fc32dfd91 --- /dev/null +++ b/grub-core/tests/boot/linux.init-x86_64.S @@ -0,0 +1,78 @@ +/* + * 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 . + */ + +#define SYSCALL_WRITE 1 +#define SYSCALL_RESET 169 +#define SYSCALL_IOPL 172 +#define SYSCALL_EXIT 60 + +#define STDOUT 1 +#define SHUTDOWN_MAGIC1 0xfee1dead +#define SHUTDOWN_MAGIC2 0x28121969 +#define SHUTDOWN_MAGIC3 0x4321fedc + +#define SHUTDOWN_PORT 0x8900 + + .text + .global start, _start +_start: +start: + /* write. */ + movq $SYSCALL_WRITE, %rax + movq $STDOUT, %rdi + leaq message, %rsi + movq $(messageend-message), %rdx + syscall + + movq $SYSCALL_IOPL, %rax + movq $3, %rdi + syscall + + movw $SHUTDOWN_PORT, %dx + movb $'S', %al + outb %al, %dx + movb $'h', %al + outb %al, %dx + movb $'u', %al + outb %al, %dx + movb $'t', %al + outb %al, %dx + movb $'d', %al + outb %al, %dx + movb $'o', %al + outb %al, %dx + movb $'w', %al + outb %al, %dx + movb $'n', %al + outb %al, %dx + + /* shutdown. */ + movq $SYSCALL_RESET, %rax + movq $SHUTDOWN_MAGIC1, %rdi + movq $SHUTDOWN_MAGIC2, %rsi + movq $SHUTDOWN_MAGIC3, %rdx + syscall + + /* exit(1). Shouldn't be reached. */ + movq $SYSCALL_EXIT, %rax + movq $1, %rdi + syscall + .data +message: + .ascii "Boot Test Passed Successfully\n" SUCCESSFUL_BOOT_STRING "\n" +messageend: diff --git a/grub-core/tests/boot/linux16.cfg b/grub-core/tests/boot/linux16.cfg new file mode 100644 index 000000000..d7fbf961c --- /dev/null +++ b/grub-core/tests/boot/linux16.cfg @@ -0,0 +1,5 @@ +linux16 /linux console=ttyS0 root=/dev/ram0 +initrd16 /initrd +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/multiboot.cfg b/grub-core/tests/boot/multiboot.cfg new file mode 100644 index 000000000..0942ec67c --- /dev/null +++ b/grub-core/tests/boot/multiboot.cfg @@ -0,0 +1,4 @@ +multiboot /multiboot.elf +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/multiboot2.cfg b/grub-core/tests/boot/multiboot2.cfg new file mode 100644 index 000000000..2bec9e6d1 --- /dev/null +++ b/grub-core/tests/boot/multiboot2.cfg @@ -0,0 +1,4 @@ +multiboot2 /multiboot2.elf +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/ntldr.cfg b/grub-core/tests/boot/ntldr.cfg new file mode 100644 index 000000000..cd438a4bc --- /dev/null +++ b/grub-core/tests/boot/ntldr.cfg @@ -0,0 +1,4 @@ +ntldr /ntldr.bin +boot +# Shouln't happen +halt diff --git a/grub-core/tests/boot/pc-chainloader.cfg b/grub-core/tests/boot/pc-chainloader.cfg new file mode 100644 index 000000000..1e80a5b96 --- /dev/null +++ b/grub-core/tests/boot/pc-chainloader.cfg @@ -0,0 +1,4 @@ +chainloader /pc-chainloader.bin +boot +# Shouln't happen +halt diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c index 6aafe4dbb..82bf372c0 100644 --- a/grub-core/tests/lib/functional_test.c +++ b/grub-core/tests/lib/functional_test.c @@ -22,7 +22,7 @@ #include static grub_err_t -grub_functional_test (struct grub_extcmd *cmd __attribute__ ((unused)), +grub_functional_test (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { diff --git a/grub-core/tests/test_blockarg.c b/grub-core/tests/test_blockarg.c new file mode 100644 index 000000000..bb6f3c3f0 --- /dev/null +++ b/grub-core/tests/test_blockarg.c @@ -0,0 +1,51 @@ +/* test_blockarg.c - print and execute block argument */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +static grub_err_t +test_blockarg (grub_extcmd_context_t ctxt, int argc, char **args) +{ + if (! ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no block parameter"); + + grub_printf ("%s\n", args[argc - 1]); + grub_script_execute (ctxt->script); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(test_blockarg) +{ + cmd = grub_register_extcmd ("test_blockarg", test_blockarg, + GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_BLOCKS, + N_("BLOCK"), + N_("Print and execute block argument."), 0); +} + +GRUB_MOD_FINI(test_blockarg) +{ + grub_unregister_extcmd (cmd); +} diff --git a/grub-core/video/i386/pc/vbe.c b/grub-core/video/i386/pc/vbe.c index 7581c48b1..3817b3f68 100644 --- a/grub-core/video/i386/pc/vbe.c +++ b/grub-core/video/i386/pc/vbe.c @@ -28,6 +28,7 @@ #include #include #include +#include static int vbe_detected = -1; @@ -58,6 +59,200 @@ real2pm (grub_vbe_farptr_t ptr) + ((unsigned long) ptr & 0x0000FFFF)); } +/* Call VESA BIOS 0x4f09 to set palette data, return status. */ +static grub_vbe_status_t +grub_vbe_bios_set_palette_data (grub_uint32_t color_count, + grub_uint32_t start_index, + struct grub_vbe_palette_data *palette_data) +{ + struct grub_bios_int_registers regs; + regs.eax = 0x4f09; + regs.ebx = 0; + regs.ecx = color_count; + regs.edx = start_index; + regs.es = (((grub_addr_t) palette_data) & 0xffff0000) >> 4; + regs.edi = ((grub_addr_t) palette_data) & 0xffff; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f00 to get VBE Controller Information, return status. */ +grub_vbe_status_t +grub_vbe_bios_get_controller_info (struct grub_vbe_info_block *ci) +{ + struct grub_bios_int_registers regs; + /* Store *controller_info to %es:%di. */ + regs.es = (((grub_addr_t) ci) & 0xffff0000) >> 4; + regs.edi = ((grub_addr_t) ci) & 0xffff; + regs.eax = 0x4f00; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f01 to get VBE Mode Information, return status. */ +grub_vbe_status_t +grub_vbe_bios_get_mode_info (grub_uint32_t mode, + struct grub_vbe_mode_info_block *mode_info) +{ + struct grub_bios_int_registers regs; + regs.eax = 0x4f01; + regs.ecx = mode; + /* Store *mode_info to %es:%di. */ + regs.es = ((grub_addr_t) mode_info & 0xffff0000) >> 4; + regs.edi = (grub_addr_t) mode_info & 0x0000ffff; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f02 to set video mode, return status. */ +static grub_vbe_status_t +grub_vbe_bios_set_mode (grub_uint32_t mode, + struct grub_vbe_crtc_info_block *crtc_info) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f02; + regs.ebx = mode; + /* Store *crtc_info to %es:%di. */ + regs.es = (((grub_addr_t) crtc_info) & 0xffff0000) >> 4; + regs.edi = ((grub_addr_t) crtc_info) & 0xffff; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f03 to return current VBE Mode, return status. */ +grub_vbe_status_t +grub_vbe_bios_get_mode (grub_uint32_t *mode) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f03; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + *mode = regs.ebx & 0xffff; + + return regs.eax & 0xffff; +} + +grub_vbe_status_t +grub_vbe_bios_getset_dac_palette_width (int set, int *dac_mask_size) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f08; + regs.ebx = (*dac_mask_size & 0xff) >> 8; + regs.ebx = set ? 1 : 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + *dac_mask_size = (regs.ebx >> 8) & 0xff; + + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f05 to set memory window, return status. */ +grub_vbe_status_t +grub_vbe_bios_set_memory_window (grub_uint32_t window, + grub_uint32_t position) +{ + struct grub_bios_int_registers regs; + + /* BL = window, BH = 0, Set memory window. */ + regs.ebx = window & 0x00ff; + regs.edx = position; + regs.eax = 0x4f05; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f05 to return memory window, return status. */ +grub_vbe_status_t +grub_vbe_bios_get_memory_window (grub_uint32_t window, + grub_uint32_t *position) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f05; + /* BH = 1, Get memory window. BL = window. */ + regs.ebx = (window & 0x00ff) | 0x100; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + + *position = regs.edx & 0xffff; + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f06 to set scanline length (in bytes), return status. */ +grub_vbe_status_t +grub_vbe_bios_set_scanline_length (grub_uint32_t length) +{ + struct grub_bios_int_registers regs; + + regs.ecx = length; + regs.eax = 0x4f06; + /* BL = 2, Set Scan Line in Bytes. */ + regs.ebx = 0x0002; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f06 to return scanline length (in bytes), return status. */ +grub_vbe_status_t +grub_vbe_bios_get_scanline_length (grub_uint32_t *length) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f06; + regs.ebx = 0x0001; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + /* BL = 1, Get Scan Line Length (in bytes). */ + grub_bios_interrupt (0x10, ®s); + + *length = regs.ebx & 0xffff; + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f07 to set display start, return status. */ +static grub_vbe_status_t +grub_vbe_bios_set_display_start (grub_uint32_t x, grub_uint32_t y) +{ + struct grub_bios_int_registers regs; + + /* Store x in %ecx. */ + regs.ecx = x; + regs.edx = y; + regs.eax = 0x4f07; + /* BL = 80h, Set Display Start during Vertical Retrace. */ + regs.ebx = 0x0080; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + return regs.eax & 0xffff; +} + +/* Call VESA BIOS 0x4f07 to get display start, return status. */ +grub_vbe_status_t +grub_vbe_bios_get_display_start (grub_uint32_t *x, + grub_uint32_t *y) +{ + struct grub_bios_int_registers regs; + + regs.eax = 0x4f07; + /* BL = 1, Get Display Start. */ + regs.ebx = 0x0001; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + + *x = regs.ecx & 0xffff; + *y = regs.edx & 0xffff; + return regs.eax & 0xffff; +} + grub_err_t grub_vbe_probe (struct grub_vbe_info_block *info_block) { diff --git a/grub-core/video/i386/pc/vga.c b/grub-core/video/i386/pc/vga.c index 3fbb18bb0..41b8d3eb1 100644 --- a/grub-core/video/i386/pc/vga.c +++ b/grub-core/video/i386/pc/vga.c @@ -19,6 +19,7 @@ #define grub_video_render_target grub_video_fbrender_target #include +#include #include #include #include @@ -46,6 +47,25 @@ static struct int back_page; } framebuffer; +static unsigned char +grub_vga_set_mode (unsigned char mode) +{ + struct grub_bios_int_registers regs; + unsigned char ret; + /* get current mode */ + regs.eax = 0x0f00; + regs.ebx = 0; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + + ret = regs.eax & 0xff; + regs.eax = mode; + regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT; + grub_bios_interrupt (0x10, ®s); + + return ret; +} + static inline void wait_vretrace (void) { diff --git a/include/grub/aout.h b/include/grub/aout.h index f962a97b3..10d7dde61 100644 --- a/include/grub/aout.h +++ b/include/grub/aout.h @@ -120,8 +120,8 @@ union grub_aout_header int EXPORT_FUNC(grub_aout_get_type) (union grub_aout_header *header); grub_err_t EXPORT_FUNC(grub_aout_load) (grub_file_t file, int offset, - grub_addr_t load_addr, int load_size, - grub_addr_t bss_end_addr); + void *load_addr, int load_size, + grub_size_t bss_size); #endif diff --git a/include/grub/autoefi.h b/include/grub/autoefi.h index 5ae4b3a21..740be3249 100644 --- a/include/grub/autoefi.h +++ b/include/grub/autoefi.h @@ -50,6 +50,7 @@ static inline grub_err_t grub_autoefi_prepare (void) # define SYSTEM_TABLE_PTR(x) ((void *)(grub_efi_system_table->x)) # define SIZEOF_OF_UINTN sizeof (grub_efi_uintn_t) # define SYSTEM_TABLE(x) (grub_efi_system_table->x) +# define grub_autoefi_finish_boot_services grub_efi_finish_boot_services # define EFI_PRESENT 1 #else # include @@ -72,6 +73,7 @@ static inline grub_err_t grub_autoefi_prepare (void) # define SYSTEM_TABLE GRUB_EFIEMU_SYSTEM_TABLE # define grub_efi_allocate_pages(x,y) (x) # define grub_efi_free_pages(x,y) GRUB_EFI_SUCCESS +# define grub_autoefi_finish_boot_services grub_efiemu_finish_boot_services # define EFI_PRESENT 1 #endif diff --git a/include/grub/command.h b/include/grub/command.h index 6bd3d07c9..599b99437 100644 --- a/include/grub/command.h +++ b/include/grub/command.h @@ -37,6 +37,8 @@ #define GRUB_COMMAND_FLAG_EXTCMD 0x10 /* This is an dynamic command. */ #define GRUB_COMMAND_FLAG_DYNCMD 0x20 +/* This command accepts block arguments. */ +#define GRUB_COMMAND_FLAG_BLOCKS 0x40 struct grub_command; diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 48b52ee65..ebe78e7a1 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -243,10 +243,12 @@ extern gcry_md_spec_t _gcry_digest_spec_md5; extern gcry_md_spec_t _gcry_digest_spec_sha1; extern gcry_md_spec_t _gcry_digest_spec_sha256; extern gcry_md_spec_t _gcry_digest_spec_sha512; +extern gcry_md_spec_t _gcry_digest_spec_crc32; #define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) #define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1) #define GRUB_MD_SHA256 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha256) #define GRUB_MD_SHA512 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha512) +#define GRUB_MD_CRC32 ((const gcry_md_spec_t *) &_gcry_digest_spec_crc32) /* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant of digest supplied by MD. Inputs are the password P of length PLEN, diff --git a/include/grub/dl.h b/include/grub/dl.h index 9db610467..afc4af41a 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -101,7 +101,6 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); void grub_dl_unload_unneeded (void); -void grub_dl_unload_all (void); int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); extern grub_dl_t EXPORT_VAR(grub_dl_head); diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 5852a476f..e9c57dd11 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -53,8 +53,10 @@ void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp); char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); grub_efi_device_path_t * EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle); -int EXPORT_FUNC(grub_efi_exit_boot_services) (grub_efi_uintn_t map_key); -int EXPORT_FUNC (grub_efi_finish_boot_services) (void); +grub_err_t EXPORT_FUNC (grub_efi_finish_boot_services) (grub_efi_uintn_t *outbuf_size, void *outbuf, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *efi_desc_size, + grub_efi_uint32_t *efi_desc_version); grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memory_map_size, grub_efi_uintn_t descriptor_size, grub_efi_uint32_t descriptor_version, @@ -70,4 +72,6 @@ void grub_efi_set_prefix (void); extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); +extern int EXPORT_VAR(grub_efi_is_finished); + #endif /* ! GRUB_EFI_EFI_HEADER */ diff --git a/include/grub/efiemu/efiemu.h b/include/grub/efiemu/efiemu.h index 3980d32cd..56d4ea8ee 100644 --- a/include/grub/efiemu/efiemu.h +++ b/include/grub/efiemu/efiemu.h @@ -217,13 +217,20 @@ int grub_efiemu_get_memory_map (grub_efi_uintn_t *memory_map_size, grub_efi_uintn_t *map_key, grub_efi_uintn_t *descriptor_size, grub_efi_uint32_t *descriptor_version); + + +grub_err_t +grub_efiemu_finish_boot_services (grub_efi_uintn_t *memory_map_size, + grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t *map_key, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version); + grub_err_t grub_efiemu_mmap_iterate (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); int grub_efiemu_sizeof_uintn_t (void); -int grub_efiemu_exit_boot_services (grub_efi_uintn_t map_key); -int grub_efiemu_finish_boot_services (void); grub_err_t grub_efiemu_get_lower_upper_memory (grub_uint64_t *lower, grub_uint64_t *upper); #define GRUB_EFIEMU_MEMORY_AVAILABLE 1 @@ -283,4 +290,6 @@ grub_efiemu_set_virtual_address_map (grub_efi_uintn_t memory_map_size, __attribute__ ((unused)), grub_efi_memory_descriptor_t *virtual_map); +grub_err_t grub_machine_efiemu_init_tables (void); + #endif /* ! GRUB_EFI_EMU_HEADER */ diff --git a/include/grub/elfload.h b/include/grub/elfload.h index 77ee41675..83fb9128a 100644 --- a/include/grub/elfload.h +++ b/include/grub/elfload.h @@ -54,5 +54,13 @@ int grub_elf_is_elf64 (grub_elf_t); grub_size_t grub_elf64_size (grub_elf_t, Elf64_Addr *); grub_err_t grub_elf64_load (grub_elf_t, grub_elf64_load_hook_t, grub_addr_t *, grub_size_t *); +grub_err_t +grub_elf32_phdr_iterate (grub_elf_t elf, + int NESTED_FUNC_ATTR (*hook) (grub_elf_t, Elf32_Phdr *, void *), + void *hook_arg); +grub_err_t +grub_elf64_phdr_iterate (grub_elf_t elf, + int NESTED_FUNC_ATTR (*hook) (grub_elf_t, Elf64_Phdr *, void *), + void *hook_arg); #endif /* ! GRUB_ELFLOAD_HEADER */ diff --git a/include/grub/err.h b/include/grub/err.h index e44705389..d35bba474 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -50,7 +50,7 @@ typedef enum GRUB_ERR_BAD_FONT, GRUB_ERR_NOT_IMPLEMENTED_YET, GRUB_ERR_SYMLINK_LOOP, - GRUB_ERR_BAD_GZIP_DATA, + GRUB_ERR_BAD_COMPRESSED_DATA, GRUB_ERR_MENU, GRUB_ERR_TIMEOUT, GRUB_ERR_IO, diff --git a/include/grub/extcmd.h b/include/grub/extcmd.h index 03eaba8f8..773e47854 100644 --- a/include/grub/extcmd.h +++ b/include/grub/extcmd.h @@ -21,10 +21,12 @@ #include #include +#include struct grub_extcmd; +struct grub_extcmd_context; -typedef grub_err_t (*grub_extcmd_func_t) (struct grub_extcmd *cmd, +typedef grub_err_t (*grub_extcmd_func_t) (struct grub_extcmd_context *ctxt, int argc, char **args); /* The argcmd description. */ @@ -38,11 +40,21 @@ struct grub_extcmd const struct grub_arg_option *options; void *data; - - struct grub_arg_list *state; }; typedef struct grub_extcmd *grub_extcmd_t; +/* Command context for each instance of execution. */ +struct grub_extcmd_context +{ + struct grub_extcmd *extcmd; + + struct grub_arg_list *state; + + /* Script parameter, if any. */ + struct grub_script *script; +}; +typedef struct grub_extcmd_context *grub_extcmd_context_t; + grub_extcmd_t grub_register_extcmd (const char *name, grub_extcmd_func_t func, unsigned flags, @@ -50,6 +62,18 @@ grub_extcmd_t grub_register_extcmd (const char *name, const char *description, const struct grub_arg_option *parser); +grub_extcmd_t grub_register_extcmd_prio (const char *name, + grub_extcmd_func_t func, + unsigned flags, + const char *summary, + const char *description, + const struct grub_arg_option *parser, + int prio); + void grub_unregister_extcmd (grub_extcmd_t cmd); +grub_err_t +grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, + struct grub_script *script); + #endif /* ! GRUB_EXTCMD_HEADER */ diff --git a/include/grub/file.h b/include/grub/file.h index 2aacf936f..72cd45468 100644 --- a/include/grub/file.h +++ b/include/grub/file.h @@ -39,6 +39,9 @@ struct grub_file /* The file size. */ grub_off_t size; + /* If file is not easly seekable. Should be set by underlying layer. */ + int not_easly_seekable; + /* Filesystem-specific data. */ void *data; @@ -48,6 +51,51 @@ struct grub_file }; typedef struct grub_file *grub_file_t; +/* Filters with lower ID are executed first. */ +typedef enum grub_file_filter_id + { + GRUB_FILE_FILTER_GZIO, + GRUB_FILE_FILTER_XZIO, + GRUB_FILE_FILTER_MAX, + GRUB_FILE_FILTER_COMPRESSION_FIRST = GRUB_FILE_FILTER_GZIO, + GRUB_FILE_FILTER_COMPRESSION_LAST = GRUB_FILE_FILTER_XZIO, + } grub_file_filter_id_t; + +typedef grub_file_t (*grub_file_filter_t) (grub_file_t in); + +extern grub_file_filter_t EXPORT_VAR(grub_file_filters_all)[GRUB_FILE_FILTER_MAX]; +extern grub_file_filter_t EXPORT_VAR(grub_file_filters_enabled)[GRUB_FILE_FILTER_MAX]; + +static inline void +grub_file_filter_register (grub_file_filter_id_t id, grub_file_filter_t filter) +{ + grub_file_filters_all[id] = filter; + grub_file_filters_enabled[id] = filter; +}; + +static inline void +grub_file_filter_unregister (grub_file_filter_id_t id) +{ + grub_file_filters_all[id] = 0; + grub_file_filters_enabled[id] = 0; +}; + +static inline void +grub_file_filter_disable (grub_file_filter_id_t id) +{ + grub_file_filters_enabled[id] = 0; +}; + +static inline void +grub_file_filter_disable_compression (void) +{ + grub_file_filter_id_t id; + + for (id = GRUB_FILE_FILTER_COMPRESSION_FIRST; + id <= GRUB_FILE_FILTER_COMPRESSION_LAST; id++) + grub_file_filters_enabled[id] = 0; +}; + /* Get a device name from NAME. */ char *EXPORT_FUNC(grub_file_get_device_name) (const char *name); @@ -57,6 +105,9 @@ grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf, grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset); grub_err_t EXPORT_FUNC(grub_file_close) (grub_file_t file); +/* Return value of grub_file_size() in case file size is unknown. */ +#define GRUB_FILE_SIZE_UNKNOWN 0xffffffffffffffffULL + static inline grub_off_t grub_file_size (const grub_file_t file) { @@ -69,4 +120,10 @@ grub_file_tell (const grub_file_t file) return file->offset; } +static inline int +grub_file_seekable (const grub_file_t file) +{ + return !file->not_easly_seekable; +} + #endif /* ! GRUB_FILE_HEADER */ diff --git a/include/grub/gzio.h b/include/grub/gzio.h deleted file mode 100644 index cd7f39793..000000000 --- a/include/grub/gzio.h +++ /dev/null @@ -1,28 +0,0 @@ -/* gzio.h - prototypes for gzio */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2005,2007 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_GZIO_H -#define GRUB_GZIO_H 1 - -#include - -grub_file_t grub_gzio_open (grub_file_t io, int transparent); -grub_file_t grub_gzfile_open (const char *name, int transparent); - -#endif /* ! GRUB_GZIO_H */ diff --git a/include/grub/i386/bsd.h b/include/grub/i386/bsd.h index 4d55f04fb..53008cdaf 100644 --- a/include/grub/i386/bsd.h +++ b/include/grub/i386/bsd.h @@ -20,6 +20,8 @@ #define GRUB_BSD_CPU_HEADER 1 #include +#include + #include #include #include @@ -27,7 +29,6 @@ #include #include - enum bsd_kernel_types { KERNEL_TYPE_NONE, @@ -65,35 +66,55 @@ struct grub_freebsd_bootinfo grub_uint32_t tags; } __attribute__ ((packed)); -struct grub_openbsd_bios_mmap +struct freebsd_tag_header { - grub_uint64_t addr; - grub_uint64_t len; -#define OPENBSD_MMAP_AVAILABLE 1 -#define OPENBSD_MMAP_RESERVED 2 -#define OPENBSD_MMAP_ACPI 3 -#define OPENBSD_MMAP_NVS 4 grub_uint32_t type; + grub_uint32_t len; }; -void grub_unix_real_boot (grub_addr_t entry, ...) - __attribute__ ((cdecl,noreturn)); -grub_err_t grub_freebsd_load_elfmodule32 (grub_file_t file, int argc, +grub_err_t grub_freebsd_load_elfmodule32 (struct grub_relocator *relocator, + grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end); -grub_err_t grub_freebsd_load_elfmodule_obj64 (grub_file_t file, int argc, +grub_err_t grub_freebsd_load_elfmodule_obj64 (struct grub_relocator *relocator, + grub_file_t file, int argc, char *argv[], grub_addr_t *kern_end); -grub_err_t grub_freebsd_load_elf_meta32 (grub_file_t file, +grub_err_t grub_freebsd_load_elf_meta32 (struct grub_relocator *relocator, + grub_file_t file, grub_addr_t *kern_end); -grub_err_t grub_freebsd_load_elf_meta64 (grub_file_t file, +grub_err_t grub_freebsd_load_elf_meta64 (struct grub_relocator *relocator, + grub_file_t file, grub_addr_t *kern_end); -grub_err_t grub_freebsd_add_meta (grub_uint32_t type, void *data, - grub_uint32_t len); +grub_err_t grub_netbsd_load_elf_meta32 (struct grub_relocator *relocator, + grub_file_t file, + grub_addr_t *kern_end); +grub_err_t grub_netbsd_load_elf_meta64 (struct grub_relocator *relocator, + grub_file_t file, + grub_addr_t *kern_end); + +grub_err_t grub_bsd_add_meta (grub_uint32_t type, + void *data, grub_uint32_t len); grub_err_t grub_freebsd_add_meta_module (char *filename, char *type, int argc, char **argv, grub_addr_t addr, grub_uint32_t size); +struct grub_openbsd_ramdisk_descriptor +{ + grub_size_t max_size; + grub_uint8_t *target; + grub_uint32_t *size; +}; + +grub_err_t grub_openbsd_find_ramdisk32 (grub_file_t file, + grub_addr_t kern_start, + void *kern_chunk_src, + struct grub_openbsd_ramdisk_descriptor *desc); +grub_err_t grub_openbsd_find_ramdisk64 (grub_file_t file, + grub_addr_t kern_start, + void *kern_chunk_src, + struct grub_openbsd_ramdisk_descriptor *desc); + extern grub_uint8_t grub_bsd64_trampoline_start, grub_bsd64_trampoline_end; extern grub_uint32_t grub_bsd64_trampoline_selfjump; extern grub_uint32_t grub_bsd64_trampoline_gdt; diff --git a/include/grub/i386/coreboot/loader.h b/include/grub/i386/coreboot/loader.h deleted file mode 100644 index d3f36bba5..000000000 --- a/include/grub/i386/coreboot/loader.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/i386/coreboot/init.h b/include/grub/i386/floppy.h similarity index 60% rename from include/grub/i386/coreboot/init.h rename to include/grub/i386/floppy.h index e67007414..0e3690549 100644 --- a/include/grub/i386/coreboot/init.h +++ b/include/grub/i386/floppy.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2007 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,13 +16,21 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_INIT_I386_LINUXBIOS_HEADER -#define GRUB_INIT_I386_LINUXBIOS_HEADER 1 +#ifndef GRUB_FLOPPY_CPU_HEADER +#define GRUB_FLOPPY_CPU_HEADER 1 -#include -#include +#define GRUB_FLOPPY_REG_DIGITAL_OUTPUT 0x3f2 -void EXPORT_FUNC(grub_stop) (void) __attribute__ ((noreturn)); -void EXPORT_FUNC(grub_stop_floppy) (void); +#ifndef ASM_FILE +#include + +/* Stop the floppy drive from spinning, so that other software is + jumped to with a known state. */ +static inline void +grub_stop_floppy (void) +{ + grub_outb (0, GRUB_FLOPPY_REG_DIGITAL_OUTPUT); +} +#endif #endif diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h index f02a722d6..63f99db62 100644 --- a/include/grub/i386/linux.h +++ b/include/grub/i386/linux.h @@ -124,7 +124,7 @@ struct linux_kernel_header grub_uint32_t bootsect_kludge; /* obsolete */ grub_uint16_t heap_end_ptr; /* Free memory after setup end */ grub_uint16_t pad1; /* Unused */ - char *cmd_line_ptr; /* Points to the kernel command line */ + grub_uint32_t cmd_line_ptr; /* Points to the kernel command line */ grub_uint32_t initrd_addr_max; /* Highest address for initrd */ } __attribute__ ((packed)); diff --git a/include/grub/i386/loader.h b/include/grub/i386/loader.h deleted file mode 100644 index 05954b6db..000000000 --- a/include/grub/i386/loader.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,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 . - */ - -#ifndef GRUB_LOADER_CPU_HEADER -#define GRUB_LOADER_CPU_HEADER 1 - -#include -#include -#include - -extern grub_addr_t EXPORT_VAR(grub_os_area_addr); -extern grub_size_t EXPORT_VAR(grub_os_area_size); - -#ifdef GRUB_MACHINE_PCBIOS -extern grub_uint32_t EXPORT_VAR(grub_linux_prot_size); -extern char *EXPORT_VAR(grub_linux_tmp_addr); -extern char *EXPORT_VAR(grub_linux_real_addr); -extern grub_int32_t EXPORT_VAR(grub_linux_is_bzimage); -grub_err_t EXPORT_FUNC(grub_linux16_real_boot) (void); -#endif - -#endif /* ! GRUB_LOADER_CPU_HEADER */ diff --git a/include/grub/i386/memory.h b/include/grub/i386/memory.h index 466947cc6..4f9a3c916 100644 --- a/include/grub/i386/memory.h +++ b/include/grub/i386/memory.h @@ -22,9 +22,34 @@ /* The flag for protected mode. */ #define GRUB_MEMORY_CPU_CR0_PE_ON 0x1 -#define GRUB_MEMORY_CPU_CR4_PAE_ON 0x00000040 +#define GRUB_MEMORY_CPU_CR4_PAE_ON 0x00000020 +#define GRUB_MEMORY_CPU_CR4_PSE_ON 0x00000010 #define GRUB_MEMORY_CPU_CR0_PAGING_ON 0x80000000 #define GRUB_MEMORY_CPU_AMD64_MSR 0xc0000080 #define GRUB_MEMORY_CPU_AMD64_MSR_ON 0x00000100 +#ifndef ASM_FILE + +typedef grub_addr_t grub_phys_addr_t; + +static inline grub_phys_addr_t +grub_vtop (void *a) +{ + return (grub_phys_addr_t) a; +} + +static inline void * +grub_map_memory (grub_phys_addr_t a, grub_size_t size __attribute__ ((unused))) +{ + return (void *) a; +} + +static inline void +grub_unmap_memory (void *a __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} + +#endif + #endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/include/grub/i386/multiboot.h b/include/grub/i386/multiboot.h index 1c711fad4..a1b94883d 100644 --- a/include/grub/i386/multiboot.h +++ b/include/grub/i386/multiboot.h @@ -19,11 +19,6 @@ #ifndef GRUB_MULTIBOOT_CPU_HEADER #define GRUB_MULTIBOOT_CPU_HEADER 1 -extern grub_uint32_t grub_multiboot_payload_eip; -extern char *grub_multiboot_payload_orig; -extern grub_addr_t grub_multiboot_payload_dest; -extern grub_size_t grub_multiboot_payload_size; - #define MULTIBOOT_INITIAL_STATE { .eax = MULTIBOOT_BOOTLOADER_MAGIC, \ .ecx = 0, \ .edx = 0, \ diff --git a/include/grub/i386/multiboot/init.h b/include/grub/i386/multiboot/init.h deleted file mode 100644 index fd935c3a2..000000000 --- a/include/grub/i386/multiboot/init.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/i386/multiboot/loader.h b/include/grub/i386/multiboot/loader.h deleted file mode 100644 index 1c725be19..000000000 --- a/include/grub/i386/multiboot/loader.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/i386/netbsd_bootinfo.h b/include/grub/i386/netbsd_bootinfo.h index 776ecf3b0..fd429a251 100644 --- a/include/grub/i386/netbsd_bootinfo.h +++ b/include/grub/i386/netbsd_bootinfo.h @@ -49,64 +49,90 @@ #include - #define NETBSD_BTINFO_BOOTPATH 0 #define NETBSD_BTINFO_ROOTDEVICE 1 -#define NETBSD_BTINFO_BOOTDISK 3 +#define NETBSD_BTINFO_CONSOLE 6 +#define NETBSD_BTINFO_SYMTAB 8 #define NETBSD_BTINFO_MEMMAP 9 +#define NETBSD_BTINFO_MODULES 11 +#define NETBSD_BTINFO_FRAMEBUF 12 + +struct grub_netbsd_bootinfo +{ + grub_uint32_t bi_count; + grub_uint32_t bi_data[0]; +}; struct grub_netbsd_btinfo_common { - int len; - int type; -}; - -struct grub_netbsd_btinfo_mmap_header -{ - struct grub_netbsd_btinfo_common common; - grub_uint32_t count; -}; - -struct grub_netbsd_btinfo_mmap_entry -{ - grub_uint64_t addr; - grub_uint64_t len; -#define NETBSD_MMAP_AVAILABLE 1 -#define NETBSD_MMAP_RESERVED 2 -#define NETBSD_MMAP_ACPI 3 -#define NETBSD_MMAP_NVS 4 + grub_uint32_t len; grub_uint32_t type; }; -struct grub_netbsd_btinfo_bootpath -{ - struct grub_netbsd_btinfo_common common; - char bootpath[80]; -}; - -struct grub_netbsd_btinfo_rootdevice -{ - struct grub_netbsd_btinfo_common common; - char devname[16]; -}; +#define GRUB_NETBSD_MAX_BOOTPATH_LEN 80 struct grub_netbsd_btinfo_bootdisk { - struct grub_netbsd_btinfo_common common; - int labelsector; /* label valid if != -1 */ + grub_uint32_t labelsector; /* label valid if != 0xffffffff */ struct { grub_uint16_t type, checksum; char packname[16]; } label; - int biosdev; - int partition; + grub_uint32_t biosdev; + grub_uint32_t partition; }; -struct grub_netbsd_bootinfo +struct grub_netbsd_btinfo_symtab { - grub_uint32_t bi_count; - void *bi_data[1]; + grub_uint32_t nsyms; + grub_uint32_t ssyms; + grub_uint32_t esyms; }; + +struct grub_netbsd_btinfo_serial +{ + char devname[16]; + grub_uint32_t addr; + grub_uint32_t speed; +}; + +struct grub_netbsd_btinfo_modules +{ + grub_uint32_t num; + grub_uint32_t last_addr; + struct grub_netbsd_btinfo_module + { + char name[80]; +#define GRUB_NETBSD_MODULE_RAW 0 +#define GRUB_NETBSD_MODULE_ELF 1 + grub_uint32_t type; + grub_uint32_t size; + grub_uint32_t addr; + } mods[0]; +}; + +struct grub_netbsd_btinfo_framebuf +{ + grub_uint64_t fbaddr; + grub_uint32_t flags; + grub_uint32_t width; + grub_uint32_t height; + grub_uint16_t pitch; + grub_uint8_t bpp; + + grub_uint8_t red_mask_size; + grub_uint8_t green_mask_size; + grub_uint8_t blue_mask_size; + + grub_uint8_t red_field_pos; + grub_uint8_t green_field_pos; + grub_uint8_t blue_field_pos; + + grub_uint8_t reserved[16]; +}; + +#define GRUB_NETBSD_MAX_ROOTDEVICE_LEN 16 + #endif diff --git a/include/grub/i386/openbsd_bootarg.h b/include/grub/i386/openbsd_bootarg.h index ccbe1ca12..935dfc0c8 100644 --- a/include/grub/i386/openbsd_bootarg.h +++ b/include/grub/i386/openbsd_bootarg.h @@ -61,12 +61,22 @@ #define OPENBSD_BOOTARG_END -1 #define OPENBSD_BOOTARG_MMAP 0 +#define OPENBSD_BOOTARG_CONSOLE 5 struct grub_openbsd_bootargs { - int ba_type; - int ba_size; - struct grub_openbsd_bootargs *ba_next; + grub_uint32_t ba_type; + grub_uint32_t ba_size; + grub_uint32_t ba_next; } __attribute__ ((packed)); +struct grub_openbsd_bootarg_console +{ + grub_uint32_t device; + grub_uint32_t speed; +}; + +#define GRUB_OPENBSD_COM_MAJOR 8 +#define GRUB_OPENBSD_VGA_MAJOR 12 + #endif diff --git a/include/grub/i386/pc/biosdisk.h b/include/grub/i386/pc/biosdisk.h index b87e0e433..f8a9b463f 100644 --- a/include/grub/i386/pc/biosdisk.h +++ b/include/grub/i386/pc/biosdisk.h @@ -106,21 +106,4 @@ struct grub_biosdisk_dap grub_uint64_t block; } __attribute__ ((packed)); -int EXPORT_FUNC(grub_biosdisk_rw_int13_extensions) (int ah, int drive, void *dap); -int EXPORT_FUNC(grub_biosdisk_rw_standard) (int ah, int drive, int coff, int hoff, - int soff, int nsec, int segment); -int EXPORT_FUNC(grub_biosdisk_check_int13_extensions) (int drive); -int EXPORT_FUNC(grub_biosdisk_get_diskinfo_int13_extensions) (int drive, - void *drp); -int EXPORT_FUNC(grub_biosdisk_get_cdinfo_int13_extensions) (int drive, - void *cdrp); -int EXPORT_FUNC(grub_biosdisk_get_diskinfo_standard) (int drive, - unsigned long *cylinders, - unsigned long *heads, - unsigned long *sectors); -int EXPORT_FUNC(grub_biosdisk_get_num_floppies) (void); - -void grub_biosdisk_init (void); -void grub_biosdisk_fini (void); - #endif /* ! GRUB_BIOSDISK_MACHINE_HEADER */ diff --git a/include/grub/i386/pc/init.h b/include/grub/i386/pc/init.h index 30130d189..4005a1772 100644 --- a/include/grub/i386/pc/init.h +++ b/include/grub/i386/pc/init.h @@ -22,23 +22,9 @@ #include #include #include - -/* Get the memory size in KB. If EXTENDED is zero, return conventional - memory, otherwise return extended memory. */ -grub_uint16_t grub_get_memsize (int extended); - -/* Get a packed EISA memory map. Lower 16 bits are between 1MB and 16MB - in 1KB parts, and upper 16 bits are above 16MB in 64KB parts. */ -grub_uint32_t grub_get_eisa_mmap (void); - -/* Get a memory map entry. Return next continuation value. Zero means - the end. */ -grub_uint32_t grub_get_mmap_entry (struct grub_machine_mmap_entry *entry, - grub_uint32_t cont); +#include /* Turn on/off Gate A20. */ void grub_gate_a20 (int on); -void EXPORT_FUNC(grub_stop_floppy) (void); - #endif /* ! GRUB_INIT_MACHINE_HEADER */ diff --git a/include/grub/i386/pc/int.h b/include/grub/i386/pc/int.h new file mode 100644 index 000000000..e1c463925 --- /dev/null +++ b/include/grub/i386/pc/int.h @@ -0,0 +1,52 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_INTERRUPT_MACHINE_HEADER +#define GRUB_INTERRUPT_MACHINE_HEADER 1 + +#include + +struct grub_bios_int_registers +{ + grub_uint32_t eax; + grub_uint16_t es; + grub_uint16_t ds; + grub_uint16_t flags; + grub_uint16_t dummy; + grub_uint32_t ebx; + grub_uint32_t ecx; + grub_uint32_t edi; + grub_uint32_t esi; + grub_uint32_t edx; +}; + +#define GRUB_CPU_INT_FLAGS_CARRY 0x1 +#define GRUB_CPU_INT_FLAGS_PARITY 0x4 +#define GRUB_CPU_INT_FLAGS_ADJUST 0x10 +#define GRUB_CPU_INT_FLAGS_ZERO 0x40 +#define GRUB_CPU_INT_FLAGS_SIGN 0x80 +#define GRUB_CPU_INT_FLAGS_TRAP 0x100 +#define GRUB_CPU_INT_FLAGS_INTERRUPT 0x200 +#define GRUB_CPU_INT_FLAGS_DIRECTION 0x400 +#define GRUB_CPU_INT_FLAGS_OVERFLOW 0x800 +#define GRUB_CPU_INT_FLAGS_DEFAULT GRUB_CPU_INT_FLAGS_INTERRUPT + +void EXPORT_FUNC (grub_bios_interrupt) (grub_uint8_t intno, + struct grub_bios_int_registers *regs); + +#endif diff --git a/include/grub/i386/pc/loader.h b/include/grub/i386/pc/loader.h index 3e031413b..bfbcaac5a 100644 --- a/include/grub/i386/pc/loader.h +++ b/include/grub/i386/pc/loader.h @@ -20,7 +20,6 @@ #define GRUB_LOADER_MACHINE_HEADER 1 #include -#include /* This is an asm part of the chainloader. */ void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn)); diff --git a/include/grub/i386/pc/pxe.h b/include/grub/i386/pc/pxe.h index 39f356c83..62ece21b0 100644 --- a/include/grub/i386/pc/pxe.h +++ b/include/grub/i386/pc/pxe.h @@ -168,6 +168,8 @@ #ifndef ASM_FILE +#define GRUB_PXE_SIGNATURE "PXENV+" + struct grub_pxenv { grub_uint8_t signature[6]; /* 'PXENV+'. */ @@ -190,6 +192,19 @@ struct grub_pxenv grub_uint32_t pxe_ptr; /* SEG:OFF to !PXE struct. */ } __attribute__ ((packed)); +struct grub_pxe_bangpxe +{ + grub_uint8_t signature[4]; +#define GRUB_PXE_BANGPXE_SIGNATURE "!PXE" + grub_uint8_t length; + grub_uint8_t chksum; + grub_uint8_t rev; + grub_uint8_t reserved; + grub_uint32_t undiromid; + grub_uint32_t baseromid; + grub_uint32_t rm_entry; +} __attribute__ ((packed)); + struct grub_pxenv_get_cached_info { grub_uint16_t status; @@ -302,10 +317,9 @@ struct grub_pxenv_unload_stack grub_uint8_t reserved[10]; } __attribute__ ((packed)); -struct grub_pxenv * EXPORT_FUNC(grub_pxe_scan) (void); -int EXPORT_FUNC(grub_pxe_call) (int func, void * data); +int EXPORT_FUNC(grub_pxe_call) (int func, void * data, grub_uint32_t pxe_rm_entry); -extern struct grub_pxenv *grub_pxe_pxenv; +extern struct grub_pxe_bangpxe *grub_pxe_pxenv; void grub_pxe_unload (void); diff --git a/include/grub/i386/pc/vbe.h b/include/grub/i386/pc/vbe.h index abf246fa1..9b05c2299 100644 --- a/include/grub/i386/pc/vbe.h +++ b/include/grub/i386/pc/vbe.h @@ -169,56 +169,40 @@ struct grub_vbe_palette_data grub_uint8_t alignment; } __attribute__ ((packed)); -/* Prototypes for kernel real mode thunks. */ - +/* Prototypes for helper functions. */ /* Call VESA BIOS 0x4f00 to get VBE Controller Information, return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_get_controller_info) (struct grub_vbe_info_block *controller_info); - +grub_vbe_status_t +grub_vbe_bios_get_controller_info (struct grub_vbe_info_block *controller_info); /* Call VESA BIOS 0x4f01 to get VBE Mode Information, return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_get_mode_info) (grub_uint32_t mode, - struct grub_vbe_mode_info_block *mode_info); +grub_vbe_status_t +grub_vbe_bios_get_mode_info (grub_uint32_t mode, + struct grub_vbe_mode_info_block *mode_info); +/* Call VESA BIOS 0x4f03 to return current VBE Mode, return status. */ +grub_vbe_status_t +grub_vbe_bios_get_mode (grub_uint32_t *mode); +/* Call VESA BIOS 0x4f05 to set memory window, return status. */ +grub_vbe_status_t +grub_vbe_bios_set_memory_window (grub_uint32_t window, grub_uint32_t position); +/* Call VESA BIOS 0x4f05 to return memory window, return status. */ +grub_vbe_status_t +grub_vbe_bios_get_memory_window (grub_uint32_t window, + grub_uint32_t *position); +/* Call VESA BIOS 0x4f06 to set scanline length (in bytes), return status. */ +grub_vbe_status_t +grub_vbe_bios_set_scanline_length (grub_uint32_t length); +/* Call VESA BIOS 0x4f06 to return scanline length (in bytes), return status. */ +grub_vbe_status_t +grub_vbe_bios_get_scanline_length (grub_uint32_t *length); +/* Call VESA BIOS 0x4f07 to get display start, return status. */ +grub_vbe_status_t +grub_vbe_bios_get_display_start (grub_uint32_t *x, + grub_uint32_t *y); -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_getset_dac_palette_width) (int set, int *width); +grub_vbe_status_t grub_vbe_bios_getset_dac_palette_width (int set, int *width); #define grub_vbe_bios_get_dac_palette_width(width) grub_vbe_bios_getset_dac_palette_width(0, (width)) #define grub_vbe_bios_set_dac_palette_width(width) grub_vbe_bios_getset_dac_palette_width(1, (width)) -/* Call VESA BIOS 0x4f02 to set video mode, return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_set_mode) (grub_uint32_t mode, - struct grub_vbe_crtc_info_block *crtc_info); - -/* Call VESA BIOS 0x4f03 to return current VBE Mode, return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_get_mode) (grub_uint32_t *mode); - -/* Call VESA BIOS 0x4f05 to set memory window, return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_set_memory_window) (grub_uint32_t window, - grub_uint32_t position); - -/* Call VESA BIOS 0x4f05 to return memory window, return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_get_memory_window) (grub_uint32_t window, - grub_uint32_t *position); - -/* Call VESA BIOS 0x4f06 to set scanline length (in bytes), return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_set_scanline_length) (grub_uint32_t length); - -/* Call VESA BIOS 0x4f06 to return scanline length (in bytes), return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_get_scanline_length) (grub_uint32_t *length); - -/* Call VESA BIOS 0x4f07 to set display start, return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_set_display_start) (grub_uint32_t x, - grub_uint32_t y); - -/* Call VESA BIOS 0x4f07 to get display start, return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_get_display_start) (grub_uint32_t *x, - grub_uint32_t *y); - -/* Call VESA BIOS 0x4f09 to set palette data, return status. */ -grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_set_palette_data) (grub_uint32_t color_count, - grub_uint32_t start_index, - struct grub_vbe_palette_data *palette_data); - -/* Prototypes for helper functions. */ - grub_err_t grub_vbe_probe (struct grub_vbe_info_block *info_block); grub_err_t grub_vbe_set_video_mode (grub_uint32_t mode, struct grub_vbe_mode_info_block *mode_info); diff --git a/include/grub/i386/pc/vga.h b/include/grub/i386/pc/vga.h index 2724f6401..ecc169022 100644 --- a/include/grub/i386/pc/vga.h +++ b/include/grub/i386/pc/vga.h @@ -25,7 +25,4 @@ /* The VGA (at the beginning of upper memory). */ #define GRUB_MEMORY_MACHINE_VGA_ADDR GRUB_MEMORY_MACHINE_UPPER -/* Set the video mode to MODE and return the previous mode. */ -unsigned char EXPORT_FUNC(grub_vga_set_mode) (unsigned char mode); - #endif /* ! GRUB_VGA_MACHINE_HEADER */ diff --git a/include/grub/i386/qemu/init.h b/include/grub/i386/qemu/init.h deleted file mode 100644 index fd935c3a2..000000000 --- a/include/grub/i386/qemu/init.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/i386/qemu/loader.h b/include/grub/i386/qemu/loader.h deleted file mode 100644 index d3f36bba5..000000000 --- a/include/grub/i386/qemu/loader.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/grub/i386/relocator.h b/include/grub/i386/relocator.h index ef7fe23aa..6ff5c6631 100644 --- a/include/grub/i386/relocator.h +++ b/include/grub/i386/relocator.h @@ -21,21 +21,54 @@ #include #include +#include struct grub_relocator32_state { grub_uint32_t esp; + grub_uint32_t ebp; grub_uint32_t eax; grub_uint32_t ebx; grub_uint32_t ecx; grub_uint32_t edx; grub_uint32_t eip; + grub_uint32_t esi; + grub_uint32_t edi; }; -void *grub_relocator32_alloc (grub_size_t size); -grub_err_t grub_relocator32_boot (void *relocator, grub_uint32_t dest, +struct grub_relocator16_state +{ + grub_uint16_t cs; + grub_uint16_t ds; + grub_uint16_t es; + grub_uint16_t fs; + grub_uint16_t gs; + grub_uint16_t ss; + grub_uint16_t sp; + grub_uint16_t ip; + grub_uint32_t edx; +}; + +struct grub_relocator64_state +{ + grub_uint64_t rsp; + grub_uint64_t rax; + grub_uint64_t rbx; + grub_uint64_t rcx; + grub_uint64_t rdx; + grub_uint64_t rip; + grub_uint64_t rsi; + grub_addr_t cr3; +}; + +grub_err_t grub_relocator16_boot (struct grub_relocator *rel, + struct grub_relocator16_state state); + +grub_err_t grub_relocator32_boot (struct grub_relocator *rel, struct grub_relocator32_state state); -void *grub_relocator32_realloc (void *relocator, grub_size_t size); -void grub_relocator32_free (void *relocator); + +grub_err_t grub_relocator64_boot (struct grub_relocator *rel, + struct grub_relocator64_state state, + grub_addr_t min_addr, grub_addr_t max_addr); #endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/include/grub/i386/xnu.h b/include/grub/i386/xnu.h index 2fa2639c1..386c8b9e0 100644 --- a/include/grub/i386/xnu.h +++ b/include/grub/i386/xnu.h @@ -115,5 +115,4 @@ extern grub_uint32_t grub_xnu_arg1; extern char grub_xnu_cmdline[1024]; grub_err_t grub_xnu_boot (void); grub_err_t grub_cpu_xnu_fill_devicetree (void); -extern grub_uint32_t grub_xnu_heap_will_be_at; #endif diff --git a/include/grub/kernel.h b/include/grub/kernel.h index fed875db1..2ecc73df4 100644 --- a/include/grub/kernel.h +++ b/include/grub/kernel.h @@ -26,8 +26,7 @@ enum { OBJ_TYPE_ELF, OBJ_TYPE_MEMDISK, - OBJ_TYPE_CONFIG, - OBJ_TYPE_FONT + OBJ_TYPE_CONFIG }; /* The module header. */ diff --git a/include/grub/lib/arg.h b/include/grub/lib/arg.h index e6af60cf9..3bab27781 100644 --- a/include/grub/lib/arg.h +++ b/include/grub/lib/arg.h @@ -38,6 +38,8 @@ typedef enum grub_arg_type grub_arg_type_t; /* Flags for the option field op grub_arg_option. */ #define GRUB_ARG_OPTION_OPTIONAL (1 << 1) +/* Flags for an option that can appear multiple times. */ +#define GRUB_ARG_OPTION_REPEATABLE (1 << 2) enum grub_key_type { @@ -59,7 +61,10 @@ struct grub_arg_option struct grub_arg_list { int set; - char *arg; + union { + char *arg; + char **args; + }; }; struct grub_extcmd; @@ -68,5 +73,7 @@ int grub_arg_parse (struct grub_extcmd *cmd, int argc, char **argv, struct grub_arg_list *usr, char ***args, int *argnum); void grub_arg_show_help (struct grub_extcmd *cmd); +struct grub_arg_list* grub_arg_list_alloc (struct grub_extcmd *cmd, + int argc, char *argv[]); #endif /* ! GRUB_ARG_HEADER */ diff --git a/include/grub/menu.h b/include/grub/menu.h index e5e5fb110..608253863 100644 --- a/include/grub/menu.h +++ b/include/grub/menu.h @@ -47,6 +47,10 @@ struct grub_menu_entry /* The sourcecode of the menu entry, used by the editor. */ const char *sourcecode; + /* Parameters to be passed to menu definition. */ + int argc; + char **args; + int hotkey; /* The next element. */ @@ -96,4 +100,7 @@ void grub_menu_execute_with_fallback (grub_menu_t menu, void grub_menu_entry_run (grub_menu_entry_t entry); int grub_menu_get_default_entry_index (grub_menu_t menu); +void grub_menu_init (void); +void grub_menu_fini (void); + #endif /* GRUB_MENU_HEADER */ diff --git a/include/grub/mips/memory.h b/include/grub/mips/memory.h new file mode 100644 index 000000000..e51bcc1f2 --- /dev/null +++ b/include/grub/mips/memory.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/mips/multiboot.h b/include/grub/mips/multiboot.h index a27229efe..4aebf29e7 100644 --- a/include/grub/mips/multiboot.h +++ b/include/grub/mips/multiboot.h @@ -19,11 +19,6 @@ #ifndef GRUB_MULTIBOOT_CPU_HEADER #define GRUB_MULTIBOOT_CPU_HEADER 1 -extern grub_uint32_t grub_multiboot_payload_eip; -extern char *grub_multiboot_payload_orig; -extern grub_addr_t grub_multiboot_payload_dest; -extern grub_size_t grub_multiboot_payload_size; - #define MULTIBOOT_INITIAL_STATE { .gpr[4] = MULTIBOOT_BOOTLOADER_MAGIC, \ .jumpreg = 1 } #define MULTIBOOT_ENTRY_REGISTER gpr[1] diff --git a/include/grub/mips/relocator.h b/include/grub/mips/relocator.h index 838ef832f..67b0a4c43 100644 --- a/include/grub/mips/relocator.h +++ b/include/grub/mips/relocator.h @@ -21,6 +21,7 @@ #include #include +#include struct grub_relocator32_state { @@ -30,10 +31,8 @@ struct grub_relocator32_state int jumpreg; }; -void *grub_relocator32_alloc (grub_size_t size); -grub_err_t grub_relocator32_boot (void *relocator, grub_uint32_t dest, - struct grub_relocator32_state state); -void *grub_relocator32_realloc (void *relocator, grub_size_t size); -void grub_relocator32_free (void *relocator); +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state); #endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/include/grub/mips/yeeloong/kernel.h b/include/grub/mips/yeeloong/kernel.h index c08405e83..15cf9f9fd 100644 --- a/include/grub/mips/yeeloong/kernel.h +++ b/include/grub/mips/yeeloong/kernel.h @@ -23,8 +23,8 @@ #ifndef ASM_FILE -void EXPORT_FUNC (grub_reboot) (void); -void EXPORT_FUNC (grub_halt) (void); +void EXPORT_FUNC (grub_reboot) (void) __attribute__ ((noreturn)); +void EXPORT_FUNC (grub_halt) (void) __attribute__ ((noreturn)); #endif diff --git a/include/grub/mips/yeeloong/loader.h b/include/grub/mips/yeeloong/loader.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/include/grub/mips/yeeloong/memory.h b/include/grub/mips/yeeloong/memory.h index 922db2404..e7e995283 100644 --- a/include/grub/mips/yeeloong/memory.h +++ b/include/grub/mips/yeeloong/memory.h @@ -31,7 +31,6 @@ #define GRUB_ARCH_LOWMEMMAXSIZE 0x10000000 #define GRUB_ARCH_HIGHMEMPSTART 0x10000000 - #define GRUB_MACHINE_MEMORY_AVAILABLE 1 #define GRUB_MACHINE_MEMORY_MAX_TYPE 1 /* This one is special: it's used internally but is never reported @@ -40,6 +39,27 @@ #define GRUB_MACHINE_MEMORY_RESERVED GRUB_MACHINE_MEMORY_HOLE #ifndef ASM_FILE + +typedef grub_addr_t grub_phys_addr_t; + +static inline grub_phys_addr_t +grub_vtop (void *a) +{ + return ((grub_phys_addr_t) a) & 0x1fffffff; +} + +static inline void * +grub_map_memory (grub_phys_addr_t a, grub_size_t size __attribute__ ((unused))) +{ + return (void *) (a | 0x80000000); +} + +static inline void +grub_unmap_memory (void *a __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} + grub_err_t EXPORT_FUNC (grub_machine_mmap_iterate) (int NESTED_FUNC_ATTR (*hook) (grub_uint64_t, grub_uint64_t, grub_uint32_t)); diff --git a/include/grub/misc.h b/include/grub/misc.h index 8bf8c82b4..774dc5843 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -43,6 +43,8 @@ #define ALIGN_UP(addr, align) \ ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1)) +#define ALIGN_DOWN(addr, align) \ + ((addr) & ~((typeof (addr)) align - 1)) #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } @@ -319,9 +321,9 @@ void EXPORT_FUNC (grub_reboot) (void) __attribute__ ((noreturn)); #ifdef GRUB_MACHINE_PCBIOS /* Halt the system, using APM if possible. If NO_APM is true, don't * use APM even if it is available. */ -void EXPORT_FUNC (grub_halt) (int no_apm) __attribute__ ((noreturn)); +void grub_halt (int no_apm) __attribute__ ((noreturn)); #else -void EXPORT_FUNC (grub_halt) (void) __attribute__ ((noreturn)); +void grub_halt (void) __attribute__ ((noreturn)); #endif #ifdef GRUB_MACHINE_EMU diff --git a/include/grub/mm.h b/include/grub/mm.h index 38dd39646..cc115907a 100644 --- a/include/grub/mm.h +++ b/include/grub/mm.h @@ -35,6 +35,9 @@ void EXPORT_FUNC(grub_free) (void *ptr); void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size); void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size); +void grub_mm_check_real (char *file, int line); +#define GRUB_MM_CHECK grub_mm_check_real (__FILE__, __LINE__); + /* For debugging. */ #if defined(MM_DEBUG) && !defined(GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) /* Set this variable to 1 when you want to trace all memory function calls. */ diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h new file mode 100644 index 000000000..c2c4cb151 --- /dev/null +++ b/include/grub/mm_private.h @@ -0,0 +1,64 @@ +/* + * 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_MM_PRIVATE_H +#define GRUB_MM_PRIVATE_H 1 + +#include + +/* Magic words. */ +#define GRUB_MM_FREE_MAGIC 0x2d3c2808 +#define GRUB_MM_ALLOC_MAGIC 0x6db08fa4 + +typedef struct grub_mm_header +{ + struct grub_mm_header *next; + grub_size_t size; + grub_size_t magic; +#if GRUB_CPU_SIZEOF_VOID_P == 4 + char padding[4]; +#elif GRUB_CPU_SIZEOF_VOID_P == 8 + char padding[8]; +#else +# error "unknown word size" +#endif +} +*grub_mm_header_t; + +#if GRUB_CPU_SIZEOF_VOID_P == 4 +# define GRUB_MM_ALIGN_LOG2 4 +#elif GRUB_CPU_SIZEOF_VOID_P == 8 +# define GRUB_MM_ALIGN_LOG2 5 +#endif + +#define GRUB_MM_ALIGN (1 << GRUB_MM_ALIGN_LOG2) + +typedef struct grub_mm_region +{ + struct grub_mm_header *first; + struct grub_mm_region *next; + grub_size_t pre_size; + grub_size_t size; +} +*grub_mm_region_t; + +#ifndef GRUB_MACHINE_EMU +extern grub_mm_region_t EXPORT_VAR (grub_mm_base); +#endif + +#endif diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index 63947d1bc..cbc58b2ee 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -34,17 +34,21 @@ #include #include +extern struct grub_relocator *grub_multiboot_relocator; + void grub_multiboot (int argc, char *argv[]); void grub_module (int argc, char *argv[]); -grub_size_t grub_multiboot_get_mbi_size (void); -grub_err_t grub_multiboot_make_mbi (void *orig, grub_uint32_t dest, - grub_off_t buf_off, grub_size_t bufsize); +void grub_multiboot_set_accepts_video (int val); +grub_err_t grub_multiboot_make_mbi (grub_uint32_t *target); void grub_multiboot_free_mbi (void); grub_err_t grub_multiboot_init_mbi (int argc, char *argv[]); grub_err_t grub_multiboot_add_module (grub_addr_t start, grub_size_t size, int argc, char *argv[]); void grub_multiboot_set_bootdev (void); +void +grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize, + unsigned shndx, void *data); grub_uint32_t grub_get_multiboot_mmap_count (void); grub_err_t grub_multiboot_set_video_mode (void); @@ -70,5 +74,7 @@ grub_err_t grub_multiboot_load_elf (grub_file_t file, void *buffer); extern grub_size_t grub_multiboot_pure_size; extern grub_size_t grub_multiboot_alloc_mbi; +extern grub_uint32_t grub_multiboot_payload_eip; + #endif /* ! GRUB_MULTIBOOT_HEADER */ diff --git a/include/grub/normal.h b/include/grub/normal.h index 2a0298bc6..51ab46b12 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -54,8 +54,6 @@ void grub_normal_execute (const char *config, int nested, int batch); void grub_menu_init_page (int nested, int edit, struct grub_term_output *term); void grub_normal_init_page (struct grub_term_output *term); -grub_err_t grub_normal_add_menu_entry (int argc, const char **args, - const char *sourcecode); char *grub_file_getline (grub_file_t file); void grub_cmdline_run (int nested); diff --git a/include/grub/ns8250.h b/include/grub/ns8250.h index f8b9c3a8c..7947ba9c9 100644 --- a/include/grub/ns8250.h +++ b/include/grub/ns8250.h @@ -70,4 +70,11 @@ /* Turn on DTR, RTS, and OUT2. */ #define UART_ENABLE_OUT2 0x08 +#ifndef ASM_FILE +#include + +grub_port_t +grub_ns8250_hw_get_port (const unsigned int unit); +#endif + #endif /* ! GRUB_SERIAL_MACHINE_HEADER */ diff --git a/include/grub/offsets.h b/include/grub/offsets.h index ae0b2557e..47eb6c9bd 100644 --- a/include/grub/offsets.h +++ b/include/grub/offsets.h @@ -34,14 +34,17 @@ /* The offset of GRUB_INSTALL_BSD_PART. */ #define GRUB_KERNEL_I386_PC_INSTALL_BSD_PART 0x18 -/* The offset of GRUB_PREFIX. */ -#define GRUB_KERNEL_I386_PC_PREFIX 0x1c - -/* End of the data section. */ -#define GRUB_KERNEL_I386_PC_DATA_END 0x5c +/* The offset of multiboot signature. */ +#define GRUB_KERNEL_I386_PC_MULTIBOOT_SIGNATURE 0x1c /* The size of the first region which won't be compressed. */ -#define GRUB_KERNEL_I386_PC_RAW_SIZE (GRUB_KERNEL_I386_PC_DATA_END + 0x5F0) +#define GRUB_KERNEL_I386_PC_RAW_SIZE 0x5D8 + +/* The offset of GRUB_PREFIX. */ +#define GRUB_KERNEL_I386_PC_PREFIX GRUB_KERNEL_I386_PC_RAW_SIZE + +/* End of the data section. */ +#define GRUB_KERNEL_I386_PC_PREFIX_END (GRUB_KERNEL_I386_PC_PREFIX + 0x40) /* The segment where the kernel is loaded. */ #define GRUB_BOOT_I386_PC_KERNEL_SEG 0x800 @@ -65,7 +68,7 @@ #define GRUB_KERNEL_I386_QEMU_PREFIX 0x10 /* End of the data section. */ -#define GRUB_KERNEL_I386_QEMU_DATA_END 0x50 +#define GRUB_KERNEL_I386_QEMU_PREFIX_END 0x50 #define GRUB_KERNEL_I386_QEMU_LINK_ADDR 0x8200 @@ -82,7 +85,7 @@ #define GRUB_KERNEL_SPARC64_IEEE1275_PREFIX 0x14 /* End of the data section. */ -#define GRUB_KERNEL_SPARC64_IEEE1275_DATA_END 0x114 +#define GRUB_KERNEL_SPARC64_IEEE1275_PREFIX_END 0x114 #define GRUB_BOOT_SPARC64_IEEE1275_LIST_SIZE 12 @@ -91,7 +94,7 @@ #define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400 #define GRUB_KERNEL_POWERPC_IEEE1275_PREFIX 0x4 -#define GRUB_KERNEL_POWERPC_IEEE1275_DATA_END 0x44 +#define GRUB_KERNEL_POWERPC_IEEE1275_PREFIX_END 0x44 #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4 #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000 @@ -105,30 +108,34 @@ #define GRUB_KERNEL_MIPS_YEELOONG_KERNEL_IMAGE_SIZE 0x10 #define GRUB_KERNEL_MIPS_YEELOONG_PREFIX GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE -#define GRUB_KERNEL_MIPS_YEELOONG_DATA_END GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE + 0x48 +#define GRUB_KERNEL_MIPS_YEELOONG_PREFIX_END GRUB_KERNEL_MIPS_YEELOONG_RAW_SIZE + 0x48 /* The offset of GRUB_PREFIX. */ #define GRUB_KERNEL_I386_EFI_PREFIX 0x8 /* End of the data section. */ -#define GRUB_KERNEL_I386_EFI_DATA_END 0x50 +#define GRUB_KERNEL_I386_EFI_PREFIX_END 0x50 /* The offset of GRUB_PREFIX. */ #define GRUB_KERNEL_X86_64_EFI_PREFIX 0x8 /* End of the data section. */ -#define GRUB_KERNEL_X86_64_EFI_DATA_END 0x50 +#define GRUB_KERNEL_X86_64_EFI_PREFIX_END 0x50 #define GRUB_KERNEL_I386_COREBOOT_PREFIX 0x2 -#define GRUB_KERNEL_I386_COREBOOT_DATA_END 0x42 +#define GRUB_KERNEL_I386_COREBOOT_PREFIX_END 0x42 #define GRUB_KERNEL_I386_COREBOOT_LINK_ADDR 0x8200 +#define GRUB_KERNEL_I386_MULTIBOOT_PREFIX GRUB_KERNEL_I386_COREBOOT_PREFIX +#define GRUB_KERNEL_I386_MULTIBOOT_PREFIX_END GRUB_KERNEL_I386_COREBOOT_PREFIX_END + #define GRUB_KERNEL_I386_IEEE1275_PREFIX 0x2 -#define GRUB_KERNEL_I386_IEEE1275_DATA_END 0x42 +#define GRUB_KERNEL_I386_IEEE1275_PREFIX_END 0x42 #define GRUB_KERNEL_I386_IEEE1275_LINK_ADDR 0x10000 #define GRUB_KERNEL_I386_IEEE1275_MOD_ALIGN 0x1000 #define GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN 0x1 +#define GRUB_KERNEL_I386_MULTIBOOT_MOD_ALIGN GRUB_KERNEL_I386_COREBOOT_MOD_ALIGN /* Non-zero value is only needed for PowerMacs. */ #define GRUB_KERNEL_I386_IEEE1275_MOD_GAP 0x0 @@ -153,7 +160,7 @@ #define GRUB_KERNEL_MACHINE_COMPRESSED_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _COMPRESSED_SIZE) #define GRUB_KERNEL_MACHINE_PREFIX GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _PREFIX) -#define GRUB_KERNEL_MACHINE_DATA_END GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _DATA_END) +#define GRUB_KERNEL_MACHINE_PREFIX_END GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _PREFIX_END) #define GRUB_BOOT_MACHINE_KERNEL_SEG GRUB_OFFSETS_CONCAT (GRUB_BOOT_, MACHINE, _KERNEL_SEG) #define GRUB_MEMORY_MACHINE_UPPER GRUB_OFFSETS_CONCAT (GRUB_MEMORY_, MACHINE, _UPPER) #define GRUB_KERNEL_MACHINE_RAW_SIZE GRUB_OFFSETS_CONCAT (GRUB_KERNEL_, MACHINE, _RAW_SIZE) diff --git a/include/grub/powerpc/ieee1275/loader.h b/include/grub/powerpc/ieee1275/loader.h deleted file mode 100644 index 606bfcd0b..000000000 --- a/include/grub/powerpc/ieee1275/loader.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2007 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 - -/* The symbol shared between the normal mode and rescue mode - loader. */ -void grub_rescue_cmd_linux (int argc, char *argv[]); -void grub_rescue_cmd_initrd (int argc, char *argv[]); - -void grub_linux_init (void); -void grub_linux_fini (void); -void grub_linux_normal_init (void); -void grub_linux_normal_fini (void); - -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ diff --git a/grub-core/loader/i386/bsd_helper.S b/include/grub/powerpc/memory.h similarity index 53% rename from grub-core/loader/i386/bsd_helper.S rename to include/grub/powerpc/memory.h index 25aee3a80..b748f33c5 100644 --- a/grub-core/loader/i386/bsd_helper.S +++ b/include/grub/powerpc/memory.h @@ -1,6 +1,7 @@ +/* memory.h - describe the memory map */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2005,2006,2007,2008, 2009 Free Software Foundation, Inc. + * Copyright (C) 2002,2007,2008,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,30 +17,31 @@ * along with GRUB. If not, see . */ -#include +#ifndef GRUB_MEMORY_CPU_HEADER +#define GRUB_MEMORY_CPU_HEADER 1 - .p2align 2 +#ifndef ASM_FILE +typedef grub_addr_t grub_phys_addr_t; - .code32 +static inline grub_phys_addr_t +grub_vtop (void *a) +{ + return (grub_phys_addr_t) a; +} -/* - * Use cdecl calling convention for *BSD kernels. - */ +static inline void * +grub_map_memory (grub_phys_addr_t a, grub_size_t size __attribute__ ((unused))) +{ + return (void *) a; +} -FUNCTION(grub_unix_real_boot) +static inline void +grub_unmap_memory (void *a __attribute__ ((unused)), + grub_size_t size __attribute__ ((unused))) +{ +} - /* Interrupts should be disabled. */ - cli +#endif - /* Discard `grub_unix_real_boot' return address. */ - popl %eax - - /* Fetch `entry' address ... */ - popl %eax - - /* - * ... and put our return address in its place. The kernel will - * ignore it, but it expects %esp to point to it. - */ - call *%eax +#endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/include/grub/i386/ieee1275/loader.h b/include/grub/powerpc/relocator.h similarity index 62% rename from include/grub/i386/ieee1275/loader.h rename to include/grub/powerpc/relocator.h index 20df2e1d6..c2780bbca 100644 --- a/include/grub/i386/ieee1275/loader.h +++ b/include/grub/powerpc/relocator.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2004,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 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 @@ -16,14 +16,22 @@ * along with GRUB. If not, see . */ -#ifndef GRUB_LOADER_MACHINE_HEADER -#define GRUB_LOADER_MACHINE_HEADER 1 +#ifndef GRUB_RELOCATOR_CPU_HEADER +#define GRUB_RELOCATOR_CPU_HEADER 1 #include -#include -#include +#include +#include -void grub_rescue_cmd_linux (int argc, char *argv[]); -void grub_rescue_cmd_initrd (int argc, char *argv[]); +#define GRUB_PPC_JUMP_REGISTER 31 -#endif /* ! GRUB_LOADER_MACHINE_HEADER */ +struct grub_relocator32_state +{ + grub_uint32_t gpr[32]; +}; + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state); + +#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ diff --git a/include/grub/relocator.h b/include/grub/relocator.h new file mode 100644 index 000000000..653a00eba --- /dev/null +++ b/include/grub/relocator.h @@ -0,0 +1,58 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_RELOCATOR_HEADER +#define GRUB_RELOCATOR_HEADER 1 + +#include +#include +#include +#include + +struct grub_relocator; +struct grub_relocator_chunk; +typedef const struct grub_relocator_chunk *grub_relocator_chunk_t; + +struct grub_relocator *grub_relocator_new (void); + +grub_err_t +grub_relocator_alloc_chunk_addr (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t target, grub_size_t size); + +void * +get_virtual_current_address (grub_relocator_chunk_t in); +grub_phys_addr_t +get_physical_target_address (grub_relocator_chunk_t in); + +grub_err_t +grub_relocator_alloc_chunk_align (struct grub_relocator *rel, + grub_relocator_chunk_t *out, + grub_phys_addr_t min_addr, + grub_phys_addr_t max_addr, + grub_size_t size, grub_size_t align, + int preference); + +#define GRUB_RELOCATOR_PREFERENCE_NONE 0 +#define GRUB_RELOCATOR_PREFERENCE_LOW 1 +#define GRUB_RELOCATOR_PREFERENCE_HIGH 2 + +void +grub_relocator_unload (struct grub_relocator *rel); + +#endif diff --git a/include/grub/relocator_private.h b/include/grub/relocator_private.h new file mode 100644 index 000000000..1c563cb64 --- /dev/null +++ b/include/grub/relocator_private.h @@ -0,0 +1,113 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_RELOCATOR_PRIVATE_HEADER +#define GRUB_RELOCATOR_PRIVATE_HEADER 1 + +#include +#include +#include + +extern grub_size_t grub_relocator_align; +extern grub_size_t grub_relocator_forward_size; +extern grub_size_t grub_relocator_backward_size; +extern grub_size_t grub_relocator_jumper_size; + +void +grub_cpu_relocator_init (void); +grub_err_t +grub_relocator_prepare_relocs (struct grub_relocator *rel, + grub_addr_t addr, + void **relstart, grub_size_t *relsize); +void grub_cpu_relocator_forward (void *rels, void *src, void *tgt, + grub_size_t size); +void grub_cpu_relocator_backward (void *rels, void *src, void *tgt, + grub_size_t size); +void grub_cpu_relocator_jumper (void *rels, grub_addr_t addr); + +/* Remark: GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG = 1 or 2 + aren't supported. */ +#ifdef GRUB_MACHINE_IEEE1275 +#define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 1 +#define GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG 0 +#elif defined (GRUB_MACHINE_EFI) +#define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 1 +#define GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG 12 +#else +#define GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS 0 +#endif + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS && GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG != 0 +#define GRUB_RELOCATOR_HAVE_LEFTOVERS 1 +#else +#define GRUB_RELOCATOR_HAVE_LEFTOVERS 0 +#endif + +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS +#define GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT (1 << GRUB_RELOCATOR_FIRMWARE_REQUESTS_QUANT_LOG) +#endif + +struct grub_relocator_mmap_event +{ + enum { + IN_REG_START = 0, + IN_REG_END = 1, + REG_BEG_START = 2, + REG_BEG_END = REG_BEG_START | 1, +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + REG_FIRMWARE_START = 4, + REG_FIRMWARE_END = REG_FIRMWARE_START | 1, + /* To track the regions already in heap. */ + FIRMWARE_BLOCK_START = 6, + FIRMWARE_BLOCK_END = FIRMWARE_BLOCK_START | 1, +#endif +#if GRUB_RELOCATOR_HAVE_LEFTOVERS + REG_LEFTOVER_START = 8, + REG_LEFTOVER_END = REG_LEFTOVER_START | 1, +#endif + COLLISION_START = 10, + COLLISION_END = COLLISION_START | 1 + } type; + grub_phys_addr_t pos; + union + { + struct + { + grub_mm_region_t reg; + grub_mm_header_t hancestor; + grub_mm_region_t *regancestor; + grub_mm_header_t head; + }; +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS + struct grub_relocator_fw_leftover *leftover; +#endif + }; +}; + +/* Return 0 on failure, 1 on success. The failure here + can be very time-expensive, so please make sure fill events is accurate. */ +#if GRUB_RELOCATOR_HAVE_FIRMWARE_REQUESTS +int grub_relocator_firmware_alloc_region (grub_phys_addr_t start, + grub_size_t size); +unsigned grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events); +unsigned grub_relocator_firmware_get_max_events (void); +void grub_relocator_firmware_free_region (grub_phys_addr_t start, + grub_size_t size); +#endif + +#endif diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h index 77e807360..6d31fca5a 100644 --- a/include/grub/script_sh.h +++ b/include/grub/script_sh.h @@ -40,8 +40,13 @@ struct grub_script_cmd struct grub_script { + unsigned refcnt; struct grub_script_mem *mem; struct grub_script_cmd *cmd; + + /* grub_scripts from block arguments. */ + struct grub_script *next_siblings; + struct grub_script *children; }; typedef enum @@ -50,7 +55,8 @@ typedef enum GRUB_SCRIPT_ARG_TYPE_TEXT, GRUB_SCRIPT_ARG_TYPE_DQVAR, GRUB_SCRIPT_ARG_TYPE_DQSTR, - GRUB_SCRIPT_ARG_TYPE_SQSTR + GRUB_SCRIPT_ARG_TYPE_SQSTR, + GRUB_SCRIPT_ARG_TYPE_BLOCK } grub_script_arg_type_t; /* A part of an argument. */ @@ -60,6 +66,9 @@ struct grub_script_arg char *str; + /* Parsed block argument. */ + struct grub_script *script; + /* Next argument part. */ struct grub_script_arg *next; }; @@ -69,8 +78,19 @@ struct grub_script_argv { unsigned argc; char **args; + struct grub_script *script; }; +/* Pluggable wildcard translator. */ +struct grub_script_wildcard_translator +{ + char *(*escape) (const char *str); + char *(*unescape) (const char *str); + grub_err_t (*expand) (const char *str, char ***expansions); +}; +extern struct grub_script_wildcard_translator *grub_wildcard_translator; +extern struct grub_script_wildcard_translator grub_filename_translator; + /* A complete argument. It consists of a list of one or more `struct grub_script_arg's. */ struct grub_script_arglist @@ -135,21 +155,6 @@ struct grub_script_cmdwhile int until; }; -/* A menu entry generate statement. */ -struct grub_script_cmd_menuentry -{ - struct grub_script_cmd cmd; - - /* The arguments for this menu entry. */ - struct grub_script_arglist *arglist; - - /* The sourcecode the entry will be generated from. */ - const char *sourcecode; - - /* Options. XXX: Not used yet. */ - int options; -}; - /* State of the lexer as passed to the lexer. */ struct grub_lexer_param { @@ -194,6 +199,12 @@ struct grub_lexer_param /* Type of text. */ grub_script_arg_type_t type; + /* Flag to indicate resplit in progres. */ + unsigned resplit; + + /* Text that is unput. */ + char *prefix; + /* Flex scanner. */ void *yyscanner; @@ -217,6 +228,9 @@ struct grub_parser_param /* The memory that was used while parsing and scanning. */ struct grub_script_mem *memused; + /* The block argument scripts. */ + struct grub_script *scripts; + /* The result of the parser. */ struct grub_script_cmd *parsed; @@ -226,7 +240,10 @@ struct grub_parser_param void grub_script_init (void); void grub_script_fini (void); +void grub_script_mem_free (struct grub_script_mem *mem); + void grub_script_argv_free (struct grub_script_argv *argv); +int grub_script_argv_make (struct grub_script_argv *argv, int argc, char **args); int grub_script_argv_next (struct grub_script_argv *argv); int grub_script_argv_append (struct grub_script_argv *argv, const char *s); int grub_script_argv_split_append (struct grub_script_argv *argv, char *s); @@ -260,12 +277,6 @@ grub_script_create_cmdwhile (struct grub_parser_param *state, struct grub_script_cmd *list, int is_an_until_loop); -struct grub_script_cmd * -grub_script_create_cmdmenu (struct grub_parser_param *state, - struct grub_script_arglist *arglist, - char *sourcecode, - int options); - struct grub_script_cmd * grub_script_append_cmd (struct grub_parser_param *state, struct grub_script_cmd *list, @@ -287,9 +298,9 @@ struct grub_lexer_param *grub_script_lexer_init (struct grub_parser_param *parse void grub_script_lexer_fini (struct grub_lexer_param *); void grub_script_lexer_ref (struct grub_lexer_param *); void grub_script_lexer_deref (struct grub_lexer_param *); -void grub_script_lexer_record_start (struct grub_parser_param *); -char *grub_script_lexer_record_stop (struct grub_parser_param *); -int grub_script_lexer_yywrap (struct grub_parser_param *); +unsigned grub_script_lexer_record_start (struct grub_parser_param *); +char *grub_script_lexer_record_stop (struct grub_parser_param *, unsigned); +int grub_script_lexer_yywrap (struct grub_parser_param *, const char *input); void grub_script_lexer_record (struct grub_parser_param *, char *); /* Functions to track allocated memory. */ @@ -310,10 +321,10 @@ grub_err_t grub_script_execute_cmdlist (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdif (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdfor (struct grub_script_cmd *cmd); grub_err_t grub_script_execute_cmdwhile (struct grub_script_cmd *cmd); -grub_err_t grub_script_execute_menuentry (struct grub_script_cmd *cmd); /* Execute any GRUB pre-parsed command or script. */ grub_err_t grub_script_execute (struct grub_script *script); +grub_err_t grub_script_execute_sourcecode (const char *source, int argc, char **args); /* Break command for loops. */ grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]); @@ -321,6 +332,12 @@ grub_err_t grub_script_break (grub_command_t cmd, int argc, char *argv[]); /* SHIFT command for GRUB script. */ grub_err_t grub_script_shift (grub_command_t cmd, int argc, char *argv[]); +/* SETPARAMS command for GRUB script functions. */ +grub_err_t grub_script_setparams (grub_command_t cmd, int argc, char *argv[]); + +/* RETURN command for functions. */ +grub_err_t grub_script_return (grub_command_t cmd, int argc, char *argv[]); + /* This variable points to the parsed command. This is used to communicate with the bison code. */ extern struct grub_script_cmd *grub_script_parsed; @@ -365,4 +382,24 @@ grub_script_execute_arglist_to_argv (struct grub_script_arglist *arglist, int *c grub_err_t grub_normal_parse_line (char *line, grub_reader_getline_t getline); +static inline struct grub_script * +grub_script_ref (struct grub_script *script) +{ + if (script) + script->refcnt++; + return script; +} + +static inline void +grub_script_unref (struct grub_script *script) +{ + if (! script) + return; + + if (script->refcnt == 0) + grub_script_free (script); + else + script->refcnt--; +} + #endif /* ! GRUB_NORMAL_PARSER_HEADER */ diff --git a/include/grub/x86_64/memory.h b/include/grub/x86_64/memory.h new file mode 100644 index 000000000..27fcd2534 --- /dev/null +++ b/include/grub/x86_64/memory.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/xnu.h b/include/grub/xnu.h index 6089aad34..076aeb5ed 100644 --- a/include/grub/xnu.h +++ b/include/grub/xnu.h @@ -87,7 +87,7 @@ extern struct grub_xnu_devtree_key *grub_xnu_devtree_root; void grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur); -grub_err_t grub_xnu_writetree_toheap (void **start, grub_size_t *size); +grub_err_t grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size); struct grub_xnu_devtree_key *grub_xnu_create_value (struct grub_xnu_devtree_key **parent, char *name); @@ -102,14 +102,15 @@ grub_err_t grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired, int maxrecursion); grub_err_t grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired, int maxrecursion); -void *grub_xnu_heap_malloc (int size); +grub_err_t grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target); grub_err_t grub_xnu_fill_devicetree (void); -extern grub_uint32_t grub_xnu_heap_real_start; +extern struct grub_relocator *grub_xnu_relocator; + extern grub_size_t grub_xnu_heap_size; -extern void *grub_xnu_heap_start; extern struct grub_video_bitmap *grub_xnu_bitmap; typedef enum {GRUB_XNU_BITMAP_CENTER, GRUB_XNU_BITMAP_STRETCH} grub_xnu_bitmap_mode_t; extern grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode; extern int grub_xnu_is_64bit; +extern grub_addr_t grub_xnu_heap_target_start; #endif diff --git a/tests/grub_cmd_regexp.in b/tests/grub_cmd_regexp.in new file mode 100644 index 000000000..43b479fec --- /dev/null +++ b/tests/grub_cmd_regexp.in @@ -0,0 +1,41 @@ +#! /bin/bash -e + +# Run GRUB script in a Qemu instance +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +cmd='regexp -s version "vm-(.*)" vm-1.2.3; echo $version' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != 1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 1:version "vm-(.*)" vm-1.2.3; echo $version' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != 1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 0:match "vm-(.*)" vm-1.2.3; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != vm-1.2.3; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s 2:match "vm-(.*)" vm-1.2.3; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test -n "$v"; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s match "\\\((.*)\\\)" (hd0,msdos1); echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != "hd0,msdos1"; then echo "error: $cmd" >&2; exit 1; fi + +cmd='regexp -s match "hd([0-9]+)" hd0; echo $match' +v=`echo "$cmd" | @builddir@/grub-shell` +if test "$v" != "0"; then echo "error: $cmd" >&2; exit 1; fi diff --git a/tests/grub_script_blockarg.in b/tests/grub_script_blockarg.in new file mode 100644 index 000000000..783cee8e0 --- /dev/null +++ b/tests/grub_script_blockarg.in @@ -0,0 +1,41 @@ +#! /bin/bash + +# Run GRUB script in a Qemu instance +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +error_if_not () { + if test "$1" != "$2"; then + echo "[$1]" != "[$2]" + exit 1 + fi +} + +cmd='test_blockarg { true }' +v=`echo "$cmd" | @builddir@/grub-shell` +error_if_not "$v" '{ true }' + +tmp=`mktemp` +cmd='test_blockarg { test_blockarg { true } }' +echo "$cmd" | @builddir@/grub-shell >$tmp +error_if_not "`head -n1 $tmp|tail -n1`" '{ test_blockarg { true } }' +error_if_not "`head -n2 $tmp|tail -n1`" '{ true }' + +cmd='test_blockarg { test_blockarg { test_blockarg { true } }; test_blockarg { true } }' +echo "$cmd" | @builddir@/grub-shell >$tmp +error_if_not "`head -n1 $tmp|tail -n1`" '{ test_blockarg { test_blockarg { true } }; test_blockarg { true } }' +error_if_not "`head -n2 $tmp|tail -n1`" '{ test_blockarg { true } }' +error_if_not "`head -n3 $tmp|tail -n1`" '{ true }' +error_if_not "`head -n4 $tmp|tail -n1`" '{ true }' diff --git a/tests/grub_script_echo1.in b/tests/grub_script_echo1.in index 554dd68ed..9415a3f73 100644 --- a/tests/grub_script_echo1.in +++ b/tests/grub_script_echo1.in @@ -57,3 +57,45 @@ e"$foo"${bar}o hello world foo=echo $foo 1234 + +echo "one +" +echo "one +\"" +echo "one +two" + +echo one"two +"three +echo one"two +\""three +echo one"two +\"three\" +four" + + +echo 'one +' +echo 'one +\' +echo 'one +two' +echo one'two +' +echo one'two +\' +echo one'two +\'three + +# echo "one\ +# two" +# echo 'one\ +# two' +# echo foo\ +# bar +# \ +# echo foo +# echo "one +# +# two" + diff --git a/tests/grub_script_expansion.in b/tests/grub_script_expansion.in new file mode 100644 index 000000000..d1e8d55c9 --- /dev/null +++ b/tests/grub_script_expansion.in @@ -0,0 +1,42 @@ +#! /bin/bash -e + +# Run GRUB script in a Qemu instance +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +disks=`echo ls | @builddir@/grub-shell` +other=`echo insmod regexp\; echo \* | @builddir@/grub-shell` +for d in $disks; do + if echo "$d" |grep ',' >/dev/null; then + if echo "$other" | grep "$d" >/dev/null; then + echo "$d should not occur in * expansion" >&2 + exit 1 + fi + else + if ! echo "$other" | grep "$d" >/dev/null; then + echo "$d missing from * expansion" >&2 + exit 1 + fi + fi +done + +other=`echo insmod regexp\; echo '(*)' | @builddir@/grub-shell` +for d in $disks; do + if ! echo "$other" | grep "$d" >/dev/null; then + echo "$d missing from (*) expansion" >&2 + exit 1 + fi +done + diff --git a/tests/grub_script_return.in b/tests/grub_script_return.in new file mode 100644 index 000000000..712d1dfcf --- /dev/null +++ b/tests/grub_script_return.in @@ -0,0 +1,134 @@ +#! @builddir@/grub-shell-tester + +# Run GRUB script in a Qemu instance +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +function f1 { + return + echo one +} +f1 + +function f2 { + true + return + echo one +} +if f2; then echo true; else echo false; fi + +function f3 { + false + return + echo one +} +if f3; then echo true; else echo false; fi + +function f4 { + true + return 1; + echo one +} +if f4; then echo true; else echo false; fi + +function f5 { + false + return 0; + echo one +} +if f5; then echo true; else echo false; fi + +function f6 { + echo one + if true; then + echo two + return 0 + else + echo three + return 1 + fi + echo four +} +if f6; then echo true; else echo false; fi + +function f7 { + if return 1; then + echo one + else + echo no + fi +} +if f7; then echo true; else echo false; fi + +function f8 { + echo one + for v in 1 2 3 4 5; do + echo $v + if test $v = 3; then return 1; fi + done + echo two +} +if f8; then echo true; else echo false; fi + +function f9 { + x=1 + echo one + until test x = 11111111; do + echo $x + x="1$x" + if test $x = 1111; then return 0; fi + done + echo two +} +if f9; then echo true; else echo false; fi + +function f10 { + echo one + while return 0; do + echo two + done + echo three +} +if f10; then echo true; else echo false; fi + +function f11 { + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 +} +if f11; then echo true; else echo false; fi + +function f12 { + echo one + f11 + return 1 + echo two +} +if f12; then echo true; else echo false; fi + +function f13 { + echo one + f12 + echo two + return 0 +} +if f13; then echo true; else echo false; fi diff --git a/tests/grub_script_setparams.in b/tests/grub_script_setparams.in new file mode 100644 index 000000000..82d316813 --- /dev/null +++ b/tests/grub_script_setparams.in @@ -0,0 +1,59 @@ +#! @builddir@/grub-shell-tester + +# Run GRUB script in a Qemu instance +# Copyright (C) 2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +if test x$grubshell = xyes; then cmd=setparams; else cmd=set; fi + +function f1 { + echo $# + echo "$#" + + echo $@ + echo "$@" + + echo $* + echo "$*" + + echo $1 $2 + for v in "$@"; do echo $v; done + shift + echo $1 $2 + for v in "$@"; do echo $v; done + + $cmd 1 2 3 4 + + echo $# + echo "$#" + + echo $@ + echo "$@" + + echo $* + echo "$*" + + echo $1 $2 + for v in "$@"; do echo $v; done + shift + echo $1 $2 + for v in "$@"; do echo $v; done +} +# f1 +# f1 a +f1 a b +f1 a b c +f1 a b c d +f1 a b c d e diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in index 3f25fe7bb..427b1ce9f 100644 --- a/tests/util/grub-shell.in +++ b/tests/util/grub-shell.in @@ -44,7 +44,9 @@ Run GRUB script in a Qemu instance. -v, --version print the version information and exit --boot=[fd|hd|cd] boot method for Qemu instance --modules=MODULES pre-load specified modules MODULES + --qemu=FILE Name of qemu binary --qemu-opts=OPTIONS extra options to pass to Qemu instance + --files=FILES add files to the image $0 runs input GRUB script or SOURCE file in a Qemu instance and prints its output. @@ -53,6 +55,9 @@ Report bugs to . EOF } +boot=hd +qemu=qemu-system-i386 + # Check the arguments. for option in "$@"; do case "$option" in @@ -65,14 +70,21 @@ for option in "$@"; do --modules=*) ms=`echo "$option" | sed -e 's/--modules=//' -e 's/,/ /g'` modules="$modules $ms" ;; + --files=*) + fls=`echo "$option" | sed -e 's/--files=//' -e 's/,/ /g'` + files="$files $fls" ;; + --qemu=*) + qemu=`echo "$option" | sed -e 's/--qemu=//' -e 's/,/ /g'`;; --qemu-opts=*) qs=`echo "$option" | sed -e 's/--qemu-opts=//'` qemuopts="$qemuopts $qs" ;; --boot=*) dev=`echo "$option" | sed -e 's/--boot=//'` - if [ "$dev" = "fd" ] ; then bootdev=a; - elif [ "$dev" = "hd" ] ; then bootdev=c; - elif [ "$dev" = "cd" ] ; then bootdev=d; + if [ "$dev" = "fd" ] ; then boot=fd; + elif [ "$dev" = "hd" ] ; then boot=hd; + elif [ "$dev" = "cd" ] ; then boot=cd; + elif [ "$dev" = "qemu" ] ; then boot=qemu; + elif [ "$dev" = "coreboot" ] ; then boot=coreboot; else echo "Unrecognized boot method \`$dev'" 1>&2 usage @@ -95,15 +107,11 @@ done if [ "x${source}" = x ] ; then tmpfile=`mktemp` while read REPLY; do - echo $REPLY >> ${tmpfile} + echo "$REPLY" >> ${tmpfile} done source=${tmpfile} fi -if [ "x${bootdev}" = x ] ; then - bootdev=c # default is boot as disk image -fi - cfgfile=`mktemp` cat <${cfgfile} grubshell=yes @@ -113,6 +121,8 @@ terminal_input serial terminal_output serial EOF +rom_directory=`mktemp -d` + for mod in ${modules} do echo "insmod ${mod}" >> ${cfgfile} @@ -124,23 +134,44 @@ halt EOF isofile=`mktemp` -sh @builddir@/grub-mkrescue --grub-mkimage=${builddir}/grub-mkimage \ - --override-directory=${builddir}/grub-core --output=${isofile} \ - boot/grub/grub.cfg=${cfgfile} \ - /boot/grub/testcase.cfg=${source} >/dev/null 2>&1 +sh @builddir@/grub-mkrescue --grub-mkimage=${builddir}/grub-mkimage --output=${isofile} --override-directory=${builddir}/grub-core \ + --rom-directory="${rom_directory}" \ + /boot/grub/grub.cfg=${cfgfile} /boot/grub/testcase.cfg=${source} \ + ${files} >/dev/null 2>&1 +if [ x$boot = xhd ]; then + device=hda + bootdev="-boot c" +fi +if [ x$boot = xcd ]; then + device=cdrom + bootdev="-boot d" +fi +if [ x$boot = xfd ]; then + device=fda + bootdev="-boot a" +fi -hdafile=`mktemp` -cp ${isofile} ${hdafile} +if [ x$boot = xqemu ]; then + bootdev="-bios ${rom_directory}/qemu.img" + device=cdrom +fi -fdafile=`mktemp` -cp ${isofile} ${fdafile} +if [ x$boot = xcoreboot ]; then + imgfile=`mktemp` + cp "${GRUB_COREBOOT_ROM}" "${imgfile}" + "${GRUB_CBFSTOOL}" "${imgfile}" add-payload "${rom_directory}/coreboot.elf" fallback/payload + bootdev="-bios ${imgfile}" + device=cdrom +fi -outfile=`mktemp` -qemu-system-i386 ${qemuopts} -nographic -hda ${hdafile} -fda ${fdafile} -cdrom ${isofile} -boot ${bootdev} | tr -d "\r" >${outfile} +${qemu} ${qemuopts} -nographic -serial file:/dev/stdout -monitor file:/dev/null -${device} ${isofile} ${bootdev} | cat | tr -d "\r" +rm -f "${isofile}" "${imgfile}" +rm -rf "${rom_directory}" +if [ x$boot = xcoreboot ]; then + rm -f "${imgfile}" +fi -cat $outfile - -rm -f ${tmpfile} ${outfile} ${cfgfile} ${isofile} ${hdafile} ${fdafile} +rm -f "${tmpfile}" "${cfgfile}" exit 0 diff --git a/util/grub-fstest.c b/util/grub-fstest.c index 48fcbc57f..3935ce08b 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -107,6 +107,7 @@ read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len)) return; } + grub_file_filter_disable_compression (); file = grub_file_open (pathname); if (!file) { diff --git a/util/grub-install.in b/util/grub-install.in index 4a5b5a1c3..e6521f069 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -30,7 +30,6 @@ PACKAGE_VERSION=@PACKAGE_VERSION@ target_cpu=@target_cpu@ platform=@platform@ host_os=@host_os@ -font=@datadir@/@PACKAGE_TARNAME@/ascii.pf2 pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}` localedir=@datadir@/locale @@ -84,11 +83,6 @@ if [ "${target_cpu}-${platform}" = "i386-pc" ] ; then cat <prefix + strlen (prefix) + 1 > image_target->data_end) + if (image_target->prefix + strlen (prefix) + 1 > image_target->prefix_end) grub_util_error (_("prefix is too long")); strcpy (kernel_img + image_target->prefix, prefix); @@ -625,20 +638,6 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], offset += memdisk_size; } - if (font_path) - { - struct grub_module_header *header; - - header = (struct grub_module_header *) (kernel_img + offset); - memset (header, 0, sizeof (struct grub_module_header)); - header->type = grub_host_to_target32 (OBJ_TYPE_FONT); - header->size = grub_host_to_target32 (font_size + sizeof (*header)); - offset += sizeof (*header); - - grub_util_load_image (font_path, kernel_img + offset); - offset += font_size; - } - if (config_path) { struct grub_module_header *header; @@ -684,6 +683,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], switch (image_target->id) { case IMAGE_I386_PC: + case IMAGE_I386_PC_PXE: { unsigned num; char *boot_path, *boot_img; @@ -698,6 +698,20 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], if (num > 0xffff) grub_util_error (_("the core image is too big")); + if (image_target->id == IMAGE_I386_PC_PXE) + { + char *pxeboot_path, *pxeboot_img; + size_t pxeboot_size; + + pxeboot_path = grub_util_get_path (dir, "pxeboot.img"); + pxeboot_size = grub_util_get_image_size (pxeboot_path); + pxeboot_img = grub_util_read_image (pxeboot_path); + + grub_util_write_image (pxeboot_img, pxeboot_size, out); + free (pxeboot_img); + free (pxeboot_path); + } + boot_path = grub_util_get_path (dir, "diskboot.img"); boot_size = grub_util_get_image_size (boot_path); if (boot_size != GRUB_DISK_SECTOR_SIZE) @@ -1241,7 +1255,6 @@ Make a bootable image of GRUB.\n\ -d, --directory=DIR use images and modules under DIR [default=%s/@platform@]\n\ -p, --prefix=DIR set grub_prefix directory [default=%s]\n\ -m, --memdisk=FILE embed FILE as a memdisk image\n\ - -f, --font=FILE embed FILE as a boot font\n\ -c, --config=FILE embed FILE as boot config\n\ -n, --note add NOTE segment for CHRP Open Firmware\n\ -o, --output=FILE output a generated image to FILE [default=stdout]\n\ @@ -1330,13 +1343,6 @@ main (int argc, char *argv[]) prefix = xstrdup ("(memdisk)/boot/grub"); break; - case 'f': - if (font) - free (font); - - font = xstrdup (optarg); - break; - case 'c': if (config) free (config); @@ -1401,7 +1407,7 @@ main (int argc, char *argv[]) } generate_image (dir, prefix ? : DEFAULT_DIRECTORY, fp, - argv + optind, memdisk, font, config, + argv + optind, memdisk, config, image_target, note); fclose (fp); diff --git a/util/grub-mkrescue.in b/util/grub-mkrescue.in index 0f40e92cc..142ee85cd 100644 --- a/util/grub-mkrescue.in +++ b/util/grub-mkrescue.in @@ -62,7 +62,8 @@ Make GRUB rescue image. $self generates a bootable rescue image with specified source files, source directories, or mkisofs options listed by: xorriso -as mkisofs -help -Option -- switches to native xorriso command mode. or directories. + +Option -- switches to native xorriso command mode. Report bugs to . Mail xorriso support requests to . diff --git a/util/grub-probe.c b/util/grub-probe.c index ab3e2713e..62206bf0e 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -245,6 +245,7 @@ probe (const char *path, char *device_name) grub_path = xasprintf ("(%s)%s", drive_name, rel_path); free (rel_path); grub_util_info ("reading %s via GRUB facilities", grub_path); + grub_file_filter_disable_compression (); file = grub_file_open (grub_path); if (! file) grub_util_error ("cannot open %s via GRUB facilities", grub_path); diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 9788efe4a..642d9d104 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -454,6 +454,7 @@ unable_to_embed: grub_disk_cache_invalidate_all (); + grub_file_filter_disable_compression (); file = grub_file_open (core_path_dev); if (file) { @@ -524,6 +525,7 @@ unable_to_embed: } /* Now read the core image to determine where the sectors are. */ + grub_file_filter_disable_compression (); file = grub_file_open (core_path_dev); if (! file) grub_util_error ("%s", grub_errmsg); diff --git a/util/sparc64/ieee1275/grub-setup.c b/util/sparc64/ieee1275/grub-setup.c index 94734b977..d8481295f 100644 --- a/util/sparc64/ieee1275/grub-setup.c +++ b/util/sparc64/ieee1275/grub-setup.c @@ -228,6 +228,7 @@ setup (const char *prefix, const char *dir, grub_disk_cache_invalidate_all (); + grub_file_filter_disable_compression (); file = grub_file_open (core_path); if (file) { @@ -297,6 +298,7 @@ setup (const char *prefix, const char *dir, } /* Now read the core image to determine where the sectors are. */ + grub_file_filter_disable_compression (); file = grub_file_open (core_path); if (! file) grub_util_error ("%s", grub_errmsg);